From a9cd9ac122c49ac10e070fdd45a5f1e009638947 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 12 May 2020 20:44:39 +0200 Subject: [PATCH 01/35] First implementation of texts collection. --- src/db/db/db.pro | 21 +- src/db/db/dbAsIfFlatTexts.cc | 277 ++++++++++++ src/db/db/dbAsIfFlatTexts.h | 88 ++++ src/db/db/dbDeepShapeStore.cc | 58 +-- src/db/db/dbDeepShapeStore.h | 9 + src/db/db/dbDeepTexts.cc | 316 ++++++++++++++ src/db/db/dbDeepTexts.h | 102 +++++ src/db/db/dbEdges.h | 1 + src/db/db/dbEmptyTexts.cc | 88 ++++ src/db/db/dbEmptyTexts.h | 85 ++++ src/db/db/dbFlatTexts.cc | 220 ++++++++++ src/db/db/dbFlatTexts.h | 171 ++++++++ src/db/db/dbHierarchyBuilder.cc | 14 + src/db/db/dbHierarchyBuilder.h | 14 + src/db/db/dbOriginalLayerTexts.cc | 197 +++++++++ src/db/db/dbOriginalLayerTexts.h | 75 ++++ src/db/db/dbRegion.h | 1 + src/db/db/dbTexts.cc | 207 +++++++++ src/db/db/dbTexts.h | 670 ++++++++++++++++++++++++++++++ src/db/db/dbTextsDelegate.cc | 68 +++ src/db/db/dbTextsDelegate.h | 140 +++++++ src/db/db/dbTextsUtils.cc | 31 ++ src/db/db/dbTextsUtils.h | 154 +++++++ src/db/db/gsiDeclDbTexts.cc | 470 +++++++++++++++++++++ 24 files changed, 3424 insertions(+), 53 deletions(-) create mode 100644 src/db/db/dbAsIfFlatTexts.cc create mode 100644 src/db/db/dbAsIfFlatTexts.h create mode 100644 src/db/db/dbDeepTexts.cc create mode 100644 src/db/db/dbDeepTexts.h create mode 100644 src/db/db/dbEmptyTexts.cc create mode 100644 src/db/db/dbEmptyTexts.h create mode 100644 src/db/db/dbFlatTexts.cc create mode 100644 src/db/db/dbFlatTexts.h create mode 100644 src/db/db/dbOriginalLayerTexts.cc create mode 100644 src/db/db/dbOriginalLayerTexts.h create mode 100644 src/db/db/dbTexts.cc create mode 100644 src/db/db/dbTexts.h create mode 100644 src/db/db/dbTextsDelegate.cc create mode 100644 src/db/db/dbTextsDelegate.h create mode 100644 src/db/db/dbTextsUtils.cc create mode 100644 src/db/db/dbTextsUtils.h create mode 100644 src/db/db/gsiDeclDbTexts.cc diff --git a/src/db/db/db.pro b/src/db/db/db.pro index ea36ff395..0d7823d6c 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -184,7 +184,16 @@ SOURCES = \ dbLayoutVsSchematic.cc \ gsiDeclDbNetlistCrossReference.cc \ gsiDeclDbLayoutVsSchematic.cc \ - dbNetlistObject.cc + dbNetlistObject.cc \ + gsiDeclDbTexts.cc \ + dbTexts.cc \ + dbDeepTexts.cc \ + dbAsIfFlatTexts.cc \ + dbTextsDelegate.cc \ + dbEmptyTexts.cc \ + dbFlatTexts.cc \ + dbTextsUtils.cc \ + dbOriginalLayerTexts.cc HEADERS = \ dbArray.h \ @@ -331,7 +340,15 @@ HEADERS = \ dbLayoutVsSchematicReader.h \ dbLayoutVsSchematicFormatDefs.h \ dbLayoutVsSchematic.h \ - dbNetlistObject.h + dbNetlistObject.h \ + dbTexts.h \ + dbDeepTexts.h \ + dbAsIfFlatTexts.h \ + dbTextsDelegate.h \ + dbEmptyTexts.h \ + dbFlatTexts.h \ + dbTextsUtils.h \ + dbOriginalLayerTexts.h !equals(HAVE_QT, "0") { diff --git a/src/db/db/dbAsIfFlatTexts.cc b/src/db/db/dbAsIfFlatTexts.cc new file mode 100644 index 000000000..968988311 --- /dev/null +++ b/src/db/db/dbAsIfFlatTexts.cc @@ -0,0 +1,277 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 "dbAsIfFlatTexts.h" +#include "dbFlatTexts.h" +#include "dbFlatRegion.h" +#include "dbFlatEdges.h" +#include "dbEmptyTexts.h" +#include "dbTexts.h" +#include "dbBoxConvert.h" + +#include + +namespace db +{ + +// ------------------------------------------------------------------------------------------------------------- +// AsIfFlagTexts implementation + +AsIfFlatTexts::AsIfFlatTexts () + : TextsDelegate (), m_bbox_valid (false) +{ + // .. nothing yet .. +} + +AsIfFlatTexts::~AsIfFlatTexts () +{ + // .. nothing yet .. +} + +std::string +AsIfFlatTexts::to_string (size_t nmax) const +{ + std::ostringstream os; + TextsIterator p (begin ()); + bool first = true; + for ( ; ! p.at_end () && nmax != 0; ++p, --nmax) { + if (! first) { + os << ";"; + } + first = false; + os << p->to_string (); + } + if (! p.at_end ()) { + os << "..."; + } + return os.str (); +} + +TextsDelegate * +AsIfFlatTexts::in (const Texts &other, bool invert) const +{ + std::set op; + for (TextsIterator o (other.begin ()); ! o.at_end (); ++o) { + op.insert (*o); + } + + std::auto_ptr new_texts (new FlatTexts (false)); + + for (TextsIterator o (begin ()); ! o.at_end (); ++o) { + if ((op.find (*o) == op.end ()) == invert) { + new_texts->insert (*o); + } + } + + return new_texts.release (); +} + +size_t +AsIfFlatTexts::size () const +{ + size_t n = 0; + for (TextsIterator t (begin ()); ! t.at_end (); ++t) { + ++n; + } + return n; +} + +Box AsIfFlatTexts::bbox () const +{ + if (! m_bbox_valid) { + m_bbox = compute_bbox (); + m_bbox_valid = true; + } + return m_bbox; +} + +Box AsIfFlatTexts::compute_bbox () const +{ + db::Box b; + for (TextsIterator t (begin ()); ! t.at_end (); ++t) { + b += t->box (); + } + return b; +} + +void AsIfFlatTexts::update_bbox (const db::Box &b) +{ + m_bbox = b; + m_bbox_valid = true; +} + +void AsIfFlatTexts::invalidate_bbox () +{ + m_bbox_valid = false; +} + +TextsDelegate * +AsIfFlatTexts::filtered (const TextFilterBase &filter) const +{ + std::auto_ptr new_texts (new FlatTexts ()); + + for (TextsIterator p (begin ()); ! p.at_end (); ++p) { + if (filter.selected (*p)) { + new_texts->insert (*p); + } + } + + return new_texts.release (); +} + +RegionDelegate * +AsIfFlatTexts::polygons (db::Coord e) const +{ + std::auto_ptr output (new FlatRegion ()); + + for (TextsIterator tp (begin ()); ! tp.at_end (); ++tp) { + db::Box box = tp->box (); + box.enlarge (db::Vector (e, e)); + output->insert (db::Polygon (box)); + } + + return output.release (); +} + +EdgesDelegate * +AsIfFlatTexts::edges () const +{ + std::auto_ptr output (new FlatEdges ()); + + for (TextsIterator tp (begin ()); ! tp.at_end (); ++tp) { + db::Box box = tp->box (); + output->insert (db::Edge (box.p1 (), box.p2 ())); + } + + return output.release (); +} + +TextsDelegate * +AsIfFlatTexts::add (const Texts &other) const +{ + FlatTexts *other_flat = dynamic_cast (other.delegate ()); + if (other_flat) { + + std::auto_ptr new_texts (new FlatTexts (*other_flat)); + new_texts->invalidate_cache (); + + size_t n = new_texts->raw_texts ().size () + size (); + + new_texts->reserve (n); + + for (TextsIterator p (begin ()); ! p.at_end (); ++p) { + new_texts->raw_texts ().insert (*p); + } + + return new_texts.release (); + + } else { + + std::auto_ptr new_texts (new FlatTexts ()); + + size_t n = size () + other.size (); + + new_texts->reserve (n); + + for (TextsIterator p (begin ()); ! p.at_end (); ++p) { + new_texts->raw_texts ().insert (*p); + } + for (TextsIterator p (other.begin ()); ! p.at_end (); ++p) { + new_texts->raw_texts ().insert (*p); + } + + return new_texts.release (); + + } +} + +bool +AsIfFlatTexts::equals (const Texts &other) const +{ + if (empty () != other.empty ()) { + return false; + } + if (size () != other.size ()) { + return false; + } + TextsIterator o1 (begin ()); + TextsIterator o2 (other.begin ()); + while (! o1.at_end () && ! o2.at_end ()) { + if (*o1 != *o2) { + return false; + } + ++o1; + ++o2; + } + return true; +} + +bool +AsIfFlatTexts::less (const Texts &other) const +{ + if (empty () != other.empty ()) { + return empty () < other.empty (); + } + if (size () != other.size ()) { + return (size () < other.size ()); + } + TextsIterator o1 (begin ()); + TextsIterator o2 (other.begin ()); + while (! o1.at_end () && ! o2.at_end ()) { + if (*o1 != *o2) { + return *o1 < *o2; + } + ++o1; + ++o2; + } + return false; +} + +void +AsIfFlatTexts::insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const +{ + // improves performance when inserting an original layout into the same layout + db::LayoutLocker locker (layout); + + db::Shapes &shapes = layout->cell (into_cell).shapes (into_layer); + for (TextsIterator t (begin ()); ! t.at_end (); ++t) { + shapes.insert (*t); + } +} + +void +AsIfFlatTexts::insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const +{ + // improves performance when inserting an original layout into the same layout + db::LayoutLocker locker (layout); + + db::Shapes &shapes = layout->cell (into_cell).shapes (into_layer); + for (TextsIterator t (begin ()); ! t.at_end (); ++t) { + db::Box box = t->box (); + box.enlarge (db::Vector (enl, enl)); + shapes.insert (db::SimplePolygon (box)); + } +} + +} + diff --git a/src/db/db/dbAsIfFlatTexts.h b/src/db/db/dbAsIfFlatTexts.h new file mode 100644 index 000000000..a2236cc7f --- /dev/null +++ b/src/db/db/dbAsIfFlatTexts.h @@ -0,0 +1,88 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 + +*/ + + +#ifndef HDR_dbAsIfFlatTexts +#define HDR_dbAsIfFlatTexts + +#include "dbCommon.h" + +#include "dbTextsDelegate.h" + +namespace db { + +/** + * @brief Provides default flat implementations + */ +class DB_PUBLIC AsIfFlatTexts + : public TextsDelegate +{ +public: + AsIfFlatTexts (); + virtual ~AsIfFlatTexts (); + + virtual size_t size () const; + virtual std::string to_string (size_t) const; + virtual Box bbox () const; + + virtual TextsDelegate *filter_in_place (const TextFilterBase &filter) + { + return filtered (filter); + } + + virtual TextsDelegate *filtered (const TextFilterBase &) const; + + virtual TextsDelegate *add_in_place (const Texts &other) + { + return add (other); + } + + virtual TextsDelegate *add (const Texts &other) const; + + virtual RegionDelegate *polygons (db::Coord e) const; + virtual EdgesDelegate *edges () const; + + virtual TextsDelegate *in (const Texts &, bool) const; + + virtual bool equals (const Texts &other) const; + virtual bool less (const Texts &other) const; + + virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const; + virtual void insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const; + +protected: + void update_bbox (const db::Box &box); + void invalidate_bbox (); + +private: + AsIfFlatTexts &operator= (const AsIfFlatTexts &other); + + mutable bool m_bbox_valid; + mutable db::Box m_bbox; + + virtual db::Box compute_bbox () const; +}; + +} + +#endif + diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index c1fcb9009..061b4b180 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -807,64 +807,20 @@ DeepLayer DeepShapeStore::create_copy (const DeepLayer &source, HierarchyBuilder 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); - - db::Layout &layout = m_layouts[layout_index]->layout; - db::HierarchyBuilder &builder = m_layouts[layout_index]->builder; - - unsigned int layer_index = init_layer (layout, si); - builder.set_target_layer (layer_index); - - // The chain of operators for producing edges db::EdgeBuildingHierarchyBuilderShapeReceiver refs (as_edges); - - // Build the working hierarchy from the recursive shape iterator - try { - - tl::SelfTimer timer (tl::verbosity () >= 41, tl::to_string (tr ("Building working hierarchy"))); - db::LayoutLocker ll (&layout, true /*no update*/); - - builder.set_shape_receiver (&refs); - db::RecursiveShapeIterator (si).push (& builder); - builder.set_shape_receiver (0); - - } catch (...) { - builder.set_shape_receiver (0); - throw; - } - - return DeepLayer (this, layout_index, layer_index); + return create_custom_layer (si, &refs, trans); } DeepLayer DeepShapeStore::create_edge_pair_layer (const db::RecursiveShapeIterator &si, const db::ICplxTrans &trans) { - unsigned int layout_index = layout_for_iter (si, trans); - - db::Layout &layout = m_layouts[layout_index]->layout; - db::HierarchyBuilder &builder = m_layouts[layout_index]->builder; - - unsigned int layer_index = init_layer (layout, si); - builder.set_target_layer (layer_index); - - // The chain of operators for producing the edge pairs db::EdgePairBuildingHierarchyBuilderShapeReceiver refs; + return create_custom_layer (si, &refs, trans); +} - // Build the working hierarchy from the recursive shape iterator - try { - - tl::SelfTimer timer (tl::verbosity () >= 41, tl::to_string (tr ("Building working hierarchy"))); - db::LayoutLocker ll (&layout, true /*no update*/); - - builder.set_shape_receiver (&refs); - db::RecursiveShapeIterator (si).push (& builder); - builder.set_shape_receiver (0); - - } catch (...) { - builder.set_shape_receiver (0); - throw; - } - - return DeepLayer (this, layout_index, layer_index); +DeepLayer DeepShapeStore::create_text_layer (const db::RecursiveShapeIterator &si, const db::ICplxTrans &trans) +{ + db::TextBuildingHierarchyBuilderShapeReceiver refs; + return create_custom_layer (si, &refs, trans); } void diff --git a/src/db/db/dbDeepShapeStore.h b/src/db/db/dbDeepShapeStore.h index 3290d5573..3c4e678ec 100644 --- a/src/db/db/dbDeepShapeStore.h +++ b/src/db/db/dbDeepShapeStore.h @@ -395,6 +395,15 @@ public: */ DeepLayer create_edge_pair_layer (const db::RecursiveShapeIterator &si, const ICplxTrans &trans = db::ICplxTrans ()); + /** + * @brief Inserts an text 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. This method creates a layer + * for texts. + */ + DeepLayer create_text_layer (const db::RecursiveShapeIterator &si, const ICplxTrans &trans = db::ICplxTrans ()); + /** * @brief Inserts a polygon layer into the deep shape store using a custom preparation pipeline * diff --git a/src/db/db/dbDeepTexts.cc b/src/db/db/dbDeepTexts.cc new file mode 100644 index 000000000..479ee93c5 --- /dev/null +++ b/src/db/db/dbDeepTexts.cc @@ -0,0 +1,316 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 "dbDeepTexts.h" +#include "dbCellGraphUtils.h" +#include "dbDeepEdges.h" +#include "dbDeepRegion.h" +#include "dbCellMapping.h" +#include "dbLayoutUtils.h" + +#include + +namespace db +{ + +/** + * @brief An iterator delegate for the deep text collection + * TODO: this is kind of redundant with OriginalLayerIterator .. + */ +class DB_PUBLIC DeepTextsIterator + : public TextsIteratorDelegate +{ +public: + DeepTextsIterator (const db::RecursiveShapeIterator &iter) + : m_iter (iter) + { + set (); + } + + virtual ~DeepTextsIterator () { } + + virtual bool at_end () const + { + return m_iter.at_end (); + } + + virtual void increment () + { + ++m_iter; + set (); + } + + virtual const value_type *get () const + { + return &m_text; + } + + virtual TextsIteratorDelegate *clone () const + { + return new DeepTextsIterator (*this); + } + +private: + friend class Texts; + + db::RecursiveShapeIterator m_iter; + mutable value_type m_text; + + void set () const { + if (! m_iter.at_end ()) { + m_iter.shape ().text (m_text); + m_text.transform (m_iter.trans ()); + } + } +}; + + +DeepTexts::DeepTexts () + : AsIfFlatTexts (), m_deep_layer () +{ + // .. nothing yet .. +} + +DeepTexts::DeepTexts (const RecursiveShapeIterator &si, DeepShapeStore &dss) + : AsIfFlatTexts (), m_deep_layer (dss.create_text_layer (si)) +{ + // .. nothing yet .. +} + +DeepTexts::DeepTexts (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans) + : AsIfFlatTexts (), m_deep_layer (dss.create_text_layer (si, trans)) +{ + // .. nothing yet .. +} + +DeepTexts::DeepTexts (const DeepTexts &other) + : AsIfFlatTexts (other), + m_deep_layer (other.m_deep_layer.copy ()) +{ + // .. nothing yet .. +} + +DeepTexts::DeepTexts (const DeepLayer &dl) + : AsIfFlatTexts (), m_deep_layer (dl) +{ + // .. nothing yet .. +} + +DeepTexts::~DeepTexts () +{ + // .. nothing yet .. +} + +TextsDelegate *DeepTexts::clone () const +{ + return new DeepTexts (*this); +} + +TextsIteratorDelegate *DeepTexts::begin () const +{ + return new DeepTextsIterator (begin_iter ().first); +} + +std::pair DeepTexts::begin_iter () const +{ + const db::Layout &layout = m_deep_layer.layout (); + if (layout.cells () == 0) { + + return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ()); + + } else { + + const db::Cell &top_cell = layout.cell (*layout.begin_top_down ()); + db::RecursiveShapeIterator iter (m_deep_layer.layout (), top_cell, m_deep_layer.layer ()); + return std::make_pair (iter, db::ICplxTrans ()); + + } +} + +size_t DeepTexts::size () const +{ + size_t n = 0; + + const db::Layout &layout = m_deep_layer.layout (); + db::CellCounter cc (&layout); + for (db::Layout::top_down_const_iterator c = layout.begin_top_down (); c != layout.end_top_down (); ++c) { + n += cc.weight (*c) * layout.cell (*c).shapes (m_deep_layer.layer ()).size (); + } + + return n; +} + +std::string DeepTexts::to_string (size_t nmax) const +{ + return db::AsIfFlatTexts::to_string (nmax); +} + +Box DeepTexts::bbox () const +{ + return m_deep_layer.initial_cell ().bbox (m_deep_layer.layer ()); +} + +bool DeepTexts::empty () const +{ + return begin_iter ().first.at_end (); +} + +const db::Text *DeepTexts::nth (size_t) const +{ + throw tl::Exception (tl::to_string (tr ("Random access to texts is available only for flat text collections"))); +} + +bool DeepTexts::has_valid_texts () const +{ + return false; +} + +const db::RecursiveShapeIterator *DeepTexts::iter () const +{ + return 0; +} + +TextsDelegate * +DeepTexts::add_in_place (const Texts &other) +{ + if (other.empty ()) { + return this; + } + + const DeepTexts *other_deep = dynamic_cast (other.delegate ()); + if (other_deep) { + + deep_layer ().add_from (other_deep->deep_layer ()); + + } else { + + // non-deep to deep merge (flat) + + db::Shapes &shapes = deep_layer ().initial_cell ().shapes (deep_layer ().layer ()); + for (db::Texts::const_iterator p = other.begin (); ! p.at_end (); ++p) { + shapes.insert (*p); + } + + } + + return this; +} + +TextsDelegate *DeepTexts::add (const Texts &other) const +{ + if (other.empty ()) { + return clone (); + } else if (empty ()) { + return other.delegate ()->clone (); + } else { + DeepTexts *new_texts = dynamic_cast (clone ()); + new_texts->add_in_place (other); + return new_texts; + } +} + +TextsDelegate *DeepTexts::filter_in_place (const TextFilterBase &filter) +{ + // TODO: implement + return AsIfFlatTexts::filter_in_place (filter); +} + +TextsDelegate *DeepTexts::filtered (const TextFilterBase &filter) const +{ + // TODO: implement + return AsIfFlatTexts::filtered (filter); +} + +RegionDelegate *DeepTexts::polygons (db::Coord e) const +{ + db::DeepLayer new_layer = m_deep_layer.derived (); + db::Layout &layout = const_cast (m_deep_layer.layout ()); + + for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { + db::Shapes &output = c->shapes (new_layer.layer ()); + for (db::Shapes::shape_iterator s = c->shapes (m_deep_layer.layer ()).begin (db::ShapeIterator::Texts); ! s.at_end (); ++s) { + db::Box box = s->bbox (); + box.enlarge (db::Vector (e, e)); + db::Polygon poly (box); + output.insert (db::PolygonRef (poly, layout.shape_repository ())); + } + } + + return new db::DeepRegion (new_layer); +} + +EdgesDelegate *DeepTexts::edges () const +{ + db::DeepLayer new_layer = m_deep_layer.derived (); + db::Layout &layout = const_cast (m_deep_layer.layout ()); + + for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { + db::Shapes &output = c->shapes (new_layer.layer ()); + for (db::Shapes::shape_iterator s = c->shapes (m_deep_layer.layer ()).begin (db::ShapeIterator::Texts); ! s.at_end (); ++s) { + db::Box box = s->bbox (); + output.insert (db::Edge (box.p1 (), box.p2 ())); + } + } + + return new db::DeepEdges (new_layer); +} + +TextsDelegate *DeepTexts::in (const Texts &other, bool invert) const +{ + // TODO: implement + return AsIfFlatTexts::in (other, invert); +} + +bool DeepTexts::equals (const Texts &other) const +{ + const DeepTexts *other_delegate = dynamic_cast (other.delegate ()); + if (other_delegate && &other_delegate->m_deep_layer.layout () == &m_deep_layer.layout () + && other_delegate->m_deep_layer.layer () == m_deep_layer.layer ()) { + return true; + } else { + return AsIfFlatTexts::equals (other); + } +} + +bool DeepTexts::less (const Texts &other) const +{ + const DeepTexts *other_delegate = dynamic_cast (other.delegate ()); + if (other_delegate && &other_delegate->m_deep_layer.layout () == &m_deep_layer.layout ()) { + return other_delegate->m_deep_layer.layer () < m_deep_layer.layer (); + } else { + return AsIfFlatTexts::less (other); + } +} + +void DeepTexts::insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const +{ + m_deep_layer.insert_into (layout, into_cell, into_layer); +} + +void DeepTexts::insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const +{ + m_deep_layer.insert_into_as_polygons (layout, into_cell, into_layer, enl); +} + + +} diff --git a/src/db/db/dbDeepTexts.h b/src/db/db/dbDeepTexts.h new file mode 100644 index 000000000..bac1c081b --- /dev/null +++ b/src/db/db/dbDeepTexts.h @@ -0,0 +1,102 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 + +*/ + + +#ifndef HDR_dbDeepTexts +#define HDR_dbDeepTexts + +#include "dbCommon.h" + +#include "dbAsIfFlatTexts.h" +#include "dbDeepShapeStore.h" +#include "dbTexts.h" + +namespace db { + +/** + * @brief Provides hierarchical edges implementation + */ +class DB_PUBLIC DeepTexts + : public db::AsIfFlatTexts +{ +public: + DeepTexts (); + DeepTexts (const RecursiveShapeIterator &si, DeepShapeStore &dss); + DeepTexts (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans); + + DeepTexts (const DeepTexts &other); + DeepTexts (const DeepLayer &dl); + + virtual ~DeepTexts (); + + TextsDelegate *clone () const; + + virtual TextsIteratorDelegate *begin () const; + virtual std::pair begin_iter () const; + + virtual size_t size () const; + virtual std::string to_string (size_t) const; + virtual Box bbox () const; + virtual bool empty () const; + virtual const db::Text *nth (size_t n) const; + virtual bool has_valid_texts () const; + virtual const db::RecursiveShapeIterator *iter () const; + + virtual TextsDelegate *filter_in_place (const TextFilterBase &filter); + virtual TextsDelegate *filtered (const TextFilterBase &) const; + + virtual TextsDelegate *add_in_place (const Texts &other); + virtual TextsDelegate *add (const Texts &other) const; + + virtual RegionDelegate *polygons (db::Coord e) const; + virtual EdgesDelegate *edges () const; + + virtual TextsDelegate *in (const Texts &, bool) const; + + virtual bool equals (const Texts &other) const; + virtual bool less (const Texts &other) const; + + virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const; + virtual void insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const; + + const DeepLayer &deep_layer () const + { + return m_deep_layer; + } + + DeepLayer &deep_layer () + { + return m_deep_layer; + } + +private: + DeepTexts &operator= (const DeepTexts &other); + + DeepLayer m_deep_layer; + + void init (); +}; + +} + +#endif + diff --git a/src/db/db/dbEdges.h b/src/db/db/dbEdges.h index 3634e5d4e..c2d304ba0 100644 --- a/src/db/db/dbEdges.h +++ b/src/db/db/dbEdges.h @@ -1301,6 +1301,7 @@ public: private: friend class EdgePairs; + friend class Texts; EdgesDelegate *mp_delegate; diff --git a/src/db/db/dbEmptyTexts.cc b/src/db/db/dbEmptyTexts.cc new file mode 100644 index 000000000..1037a078b --- /dev/null +++ b/src/db/db/dbEmptyTexts.cc @@ -0,0 +1,88 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 "dbEmptyTexts.h" +#include "dbEmptyRegion.h" +#include "dbEmptyEdges.h" +#include "dbTexts.h" + +namespace db +{ + +// ------------------------------------------------------------------------------------------------------------- + +EmptyTexts::EmptyTexts () +{ + // .. nothing yet .. +} + +EmptyTexts::EmptyTexts (const EmptyTexts &other) + : TextsDelegate (other) +{ + // .. nothing yet .. +} + +TextsDelegate * +EmptyTexts::clone () const +{ + return new EmptyTexts (*this); +} + +RegionDelegate * +EmptyTexts::polygons (db::Coord) const +{ + return new EmptyRegion (); +} + +EdgesDelegate * +EmptyTexts::edges () const +{ + return new EmptyEdges (); +} + +TextsDelegate * +EmptyTexts::add_in_place (const Texts &other) +{ + return add (other); +} + +TextsDelegate * +EmptyTexts::add (const Texts &other) const +{ + return other.delegate ()->clone (); +} + +bool +EmptyTexts::equals (const Texts &other) const +{ + return other.empty (); +} + +bool +EmptyTexts::less (const Texts &other) const +{ + return other.empty () ? false : true; +} + +} + diff --git a/src/db/db/dbEmptyTexts.h b/src/db/db/dbEmptyTexts.h new file mode 100644 index 000000000..59520928b --- /dev/null +++ b/src/db/db/dbEmptyTexts.h @@ -0,0 +1,85 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 + +*/ + + +#ifndef HDR_dbEmptyTexts +#define HDR_dbEmptyTexts + +#include "dbCommon.h" + +#include "dbTextsDelegate.h" +#include "dbRecursiveShapeIterator.h" + +namespace db { + +/** + * @brief The delegate for the actual edge set implementation + */ +class DB_PUBLIC EmptyTexts + : public TextsDelegate +{ +public: + EmptyTexts (); + EmptyTexts (const EmptyTexts &other); + + virtual TextsDelegate *clone () const; + + virtual std::string to_string (size_t) const { return std::string (); } + + virtual TextsIteratorDelegate *begin () const { return 0; } + virtual std::pair begin_iter () const { return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ()); } + + virtual bool empty () const { return true; } + virtual size_t size () const { return 0; } + + virtual Box bbox () const { return Box (); } + + virtual TextsDelegate *filter_in_place (const TextFilterBase &) { return this; } + virtual TextsDelegate *filtered (const TextFilterBase &) const { return new EmptyTexts (); } + + virtual RegionDelegate *polygons (db::Coord e) const; + virtual EdgesDelegate *edges () const; + + virtual TextsDelegate *add_in_place (const Texts &other); + virtual TextsDelegate *add (const Texts &other) const; + + virtual TextsDelegate *in (const Texts &, bool) const { return new EmptyTexts (); } + + virtual const db::Text *nth (size_t) const { tl_assert (false); } + virtual bool has_valid_texts () const { return true; } + + virtual const db::RecursiveShapeIterator *iter () const { return 0; } + + virtual bool equals (const Texts &other) const; + virtual bool less (const Texts &other) const; + + virtual void insert_into (Layout *, db::cell_index_type, unsigned int) const { } + virtual void insert_into_as_polygons (Layout *, db::cell_index_type, unsigned int, db::Coord) const { } + +private: + EmptyTexts &operator= (const EmptyTexts &other); +}; + +} + +#endif + diff --git a/src/db/db/dbFlatTexts.cc b/src/db/db/dbFlatTexts.cc new file mode 100644 index 000000000..4e4152d3a --- /dev/null +++ b/src/db/db/dbFlatTexts.cc @@ -0,0 +1,220 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 "dbFlatTexts.h" +#include "dbEmptyTexts.h" +#include "dbTexts.h" + +namespace db +{ + +// ------------------------------------------------------------------------------------------------------------- +// FlatTexts implementation + +FlatTexts::FlatTexts () + : AsIfFlatTexts (), m_texts (false) +{ + // .. nothing yet .. +} + +FlatTexts::~FlatTexts () +{ + // .. nothing yet .. +} + +FlatTexts::FlatTexts (const FlatTexts &other) + : AsIfFlatTexts (other), m_texts (false) +{ + m_texts = other.m_texts; +} + +FlatTexts::FlatTexts (const db::Shapes &texts) + : AsIfFlatTexts (), m_texts (texts) +{ + // .. nothing yet .. +} + +void FlatTexts::invalidate_cache () +{ + invalidate_bbox (); +} + +void FlatTexts::reserve (size_t n) +{ + m_texts.reserve (db::Text::tag (), n); +} + +TextsIteratorDelegate *FlatTexts::begin () const +{ + return new FlatTextsIterator (m_texts.get_layer ().begin (), m_texts.get_layer ().end ()); +} + +std::pair FlatTexts::begin_iter () const +{ + return std::make_pair (db::RecursiveShapeIterator (m_texts), db::ICplxTrans ()); +} + +bool FlatTexts::empty () const +{ + return m_texts.empty (); +} + +size_t FlatTexts::size () const +{ + return m_texts.size (); +} + +Box FlatTexts::compute_bbox () const +{ + m_texts.update_bbox (); + return m_texts.bbox (); +} + +TextsDelegate * +FlatTexts::filter_in_place (const TextFilterBase &filter) +{ + text_iterator_type pw = m_texts.get_layer ().begin (); + for (TextsIterator p (begin ()); ! p.at_end (); ++p) { + if (filter.selected (*p)) { + if (pw == m_texts.get_layer ().end ()) { + m_texts.get_layer ().insert (*p); + pw = m_texts.get_layer ().end (); + } else { + m_texts.get_layer ().replace (pw++, *p); + } + } + } + + m_texts.get_layer ().erase (pw, m_texts.get_layer ().end ()); + + return this; +} + +TextsDelegate *FlatTexts::add (const Texts &other) const +{ + std::auto_ptr new_texts (new FlatTexts (*this)); + new_texts->invalidate_cache (); + + FlatTexts *other_flat = dynamic_cast (other.delegate ()); + if (other_flat) { + + new_texts->raw_texts ().insert (other_flat->raw_texts ().get_layer ().begin (), other_flat->raw_texts ().get_layer ().end ()); + + } else { + + size_t n = new_texts->raw_texts ().size (); + for (TextsIterator p (other.begin ()); ! p.at_end (); ++p) { + ++n; + } + + new_texts->raw_texts ().reserve (db::Text::tag (), n); + + for (TextsIterator p (other.begin ()); ! p.at_end (); ++p) { + new_texts->raw_texts ().insert (*p); + } + + } + + return new_texts.release (); +} + +TextsDelegate *FlatTexts::add_in_place (const Texts &other) +{ + invalidate_cache (); + + FlatTexts *other_flat = dynamic_cast (other.delegate ()); + if (other_flat) { + + m_texts.insert (other_flat->raw_texts ().get_layer ().begin (), other_flat->raw_texts ().get_layer ().end ()); + + } else { + + size_t n = m_texts.size (); + for (TextsIterator p (other.begin ()); ! p.at_end (); ++p) { + ++n; + } + + m_texts.reserve (db::Text::tag (), n); + + for (TextsIterator p (other.begin ()); ! p.at_end (); ++p) { + m_texts.insert (*p); + } + + } + + return this; +} + +const db::Text *FlatTexts::nth (size_t n) const +{ + return n < m_texts.size () ? &m_texts.get_layer ().begin () [n] : 0; +} + +bool FlatTexts::has_valid_texts () const +{ + return true; +} + +const db::RecursiveShapeIterator *FlatTexts::iter () const +{ + return 0; +} + +void +FlatTexts::insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const +{ + db::Shapes &out = layout->cell (into_cell).shapes (into_layer); + for (TextsIterator p (begin ()); ! p.at_end (); ++p) { + db::Box box = p->box (); + box.enlarge (db::Vector (enl, enl)); + out.insert (db::SimplePolygon (box)); + } +} + +void +FlatTexts::insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const +{ + layout->cell (into_cell).shapes (into_layer).insert (m_texts); +} + +void +FlatTexts::insert (const db::Text &t) +{ + m_texts.insert (t); + invalidate_cache (); +} + +void +FlatTexts::insert (const db::Shape &shape) +{ + if (shape.is_edge_pair ()) { + + db::Text t; + shape.text (t); + insert (t); + + } +} + +} + diff --git a/src/db/db/dbFlatTexts.h b/src/db/db/dbFlatTexts.h new file mode 100644 index 000000000..38a249fbe --- /dev/null +++ b/src/db/db/dbFlatTexts.h @@ -0,0 +1,171 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 + +*/ + + +#ifndef HDR_dbFlatTexts +#define HDR_dbFlatTexts + +#include "dbCommon.h" + +#include "dbAsIfFlatTexts.h" +#include "dbShapes.h" + +namespace db { + +/** + * @brief An iterator delegate for the flat text set + */ +class DB_PUBLIC FlatTextsIterator + : public TextsIteratorDelegate +{ +public: + typedef db::layer edge_pair_layer_type; + typedef edge_pair_layer_type::iterator iterator_type; + + FlatTextsIterator (iterator_type from, iterator_type to) + : m_from (from), m_to (to) + { + // .. nothing yet .. + } + + virtual bool at_end () const + { + return m_from == m_to; + } + + virtual void increment () + { + ++m_from; + } + + virtual const value_type *get () const + { + return m_from.operator-> (); + } + + virtual TextsIteratorDelegate *clone () const + { + return new FlatTextsIterator (*this); + } + +private: + friend class Texts; + + iterator_type m_from, m_to; +}; + +/** + * @brief The delegate for the actual text set implementation + */ +class DB_PUBLIC FlatTexts + : public AsIfFlatTexts +{ +public: + typedef db::layer text_layer_type; + typedef text_layer_type::iterator text_iterator_type; + + FlatTexts (); + FlatTexts (const db::Shapes &texts); + + FlatTexts (const FlatTexts &other); + + virtual ~FlatTexts (); + + TextsDelegate *clone () const + { + return new FlatTexts (*this); + } + + void reserve (size_t); + + virtual TextsIteratorDelegate *begin () const; + virtual std::pair begin_iter () const; + + virtual bool empty () const; + virtual size_t size () const; + + virtual TextsDelegate *filter_in_place (const TextFilterBase &filter); + + virtual TextsDelegate *add_in_place (const Texts &other); + virtual TextsDelegate *add (const Texts &other) const; + + virtual const db::Text *nth (size_t n) const; + virtual bool has_valid_texts () const; + + virtual const db::RecursiveShapeIterator *iter () const; + + virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const; + virtual void insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const; + + void insert (const db::Text &text); + void insert (const db::Shape &shape); + + template + void insert (const db::Shape &shape, const T &trans) + { + if (shape.is_edge_pair ()) { + + db::Text t; + shape.text (t); + t.transform (trans); + insert (t); + + } + } + + template + void insert_seq (const Iter &seq) + { + for (Iter i = seq; ! i.at_end (); ++i) { + insert (*i); + } + } + + template + void transform (const Trans &trans) + { + if (! trans.is_unity ()) { + for (text_iterator_type p = m_texts.template get_layer ().begin (); p != m_texts.template get_layer ().end (); ++p) { + m_texts.get_layer ().replace (p, p->transformed (trans)); + } + invalidate_cache (); + } + } + + db::Shapes &raw_texts () { return m_texts; } + +protected: + virtual Box compute_bbox () const; + void invalidate_cache (); + +private: + friend class AsIfFlatTexts; + + FlatTexts &operator= (const FlatTexts &other); + + mutable db::Shapes m_texts; +}; + +} + +#endif + diff --git a/src/db/db/dbHierarchyBuilder.cc b/src/db/db/dbHierarchyBuilder.cc index a548c0341..50340a6a1 100644 --- a/src/db/db/dbHierarchyBuilder.cc +++ b/src/db/db/dbHierarchyBuilder.cc @@ -704,4 +704,18 @@ void EdgePairBuildingHierarchyBuilderShapeReceiver::push (const db::Shape &shape } } +// --------------------------------------------------------------------------------------------- + +TextBuildingHierarchyBuilderShapeReceiver::TextBuildingHierarchyBuilderShapeReceiver () +{ + // .. nothing yet .. +} + +void TextBuildingHierarchyBuilderShapeReceiver::push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box & /*region*/, const db::RecursiveShapeReceiver::box_tree_type * /*complex_region*/, db::Shapes *target) +{ + if (shape.is_text ()) { + target->insert (shape.text ().transformed (trans)); + } +} + } diff --git a/src/db/db/dbHierarchyBuilder.h b/src/db/db/dbHierarchyBuilder.h index b1d323dc7..9b115bb05 100644 --- a/src/db/db/dbHierarchyBuilder.h +++ b/src/db/db/dbHierarchyBuilder.h @@ -189,6 +189,20 @@ public: virtual void push (const db::Polygon &, const db::ICplxTrans &, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *) { } }; +/** + * @brief An text-generating shape receiver that feeds a shapes array after turning the shapes into texts + */ +class DB_PUBLIC TextBuildingHierarchyBuilderShapeReceiver + : public HierarchyBuilderShapeReceiver +{ +public: + TextBuildingHierarchyBuilderShapeReceiver (); + + virtual void push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *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 *) { } +}; + /** * @brief A class building a hierarchy from a recursive shape iterator in push mode * diff --git a/src/db/db/dbOriginalLayerTexts.cc b/src/db/db/dbOriginalLayerTexts.cc new file mode 100644 index 000000000..ceb8534fd --- /dev/null +++ b/src/db/db/dbOriginalLayerTexts.cc @@ -0,0 +1,197 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 "dbOriginalLayerTexts.h" +#include "dbTexts.h" +#include "tlInternational.h" + +namespace db +{ + +// ------------------------------------------------------------------------------------------------------------- +// OriginalLayerTexts implementation + +namespace +{ + + class OriginalLayerTextsIterator + : public TextsIteratorDelegate + { + public: + OriginalLayerTextsIterator (const db::RecursiveShapeIterator &iter, const db::ICplxTrans &trans) + : m_rec_iter (iter), m_iter_trans (trans) + { + set (); + } + + virtual bool at_end () const + { + return m_rec_iter.at_end (); + } + + virtual void increment () + { + inc (); + set (); + } + + virtual const value_type *get () const + { + return &m_text; + } + + virtual TextsIteratorDelegate *clone () const + { + return new OriginalLayerTextsIterator (*this); + } + + private: + friend class Texts; + + db::RecursiveShapeIterator m_rec_iter; + db::ICplxTrans m_iter_trans; + db::Text m_text; + + void set () + { + while (! m_rec_iter.at_end () && ! m_rec_iter.shape ().is_text ()) { + ++m_rec_iter; + } + if (! m_rec_iter.at_end ()) { + m_rec_iter.shape ().text (m_text); + m_text.transform (m_iter_trans * m_rec_iter.trans ()); + } + } + + void inc () + { + if (! m_rec_iter.at_end ()) { + ++m_rec_iter; + } + } + }; + +} + +OriginalLayerTexts::OriginalLayerTexts () + : AsIfFlatTexts () +{ + init (); +} + +OriginalLayerTexts::OriginalLayerTexts (const OriginalLayerTexts &other) + : AsIfFlatTexts (other), + m_iter (other.m_iter), + m_iter_trans (other.m_iter_trans) +{ + // .. nothing yet .. +} + +OriginalLayerTexts::OriginalLayerTexts (const RecursiveShapeIterator &si) + : AsIfFlatTexts (), m_iter (si) +{ + init (); +} + +OriginalLayerTexts::OriginalLayerTexts (const RecursiveShapeIterator &si, const db::ICplxTrans &trans) + : AsIfFlatTexts (), m_iter (si), m_iter_trans (trans) +{ + init (); +} + +OriginalLayerTexts::~OriginalLayerTexts () +{ + // .. nothing yet .. +} + +TextsDelegate * +OriginalLayerTexts::clone () const +{ + return new OriginalLayerTexts (*this); +} + +TextsIteratorDelegate * +OriginalLayerTexts::begin () const +{ + return new OriginalLayerTextsIterator (m_iter, m_iter_trans); +} + +std::pair +OriginalLayerTexts::begin_iter () const +{ + return std::make_pair (m_iter, m_iter_trans); +} + +bool +OriginalLayerTexts::empty () const +{ + return m_iter.at_end (); +} + +const db::Text * +OriginalLayerTexts::nth (size_t) const +{ + throw tl::Exception (tl::to_string (tr ("Random access to texts is available only for flat collections"))); +} + +bool +OriginalLayerTexts::has_valid_texts () const +{ + return false; +} + +const db::RecursiveShapeIterator * +OriginalLayerTexts::iter () const +{ + return &m_iter; +} + +bool +OriginalLayerTexts::equals (const Texts &other) const +{ + const OriginalLayerTexts *other_delegate = dynamic_cast (other.delegate ()); + if (other_delegate && other_delegate->m_iter == m_iter && other_delegate->m_iter_trans == m_iter_trans) { + return true; + } else { + return AsIfFlatTexts::equals (other); + } +} + +bool +OriginalLayerTexts::less (const Texts &other) const +{ + const OriginalLayerTexts *other_delegate = dynamic_cast (other.delegate ()); + if (other_delegate && other_delegate->m_iter == m_iter && other_delegate->m_iter_trans == m_iter_trans) { + return false; + } else { + return AsIfFlatTexts::less (other); + } +} + +void +OriginalLayerTexts::init () +{ + // .. nothing yet .. +} + +} diff --git a/src/db/db/dbOriginalLayerTexts.h b/src/db/db/dbOriginalLayerTexts.h new file mode 100644 index 000000000..32afd1e3f --- /dev/null +++ b/src/db/db/dbOriginalLayerTexts.h @@ -0,0 +1,75 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 + +*/ + + +#ifndef HDR_dbOriginalLayerTexts +#define HDR_dbOriginalLayerTexts + +#include "dbCommon.h" + +#include "dbAsIfFlatTexts.h" +#include "dbShapes.h" +#include "dbRecursiveShapeIterator.h" + +namespace db { + +/** + * @brief An original layer text collection based on a RecursiveShapeIterator + */ +class DB_PUBLIC OriginalLayerTexts + : public AsIfFlatTexts +{ +public: + OriginalLayerTexts (); + OriginalLayerTexts (const OriginalLayerTexts &other); + OriginalLayerTexts (const RecursiveShapeIterator &si); + OriginalLayerTexts (const RecursiveShapeIterator &si, const db::ICplxTrans &trans); + virtual ~OriginalLayerTexts (); + + TextsDelegate *clone () const; + + virtual TextsIteratorDelegate *begin () const; + virtual std::pair begin_iter () const; + + virtual bool empty () const; + + virtual const db::Text *nth (size_t n) const; + virtual bool has_valid_texts () const; + + virtual const db::RecursiveShapeIterator *iter () const; + + virtual bool equals (const Texts &other) const; + virtual bool less (const Texts &other) const; + +private: + OriginalLayerTexts &operator= (const OriginalLayerTexts &other); + + mutable db::RecursiveShapeIterator m_iter; + db::ICplxTrans m_iter_trans; + + void init (); +}; + +} + +#endif + diff --git a/src/db/db/dbRegion.h b/src/db/db/dbRegion.h index bc8aa21df..5ac56c8d4 100644 --- a/src/db/db/dbRegion.h +++ b/src/db/db/dbRegion.h @@ -1612,6 +1612,7 @@ public: private: friend class Edges; friend class EdgePairs; + friend class Texts; RegionDelegate *mp_delegate; diff --git a/src/db/db/dbTexts.cc b/src/db/db/dbTexts.cc new file mode 100644 index 000000000..1ab956aa0 --- /dev/null +++ b/src/db/db/dbTexts.cc @@ -0,0 +1,207 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 "dbCommon.h" + +#include "dbTexts.h" +#include "dbEmptyTexts.h" +#include "dbFlatTexts.h" +#include "dbDeepTexts.h" +#include "dbOriginalLayerTexts.h" +#include "dbEdges.h" +#include "dbRegion.h" + +#include "tlVariant.h" + +#include + +namespace db +{ + +Texts::Texts () + : mp_delegate (new EmptyTexts ()) +{ + // .. nothing yet .. +} + +Texts::~Texts () +{ + delete mp_delegate; + mp_delegate = 0; +} + +Texts::Texts (TextsDelegate *delegate) + : mp_delegate (delegate) +{ + // .. nothing yet .. +} + +Texts::Texts (const Texts &other) + : gsi::ObjectBase (), mp_delegate (other.mp_delegate->clone ()) +{ + // .. nothing yet .. +} + +Texts &Texts::operator= (const Texts &other) +{ + if (this != &other) { + set_delegate (other.mp_delegate->clone ()); + } + return *this; +} + +Texts::Texts (const RecursiveShapeIterator &si) +{ + mp_delegate = new OriginalLayerTexts (si); +} + +Texts::Texts (const RecursiveShapeIterator &si, const db::ICplxTrans &trans) +{ + mp_delegate = new OriginalLayerTexts (si, trans); +} + +Texts::Texts (const RecursiveShapeIterator &si, DeepShapeStore &dss) +{ + mp_delegate = new DeepTexts (si, dss); +} + +Texts::Texts (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans) +{ + mp_delegate = new DeepTexts (si, dss, trans); +} + +template +void Texts::insert (const Sh &shape) +{ + flat_texts ()->insert (shape); +} + +template DB_PUBLIC void Texts::insert (const db::Text &); + +void Texts::insert (const db::Shape &shape) +{ + flat_texts ()->insert (shape); +} + +template +void Texts::insert (const db::Shape &shape, const T &trans) +{ + flat_texts ()->insert (shape, trans); +} + +template DB_PUBLIC void Texts::insert (const db::Shape &, const db::ICplxTrans &); +template DB_PUBLIC void Texts::insert (const db::Shape &, const db::Trans &); +template DB_PUBLIC void Texts::insert (const db::Shape &, const db::Disp &); + +void Texts::clear () +{ + set_delegate (new EmptyTexts ()); +} + +void Texts::reserve (size_t n) +{ + flat_texts ()->reserve (n); +} + +template +Texts &Texts::transform (const T &trans) +{ + flat_texts ()->transform (trans); + return *this; +} + +// explicit instantiations +template DB_PUBLIC Texts &Texts::transform (const db::ICplxTrans &); +template DB_PUBLIC Texts &Texts::transform (const db::Trans &); +template DB_PUBLIC Texts &Texts::transform (const db::Disp &); + +const db::RecursiveShapeIterator & +Texts::iter () const +{ + static db::RecursiveShapeIterator def_iter; + const db::RecursiveShapeIterator *i = mp_delegate->iter (); + return *(i ? i : &def_iter); +} + +void Texts::polygons (Region &output, db::Coord e) const +{ + output.set_delegate (mp_delegate->polygons (e)); +} + +void Texts::edges (Edges &output) const +{ + output.set_delegate (mp_delegate->edges ()); +} + +void Texts::set_delegate (TextsDelegate *delegate) +{ + if (delegate != mp_delegate) { + delete mp_delegate; + mp_delegate = delegate; + } +} + +FlatTexts *Texts::flat_texts () +{ + FlatTexts *texts = dynamic_cast (mp_delegate); + if (! texts) { + texts = new FlatTexts (); + if (mp_delegate) { + texts->TextsDelegate::operator= (*mp_delegate); + texts->insert_seq (begin ()); + } + set_delegate (texts); + } + + return texts; +} + +} + +namespace tl +{ + template<> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::Texts &b) + { + db::Text ep; + + if (! ex.try_read (ep)) { + return false; + } + b.insert (ep); + + while (ex.test (";")) { + ex.read (ep); + b.insert (ep); + } + + return true; + } + + template<> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::Texts &b) + { + if (! test_extractor_impl (ex, b)) { + ex.error (tl::to_string (tr ("Expected an edge pair collection specification"))); + } + } +} + diff --git a/src/db/db/dbTexts.h b/src/db/db/dbTexts.h new file mode 100644 index 000000000..bfba8ac50 --- /dev/null +++ b/src/db/db/dbTexts.h @@ -0,0 +1,670 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 + +*/ + + +#ifndef HDR_dbTexts +#define HDR_dbTexts + +#include "dbTextsDelegate.h" +#include "dbShape.h" +#include "dbRecursiveShapeIterator.h" + +#include "gsiObject.h" + +#include + +namespace db +{ + +class TextFilterBase; +class FlatTexts; +class EmptyTexts; +class Edges; +class Region; +class DeepShapeStore; +class TransformationReducer; + +/** + * @brief An text set iterator + * + * The iterator delivers the texts of the text set + */ +class DB_PUBLIC TextsIterator +{ +public: + typedef TextsIteratorDelegate::value_type value_type; + typedef const value_type &reference; + typedef const value_type *pointer; + typedef std::forward_iterator_tag iterator_category; + typedef void difference_type; + + /** + * @brief Default constructor + */ + TextsIterator () + : mp_delegate (0) + { + // .. nothing yet .. + } + + /** + * @brief Constructor from a delegate + * The iterator will take ownership over the delegate + */ + TextsIterator (TextsIteratorDelegate *delegate) + : mp_delegate (delegate) + { + // .. nothing yet .. + } + + /** + * @brief Destructor + */ + ~TextsIterator () + { + delete mp_delegate; + mp_delegate = 0; + } + + /** + * @brief Copy constructor and assignment + */ + TextsIterator (const TextsIterator &other) + : mp_delegate (0) + { + operator= (other); + } + + /** + * @brief Assignment + */ + TextsIterator &operator= (const TextsIterator &other) + { + if (this != &other) { + delete mp_delegate; + mp_delegate = other.mp_delegate ? other.mp_delegate->clone () : 0; + } + return *this; + } + + /** + * @Returns true, if the iterator is at the end + */ + bool at_end () const + { + return mp_delegate == 0 || mp_delegate->at_end (); + } + + /** + * @brief Increment + */ + TextsIterator &operator++ () + { + if (mp_delegate) { + mp_delegate->increment (); + } + return *this; + } + + /** + * @brief Access + */ + reference operator* () const + { + const value_type *value = operator-> (); + tl_assert (value != 0); + return *value; + } + + /** + * @brief Access + */ + pointer operator-> () const + { + return mp_delegate ? mp_delegate->get () : 0; + } + +private: + TextsIteratorDelegate *mp_delegate; +}; + +/** + * @brief A helper class allowing delivery of addressable texts + * + * In some applications (i.e. box scanner), texts need to be taken + * by address. The text set cannot always deliver adressable edges. + * This class help providing this ability by keeping a temporary copy + * if required. + */ + +class DB_PUBLIC AddressableTextDelivery +{ +public: + AddressableTextDelivery () + : m_iter (), m_valid (false) + { + // .. nothing yet .. + } + + AddressableTextDelivery (const TextsIterator &iter, bool valid) + : m_iter (iter), m_valid (valid) + { + if (! m_valid && ! m_iter.at_end ()) { + m_heap.push_back (*m_iter); + } + } + + bool at_end () const + { + return m_iter.at_end (); + } + + AddressableTextDelivery &operator++ () + { + ++m_iter; + if (! m_valid && ! m_iter.at_end ()) { + m_heap.push_back (*m_iter); + } + return *this; + } + + const db::Text *operator-> () const + { + if (m_valid) { + return m_iter.operator-> (); + } else { + return &m_heap.back (); + } + } + +private: + TextsIterator m_iter; + bool m_valid; + std::list m_heap; +}; + +class Texts; + +/** + * @brief A base class for text filters + */ +class DB_PUBLIC TextFilterBase +{ +public: + TextFilterBase () { } + virtual ~TextFilterBase () { } + + virtual bool selected (const db::Text &text) const = 0; + virtual const TransformationReducer *vars () const = 0; +}; + +/** + * @brief A set of texts + * + * Texts are convenient objects describing labels (a point and a text). + * + * Text sets are created from a text-delivering recursive shape iterator for example. Text sets + * can be converted to polygons (representing a small box around the text's point) or to dot-like + * edges representing the point of the text. + */ +class DB_PUBLIC Texts + : public gsi::ObjectBase +{ +public: + typedef db::Coord coord_type; + typedef db::coord_traits coord_traits; + typedef db::Text edge_pair_type; + typedef db::Vector vector_type; + typedef db::Point point_type; + typedef db::Box box_type; + typedef coord_traits::distance_type distance_type; + typedef TextsIterator const_iterator; + + /** + * @brief Default constructor + * + * This constructor creates an empty text set. + */ + Texts (); + + /** + * @brief Destructor + */ + ~Texts (); + + /** + * @brief Constructor from a delegate + * + * The region will take ownership of the delegate. + */ + Texts (TextsDelegate *delegate); + + /** + * @brief Copy constructor + */ + Texts (const Texts &other); + + /** + * @brief Assignment + */ + Texts &operator= (const Texts &other); + + /** + * @brief Constructor from an object + * + * Creates an text set representing a single instance of that object + */ + explicit Texts (const db::Text &s) + : mp_delegate (0) + { + insert (s); + } + + /** + * @brief Constructor from an object + * + * Creates an text set representing a single instance of that object + */ + explicit Texts (const db::Shape &s) + : mp_delegate (0) + { + insert (s); + } + + /** + * @brief Sequence constructor + * + * Creates an edge set from a sequence of objects. The objects need to be texts. + * This version accepts iterators of the begin ... end style. + */ + template + explicit Texts (const Iter &b, const Iter &e) + : mp_delegate (0) + { + reserve (e - b); + for (Iter i = b; i != e; ++i) { + insert (*i); + } + } + + /** + * @brief Constructor from a RecursiveShapeIterator + * + * Creates an text set from a recursive shape iterator. This allows one to feed an text set + * from a hierarchy of cells. + */ + explicit Texts (const RecursiveShapeIterator &si); + + /** + * @brief Constructor from a RecursiveShapeIterator with a transformation + * + * Creates an text set from a recursive shape iterator. This allows one to feed an text set + * from a hierarchy of cells. The transformation is useful to scale to a specific + * DBU for example. + */ + explicit Texts (const RecursiveShapeIterator &si, const db::ICplxTrans &trans); + + /** + * @brief Constructor from a RecursiveShapeIterator providing a deep representation + * + * This version will create a hierarchical text collection. The DeepShapeStore needs to be provided + * during the lifetime of the collection and acts as a heap for optimized data. + */ + explicit Texts (const RecursiveShapeIterator &si, DeepShapeStore &dss); + + /** + * @brief Constructor from a RecursiveShapeIterator providing a deep representation with transformation + */ + explicit Texts (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans); + + /** + * @brief Gets the underlying delegate object + */ + TextsDelegate *delegate () const + { + return mp_delegate; + } + + /** + * @brief Iterator of the text set + * + * The iterator delivers the edges of the text set. + * It follows the at_end semantics. + */ + const_iterator begin () const + { + return TextsIterator (mp_delegate->begin ()); + } + + /** + * @brief Delivers a RecursiveShapeIterator pointing to the texts plus the necessary transformation + */ + std::pair begin_iter () const + { + return mp_delegate->begin_iter (); + } + + /** + * @brief Inserts the given shape (working object) into the text set + */ + template + void insert (const Sh &shape); + + /** + * @brief Insert a shape reference into the text set + */ + void insert (const db::Shape &shape); + + /** + * @brief Insert a transformed shape into the text set + */ + template + void insert (const db::Shape &shape, const T &trans); + + /** + * @brief Returns true if the edge pair set is empty + */ + bool empty () const + { + return mp_delegate->empty (); + } + + /** + * @brief Returns the number of texts in the text set + */ + size_t size () const + { + return mp_delegate->size (); + } + + /** + * @brief Returns a string representing the text set + * + * nmax specifies how many texts are included (set to std::numeric_limits::max() for "all". + */ + std::string to_string (size_t nmax = 10) const + { + return mp_delegate->to_string (nmax); + } + + /** + * @brief Clears the text set + */ + void clear (); + + /** + * @brief Reserve memory for the given number of texts + */ + void reserve (size_t n); + + /** + * @brief Returns the bounding box of the text set + */ + Box bbox () const + { + return mp_delegate->bbox (); + } + + /** + * @brief Filters the texts + * + * This method will keep all texts for which the filter returns true. + */ + Texts &filter (const TextFilterBase &filter) + { + set_delegate (mp_delegate->filter_in_place (filter)); + return *this; + } + + /** + * @brief Returns the filtered texts + * + * This method will return a new text set with only those texts which + * conform to the filter criterion. + */ + Texts filtered (const TextFilterBase &filter) const + { + return Texts (mp_delegate->filtered (filter)); + } + + /** + * @brief Transforms the text set + */ + template + Texts &transform (const T &trans); + + /** + * @brief Returns the transformed text set + */ + template + Texts transformed (const T &trans) const + { + Texts d (*this); + d.transform (trans); + return d; + } + + /** + * @brief Swaps with the other text set + */ + void swap (db::Texts &other) + { + std::swap (other.mp_delegate, mp_delegate); + } + + /** + * @brief Joining of text set + * + * This method joins the text sets. + */ + Texts operator+ (const Texts &other) const + { + return Texts (mp_delegate->add (other)); + } + + /** + * @brief In-place text set joining + */ + Texts &operator+= (const Texts &other) + { + set_delegate (mp_delegate->add_in_place (other)); + return *this; + } + + /** + * @brief Returns all texts which are in the other text set + * + * This method will return all texts which are part of another text set. + * The match is done exactly. + * The "invert" flag can be used to invert the sense, i.e. with + * "invert" set to true, this method will return all texts not + * in the other text set. + */ + Texts in (const Texts &other, bool invert = false) const + { + return Texts (mp_delegate->in (other, invert)); + } + + /** + * @brief Returns the nth text + * + * This operation is available only for flat regions - i.e. such for which + * "has_valid_texts" is true. + */ + const db::Text *nth (size_t n) const + { + return mp_delegate->nth (n); + } + + /** + * @brief Forces flattening of the text collection + * + * This method will turn any edge pair collection into a flat one. + */ + void flatten () + { + flat_texts (); + } + + /** + * @brief Returns true, if the text set has valid texts stored within itself + * + * If the region has valid texts, it is permissable to use the text's addresses + * from the iterator. Furthermore, the random access operator nth() is available. + */ + bool has_valid_texts () const + { + return mp_delegate->has_valid_texts (); + } + + /** + * @brief Returns an addressable delivery for texts + * + * This object allows accessing the texts by address, even if they + * are not delivered from a container. The magic is a heap object + * inside the delivery object. Hence, the deliver object must persist + * as long as the addresses are required. + */ + AddressableTextDelivery addressable_texts () const + { + return AddressableTextDelivery (begin (), has_valid_texts ()); + } + + /** + * @brief Gets the internal iterator + * + * This method is intended for users who know what they are doing + */ + const db::RecursiveShapeIterator &iter () const; + + /** + * @brief Equality + */ + bool operator== (const db::Texts &other) const + { + return mp_delegate->equals (other); + } + + /** + * @brief Inequality + */ + bool operator!= (const db::Texts &other) const + { + return ! mp_delegate->equals (other); + } + + /** + * @brief Less operator + */ + bool operator< (const db::Texts &other) const + { + return mp_delegate->less (other); + } + + /** + * @brief Converts to polygons + * + * Note: because of the include hierarchy we can't use a direct return value. + * + * The output container is not cleared by this method but polygons are rather + * appended. + * + * The given extension is applied in all directions rendering a square of 2*e + * width and height. The center of the boxes will be the position of the texts. + */ + void polygons (Region &output, db::Coord e = 1) const; + + /** + * @brief Returns individual, dot-like edges + * + * Note: because of the include hierarchy we can't use a direct return value. + * + * The returned edges will be dot-like (identical points) and represent the + * position of the text. + */ + void edges (Edges &output) const; + + /** + * @brief Enable progress reporting + * + * @param progress_text The description text of the progress object + */ + void enable_progress (const std::string &progress_desc = std::string ()) + { + mp_delegate->enable_progress (progress_desc); + } + + /** + * @brief Disable progress reporting + */ + void disable_progress () + { + mp_delegate->disable_progress (); + } + + /** + * @brief Inserts the edge pair collection into the given layout, cell and layer + * If the text collection is a hierarchical region, the hierarchy is copied into the + * layout's hierarchy. + */ + void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const + { + return mp_delegate->insert_into (layout, into_cell, into_layer); + } + + /** + * @brief Inserts the edge pair collection into the given layout, cell and layer as polygons with the given enlargement + * If the text collection is a hierarchical region, the hierarchy is copied into the + * layout's hierarchy. + */ + void insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const + { + return mp_delegate->insert_into_as_polygons (layout, into_cell, into_layer, enl); + } + +private: + TextsDelegate *mp_delegate; + + void set_delegate (TextsDelegate *delegate); + FlatTexts *flat_texts (); +}; + +} + +namespace tl +{ + /** + * @brief The type traits for the box type + */ + template <> + struct type_traits : public type_traits + { + typedef true_tag supports_extractor; + typedef true_tag supports_to_string; + typedef true_tag has_less_operator; + typedef true_tag has_equal_operator; + }; + +} + +#endif + diff --git a/src/db/db/dbTextsDelegate.cc b/src/db/db/dbTextsDelegate.cc new file mode 100644 index 000000000..0691920f4 --- /dev/null +++ b/src/db/db/dbTextsDelegate.cc @@ -0,0 +1,68 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 "dbTextsDelegate.h" + +namespace db +{ + +// ------------------------------------------------------------------------------------------------------------- + +TextsDelegate::TextsDelegate () +{ + m_report_progress = false; +} + +TextsDelegate::TextsDelegate (const TextsDelegate &other) + : tl::UniqueId () +{ + operator= (other); +} + +TextsDelegate & +TextsDelegate::operator= (const TextsDelegate &other) +{ + if (this != &other) { + m_report_progress = other.m_report_progress; + } + return *this; +} + +TextsDelegate::~TextsDelegate () +{ + // .. nothing yet .. +} + +void TextsDelegate::enable_progress (const std::string &progress_desc) +{ + m_report_progress = true; + m_progress_desc = progress_desc; +} + +void TextsDelegate::disable_progress () +{ + m_report_progress = false; +} + +} + diff --git a/src/db/db/dbTextsDelegate.h b/src/db/db/dbTextsDelegate.h new file mode 100644 index 000000000..d25eef6a3 --- /dev/null +++ b/src/db/db/dbTextsDelegate.h @@ -0,0 +1,140 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 + +*/ + + +#ifndef HDR_dbTextsDelegate +#define HDR_dbTextsDelegate + +#include "dbCommon.h" + +#include "dbText.h" +#include "tlUniqueId.h" + +namespace db { + +class RecursiveShapeIterator; +class Texts; +class TextFilterBase; +class RegionDelegate; +class EdgesDelegate; +class Layout; + +/** + * @brief The edge pair set iterator delegate + */ +class DB_PUBLIC TextsIteratorDelegate +{ +public: + TextsIteratorDelegate () { } + virtual ~TextsIteratorDelegate () { } + + typedef db::Text value_type; + + virtual bool at_end () const = 0; + virtual void increment () = 0; + virtual const value_type *get () const = 0; + virtual TextsIteratorDelegate *clone () const = 0; +}; + +/** + * @brief The delegate for the actual edge set implementation + */ +class DB_PUBLIC TextsDelegate + : public tl::UniqueId +{ +public: + typedef db::Coord coord_type; + typedef db::coord_traits coord_traits; + typedef db::Text edge_pair_type; + typedef db::Vector vector_type; + typedef db::Point point_type; + typedef db::Box box_type; + + TextsDelegate (); + virtual ~TextsDelegate (); + + TextsDelegate (const TextsDelegate &other); + TextsDelegate &operator= (const TextsDelegate &other); + + virtual TextsDelegate *clone () const = 0; + + void enable_progress (const std::string &progress_desc); + void disable_progress (); + + // dummy features to harmonize the interface of region, edges and edge pair delegates + void set_merged_semantics (bool) { } + bool merged_semantics () const { return false; } + void set_is_merged (bool) { } + bool is_merged () const { return false; } + + virtual std::string to_string (size_t nmax) const = 0; + + virtual TextsIteratorDelegate *begin () const = 0; + virtual std::pair begin_iter () const = 0; + + virtual bool empty () const = 0; + virtual size_t size () const = 0; + + virtual Box bbox () const = 0; + + virtual TextsDelegate *filter_in_place (const TextFilterBase &filter) = 0; + virtual TextsDelegate *filtered (const TextFilterBase &filter) const = 0; + + virtual RegionDelegate *polygons (db::Coord e) const = 0; + virtual EdgesDelegate *edges () const = 0; + + virtual TextsDelegate *add_in_place (const Texts &other) = 0; + virtual TextsDelegate *add (const Texts &other) const = 0; + + virtual TextsDelegate *in (const Texts &other, bool invert) const = 0; + + virtual const db::Text *nth (size_t n) const = 0; + virtual bool has_valid_texts () const = 0; + + virtual const db::RecursiveShapeIterator *iter () const = 0; + + virtual bool equals (const Texts &other) const = 0; + virtual bool less (const Texts &other) const = 0; + + virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const = 0; + virtual void insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const = 0; + +protected: + const std::string &progress_desc () const + { + return m_progress_desc; + } + + bool report_progress () const + { + return m_report_progress; + } + +private: + bool m_report_progress; + std::string m_progress_desc; +}; + +} + +#endif + diff --git a/src/db/db/dbTextsUtils.cc b/src/db/db/dbTextsUtils.cc new file mode 100644 index 000000000..9c39d3e05 --- /dev/null +++ b/src/db/db/dbTextsUtils.cc @@ -0,0 +1,31 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 "dbTextsUtils.h" +#include "dbRegion.h" + +namespace db +{ + + // .. nothing yet .. + +} diff --git a/src/db/db/dbTextsUtils.h b/src/db/db/dbTextsUtils.h new file mode 100644 index 000000000..5b604f89f --- /dev/null +++ b/src/db/db/dbTextsUtils.h @@ -0,0 +1,154 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 + +*/ + +#ifndef HDR_dbTextsUtils +#define HDR_dbTextsUtils + +#include "dbCommon.h" +#include "dbTexts.h" +#include "tlGlobPattern.h" + +namespace db { + +/** + * @brief An text filter filtering by a string + * + * It will filter all texts for which the string is equal to "text". + * There is an "invert" flag which allows selecting all texts not + * matching the criterion. + */ + +struct DB_PUBLIC TextStringFilter + : public TextFilterBase +{ + /** + * @brief Constructor + * + * @param text The text string to match + * @param inverse If set to true, only polygons not matching this criterion will be filtered + */ + TextStringFilter (const std::string &text, bool inverse) + : m_text (text), m_inverse (inverse) + { + // .. nothing yet .. + } + + /** + * @brief Returns true if the text matches the criterion + */ + virtual bool selected (const db::Text &text) const + { + return (text.string () == m_text) != m_inverse; + } + + /** + * @brief This filter is not sensitive to hierarchy + */ + virtual const TransformationReducer *vars () const + { + return 0; + } + + /** + * @brief Requires merged input + */ + virtual bool requires_raw_input () const + { + return false; + } + + /** + * @brief Wants to build variants + */ + virtual bool wants_variants () const + { + return false; + } + +private: + std::string m_text; + bool m_inverse; +}; + +/** + * @brief An text filter filtering by a glob-style pattern + * + * It will filter all texts for which the string matches the given glob-style pattern. + * There is an "invert" flag which allows selecting all texts not + * matching the criterion. + */ + +struct DB_PUBLIC TextPatternFilter + : public TextFilterBase +{ + /** + * @brief Constructor + * + * @param text The text pattern to match + * @param inverse If set to true, only polygons not matching this criterion will be filtered + */ + TextPatternFilter (const std::string &text, bool inverse) + : m_pattern (text), m_inverse (inverse) + { + // .. nothing yet .. + } + + /** + * @brief Returns true if the text matches the criterion + */ + virtual bool selected (const db::Text &text) const + { + return m_pattern.match (text.string ()) != m_inverse; + } + + /** + * @brief This filter is not sensitive to hierarchy + */ + virtual const TransformationReducer *vars () const + { + return 0; + } + + /** + * @brief Requires merged input + */ + virtual bool requires_raw_input () const + { + return false; + } + + /** + * @brief Wants to build variants + */ + virtual bool wants_variants () const + { + return false; + } + +private: + tl::GlobPattern m_pattern; + bool m_inverse; +}; + +} // namespace db + +#endif diff --git a/src/db/db/gsiDeclDbTexts.cc b/src/db/db/gsiDeclDbTexts.cc new file mode 100644 index 000000000..c701d2a1a --- /dev/null +++ b/src/db/db/gsiDeclDbTexts.cc @@ -0,0 +1,470 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 "gsiDecl.h" + +#include "dbTexts.h" +#include "dbRegion.h" +#include "dbDeepTexts.h" +#include "dbTextsUtils.h" + +namespace gsi +{ + +static db::Texts *new_v () +{ + return new db::Texts (); +} + +static db::Texts *new_a (const std::vector &t) +{ + return new db::Texts (t.begin (), t.end ()); +} + +static db::Texts *new_text (const db::Text &t) +{ + return new db::Texts (t); +} + +static db::Texts *new_shapes (const db::Shapes &s) +{ + db::Texts *r = new db::Texts (); + for (db::Shapes::shape_iterator i = s.begin (db::ShapeIterator::Texts); !i.at_end (); ++i) { + r->insert (*i); + } + return r; +} + +static db::Texts *new_si (const db::RecursiveShapeIterator &si) +{ + return new db::Texts (si); +} + +static db::Texts *new_si2 (const db::RecursiveShapeIterator &si, const db::ICplxTrans &trans) +{ + return new db::Texts (si, trans); +} + +static db::Texts *new_sid (const db::RecursiveShapeIterator &si, db::DeepShapeStore &dss) +{ + return new db::Texts (si, dss); +} + +static db::Texts *new_si2d (const db::RecursiveShapeIterator &si, db::DeepShapeStore &dss, const db::ICplxTrans &trans) +{ + return new db::Texts (si, dss, trans); +} + +static std::string to_string0 (const db::Texts *r) +{ + return r->to_string (); +} + +static std::string to_string1 (const db::Texts *r, size_t n) +{ + return r->to_string (n); +} + +static db::Texts &move_p (db::Texts *r, const db::Vector &p) +{ + r->transform (db::Disp (p)); + return *r; +} + +static db::Texts &move_xy (db::Texts *r, db::Coord x, db::Coord y) +{ + r->transform (db::Disp (db::Vector (x, y))); + return *r; +} + +static db::Texts moved_p (const db::Texts *r, const db::Vector &p) +{ + return r->transformed (db::Disp (p)); +} + +static db::Texts moved_xy (const db::Texts *r, db::Coord x, db::Coord y) +{ + return r->transformed (db::Disp (db::Vector (x, y))); +} + +static db::Region polygons0 (const db::Texts *e, db::Coord d) +{ + db::Region r; + e->polygons (r, d); + return r; +} + +static db::Region extents1 (const db::Texts *r, db::Coord dx, db::Coord dy) +{ + db::Region e; + e.reserve (r->size ()); + for (db::Texts::const_iterator i = r->begin (); ! i.at_end (); ++i) { + e.insert (i->box ().enlarged (db::Vector (dx, dy))); + } + return e; +} + +static db::Region extents0 (const db::Texts *r, db::Coord d) +{ + return extents1 (r, d, d); +} + +static db::Edges edges (const db::Texts *ep) +{ + db::Edges e; + ep->edges (e); + return e; +} + +static void insert_t (db::Texts *t, const db::Texts &a) +{ + for (db::Texts::const_iterator p = a.begin (); ! p.at_end (); ++p) { + t->insert (*p); + } +} + +static bool is_deep (const db::Texts *t) +{ + return dynamic_cast (t->delegate ()) != 0; +} + +static size_t id (const db::Texts *t) +{ + return tl::id_of (t->delegate ()); +} + +static db::Texts with_text (const db::Texts *r, const std::string &text, bool inverse) +{ + db::TextStringFilter f (text, inverse); + return r->filtered (f); +} + +static db::Texts with_pattern (const db::Texts *r, const std::string &pattern, bool inverse) +{ + db::TextPatternFilter f (pattern, inverse); + return r->filtered (f); +} + +Class decl_Texts ("db", "Texts", + constructor ("new", &new_v, + "@brief Default constructor\n" + "\n" + "This constructor creates an empty text collection.\n" + ) + + constructor ("new", &new_a, gsi::arg ("array"), + "@brief Constructor from an text array\n" + "\n" + "This constructor creates an text collection from an array of \\Text objects.\n" + ) + + constructor ("new", &new_text, gsi::arg ("text"), + "@brief Constructor from a single edge pair object\n" + "\n" + "This constructor creates an text collection with a single text.\n" + ) + + constructor ("new", &new_shapes, gsi::arg ("shapes"), + "@brief Shapes constructor\n" + "\n" + "This constructor creates an text collection from a \\Shapes collection.\n" + ) + + constructor ("new", &new_si, gsi::arg ("shape_iterator"), + "@brief Constructor from a hierarchical shape set\n" + "\n" + "This constructor creates a text collection from the shapes delivered by the given recursive shape iterator.\n" + "Only texts are taken from the shape set and other shapes are ignored.\n" + "This method allows feeding the text collection from a hierarchy of cells.\n" + "\n" + "@code\n" + "layout = ... # a layout\n" + "cell = ... # the index of the initial cell\n" + "layer = ... # the index of the layer from where to take the shapes from\n" + "r = RBA::Texts::new(layout.begin_shapes(cell, layer))\n" + "@/code\n" + ) + + constructor ("new", &new_si2, gsi::arg ("shape_iterator"), gsi::arg ("trans"), + "@brief Constructor from a hierarchical shape set with a transformation\n" + "\n" + "This constructor creates a text collection from the shapes delivered by the given recursive shape iterator.\n" + "Only texts are taken from the shape set and other shapes are ignored.\n" + "The given transformation is applied to each text taken.\n" + "This method allows feeding the text collection from a hierarchy of cells.\n" + "The transformation is useful to scale to a specific database unit for example.\n" + "\n" + "@code\n" + "layout = ... # a layout\n" + "cell = ... # the index of the initial cell\n" + "layer = ... # the index of the layer from where to take the shapes from\n" + "dbu = 0.1 # the target database unit\n" + "r = RBA::Texts::new(layout.begin_shapes(cell, layer), RBA::ICplxTrans::new(layout.dbu / dbu))\n" + "@/code\n" + ) + + constructor ("new", &new_sid, gsi::arg ("shape_iterator"), gsi::arg ("dss"), + "@brief Creates a hierarchical text collection from an original layer\n" + "\n" + "This constructor creates a text collection from the shapes delivered by the given recursive shape iterator.\n" + "This version will create a hierarchical text collection which supports hierarchical operations.\n" + "\n" + "@code\n" + "dss = RBA::DeepShapeStore::new\n" + "layout = ... # a layout\n" + "cell = ... # the index of the initial cell\n" + "layer = ... # the index of the layer from where to take the shapes from\n" + "r = RBA::Texts::new(layout.begin_shapes(cell, layer))\n" + "@/code\n" + ) + + constructor ("new", &new_si2d, gsi::arg ("shape_iterator"), gsi::arg ("dss"), gsi::arg ("trans"), + "@brief Creates a hierarchical text collection from an original layer with a transformation\n" + "\n" + "This constructor creates a text collection from the shapes delivered by the given recursive shape iterator.\n" + "This version will create a hierarchical text collection which supports hierarchical operations.\n" + "The transformation is useful to scale to a specific database unit for example.\n" + "\n" + "@code\n" + "dss = RBA::DeepShapeStore::new\n" + "layout = ... # a layout\n" + "cell = ... # the index of the initial cell\n" + "layer = ... # the index of the layer from where to take the shapes from\n" + "dbu = 0.1 # the target database unit\n" + "r = RBA::Texts::new(layout.begin_shapes(cell, layer), RBA::ICplxTrans::new(layout.dbu / dbu))\n" + "@/code\n" + ) + + method ("insert_into", &db::Texts::insert_into, gsi::arg ("layout"), gsi::arg ("cell_index"), gsi::arg ("layer"), + "@brief Inserts this texts into the given layout, below the given cell and into the given layer.\n" + "If the text collection is a hierarchical one, a suitable hierarchy will be built below the top cell or " + "and existing hierarchy will be reused.\n" + ) + + method ("insert_into_as_polygons", &db::Texts::insert_into_as_polygons, gsi::arg ("layout"), gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("e"), + "@brief Inserts this texts into the given layout, below the given cell and into the given layer.\n" + "If the text collection is a hierarchical one, a suitable hierarchy will be built below the top cell or " + "and existing hierarchy will be reused.\n" + "\n" + "The texts will be converted to polygons with the enlargement value given be 'e'. See \\polygon or \\extents for details.\n" + ) + + method ("insert", (void (db::Texts::*) (const db::Text &)) &db::Texts::insert, gsi::arg ("text"), + "@brief Inserts a text into the collection\n" + ) + + method_ext ("is_deep?", &is_deep, + "@brief Returns true if the edge pair collection is a deep (hierarchical) one\n" + ) + + method_ext ("data_id", &id, + "@brief Returns the data ID (a unique identifier for the underlying data storage)\n" + ) + + method ("+", &db::Texts::operator+, gsi::arg ("other"), + "@brief Returns the combined text collection of self and the other one\n" + "\n" + "@return The resulting text collection\n" + "\n" + "This operator adds the texts of the other collection to self and returns a new combined set.\n" + ) + + method ("+=", &db::Texts::operator+=, gsi::arg ("other"), + "@brief Adds the texts of the other text collection to self\n" + "\n" + "@return The text collection after modification (self)\n" + "\n" + "This operator adds the texts of the other collection to self.\n" + ) + + method_ext ("move", &move_p, gsi::arg ("p"), + "@brief Moves the text collection\n" + "\n" + "Moves the texts by the given offset and returns the \n" + "moved text collection. The text collection is overwritten.\n" + "\n" + "@param p The distance to move the texts.\n" + "\n" + "@return The moved texts (self).\n" + ) + + method_ext ("move", &move_xy, gsi::arg ("x"), gsi::arg ("y"), + "@brief Moves the text collection\n" + "\n" + "Moves the edge pairs by the given offset and returns the \n" + "moved texts. The edge pair collection is overwritten.\n" + "\n" + "@param x The x distance to move the texts.\n" + "@param y The y distance to move the texts.\n" + "\n" + "@return The moved texts (self).\n" + ) + + method_ext ("moved", &moved_p, gsi::arg ("p"), + "@brief Returns the moved text collection (does not modify self)\n" + "\n" + "Moves the texts by the given offset and returns the \n" + "moved texts. The text collection is not modified.\n" + "\n" + "@param p The distance to move the texts.\n" + "\n" + "@return The moved texts.\n" + ) + + method_ext ("moved", &moved_xy, gsi::arg ("x"), gsi::arg ("y"), + "@brief Returns the moved edge pair collection (does not modify self)\n" + "\n" + "Moves the texts by the given offset and returns the \n" + "moved texts. The text collection is not modified.\n" + "\n" + "@param x The x distance to move the texts.\n" + "@param y The y distance to move the texts.\n" + "\n" + "@return The moved texts.\n" + ) + + method ("transformed", (db::Texts (db::Texts::*)(const db::Trans &) const) &db::Texts::transformed, gsi::arg ("t"), + "@brief Transform the edge pair collection\n" + "\n" + "Transforms the texts with the given transformation.\n" + "Does not modify the edge pair collection but returns the transformed texts.\n" + "\n" + "@param t The transformation to apply.\n" + "\n" + "@return The transformed texts.\n" + ) + + method ("transformed|#transformed_icplx", (db::Texts (db::Texts::*)(const db::ICplxTrans &) const) &db::Texts::transformed, gsi::arg ("t"), + "@brief Transform the text collection with a complex transformation\n" + "\n" + "Transforms the text with the given complex transformation.\n" + "Does not modify the text collection but returns the transformed texts.\n" + "\n" + "@param t The transformation to apply.\n" + "\n" + "@return The transformed texts.\n" + ) + + method ("transform", (db::Texts &(db::Texts::*)(const db::Trans &)) &db::Texts::transform, gsi::arg ("t"), + "@brief Transform the text collection (modifies self)\n" + "\n" + "Transforms the text collection with the given transformation.\n" + "This version modifies the text collection and returns a reference to self.\n" + "\n" + "@param t The transformation to apply.\n" + "\n" + "@return The transformed text collection.\n" + ) + + method ("transform|#transform_icplx", (db::Texts &(db::Texts::*)(const db::ICplxTrans &)) &db::Texts::transform, gsi::arg ("t"), + "@brief Transform the text collection with a complex transformation (modifies self)\n" + "\n" + "Transforms the text collection with the given transformation.\n" + "This version modifies the text collection and returns a reference to self.\n" + "\n" + "@param t The transformation to apply.\n" + "\n" + "@return The transformed text collection.\n" + ) + + method_ext ("insert", &insert_t, gsi::arg ("texts"), + "@brief Inserts all texts from the other text collection into this collection\n" + ) + + method_ext ("edges", &edges, + "@brief Returns dot-like edges for the texts\n" + "@return An edge collection containing the individual, dot-like edges\n" + ) + + method_ext ("extents", &extents0, gsi::arg ("d", db::Coord (1)), + "@brief Returns a region with the enlarged bounding boxes of the texts\n" + "Text bounding boxes are point-like boxes which vanish unless an enlargement of >0 is specified.\n" + "The bounding box is centered at the text's location.\n" + "The boxes will not be merged, so it is possible to determine overlaps " + "of these boxes for example.\n" + ) + + method_ext ("extents", &extents1, gsi::arg ("dx"), gsi::arg ("dy"), + "@brief Returns a region with the enlarged bounding boxes of the texts\n" + "This method acts like the other version of \\extents, but allows giving different enlargements for x and y direction.\n" + ) + + method_ext ("polygons", &polygons0, gsi::arg ("e", db::Coord (1)), + "@brief Converts the edge pairs to polygons\n" + "This method creates polygons from the texts. This is equivalent to calling \\extents." + ) + + method_ext ("with_text", with_text, gsi::arg ("text"), gsi::arg ("inverse"), + "@brief Filter the text by text string\n" + "If \"inverse\" is false, this method returns the texts with the given string.\n" + "If \"inverse\" is true, this method returns the texts not having the given string.\n" + ) + + method_ext ("with_match", with_pattern, gsi::arg ("pattern"), gsi::arg ("inverse"), + "@brief Filter the text by glob pattern\n" + "\"pattern\" is a glob-style pattern (e.g. \"A*\" will select all texts starting with a capital \"A\").\n" + "If \"inverse\" is false, this method returns the texts matching the pattern.\n" + "If \"inverse\" is true, this method returns the texts not matching the pattern.\n" + ) + + method ("clear", &db::Texts::clear, + "@brief Clears the text collection\n" + ) + + method ("swap", &db::Texts::swap, gsi::arg ("other"), + "@brief Swap the contents of this collection with the contents of another collection\n" + "This method is useful to avoid excessive memory allocation in some cases. " + "For managed memory languages such as Ruby, those cases will be rare. " + ) + + method ("bbox", &db::Texts::bbox, + "@brief Return the bounding box of the text collection\n" + "The bounding box is the box enclosing all origins of all texts.\n" + ) + + method ("is_empty?", &db::Texts::empty, + "@brief Returns true if the collection is empty\n" + ) + + method ("size", &db::Texts::size, + "@brief Returns the number of texts in this collection\n" + ) + + gsi::iterator ("each", &db::Texts::begin, + "@brief Returns each text of the text collection\n" + ) + + method ("[]", &db::Texts::nth, gsi::arg ("n"), + "@brief Returns the nth text\n" + "\n" + "This method returns nil if the index is out of range. It is available for flat texts only - i.e. " + "those for which \\has_valid_texts? is true. Use \\flatten to explicitly flatten an text collection.\n" + "\n" + "The \\each iterator is the more general approach to access the texts." + ) + + method ("flatten", &db::Texts::flatten, + "@brief Explicitly flattens an text collection\n" + "\n" + "If the collection is already flat (i.e. \\has_valid_texts? returns true), this method will " + "not change the collection.\n" + ) + + method ("has_valid_texts?", &db::Texts::has_valid_texts, + "@brief Returns true if the text collection is flat and individual texts can be accessed randomly\n" + ) + + method ("enable_progress", &db::Texts::enable_progress, gsi::arg ("label"), + "@brief Enable progress reporting\n" + "After calling this method, the text collection will report the progress through a progress bar while " + "expensive operations are running.\n" + "The label is a text which is put in front of the progress bar.\n" + "Using a progress bar will imply a performance penalty of a few percent typically.\n" + ) + + method ("disable_progress", &db::Texts::disable_progress, + "@brief Disable progress reporting\n" + "Calling this method will disable progress reporting. See \\enable_progress.\n" + ) + + method_ext ("to_s", &to_string0, + "@brief Converts the text collection to a string\n" + "The length of the output is limited to 20 edge pairs to avoid giant strings on large collections. " + "For full output use \"to_s\" with a maximum count parameter.\n" + ) + + method_ext ("to_s", &to_string1, gsi::arg ("max_count"), + "@brief Converts the text collection to a string\n" + "This version allows specification of the maximum number of texts contained in the string." + ), + "@brief Texts (a collection of texts)\n" + "\n" + "Text objects are useful as labels for net names, to identify certain regions and to specify specific locations in general. " + "Text collections provide a way to store - also in a hierarchical fashion - and manipulate collection of text objects. " + "Text objects can be turned into polygons by creating small boxes around the texts. Texts can also be turned into dot-like " + "edges. Texts can be filtered by string, either by matching against a fixed string or a glob-style pattern.\n" + "\n" + "Beside that, text collections can be transformed and combined, similar to \\EdgePairs.\n" + "\n" + "This class has been introduced in version 0.27.\n" +); + +} From 8b083a833007b7f34aac78f62616bd6401513a4b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 12 May 2020 21:09:21 +0200 Subject: [PATCH 02/35] Added unit tests for db::Texts, renamed db unit test files so debugging is possible --- .../{dbArray.cc => dbArrayTests.cc} | 0 .../{dbBoxScanner.cc => dbBoxScannerTests.cc} | 0 src/db/unit_tests/{dbBox.cc => dbBoxTests.cc} | 0 .../{dbBoxTree.cc => dbBoxTreeTests.cc} | 0 ...GraphUtils.cc => dbCellGraphUtilsTests.cc} | 0 ...nerator.cc => dbCellHullGeneratorTests.cc} | 0 ...dbCellMapping.cc => dbCellMappingTests.cc} | 0 .../unit_tests/{dbCell.cc => dbCellTests.cc} | 0 .../unit_tests/{dbClip.cc => dbClipTests.cc} | 0 ...lations.cc => dbEdgePairRelationsTests.cc} | 0 .../{dbEdgePair.cc => dbEdgePairTests.cc} | 0 .../{dbEdgePairs.cc => dbEdgePairsTests.cc} | 0 ...geProcessor.cc => dbEdgeProcessorTests.cc} | 0 .../unit_tests/{dbEdge.cc => dbEdgeTests.cc} | 0 .../{dbEdges.cc => dbEdgesTests.cc} | 0 ...oContours.cc => dbEdgesToContoursTests.cc} | 0 .../{dbExpression.cc => dbExpressionTests.cc} | 0 ...LayerMapping.cc => dbLayerMappingTests.cc} | 0 .../{dbLayer.cc => dbLayerTests.cc} | 0 .../{dbLayoutDiff.cc => dbLayoutDiffTests.cc} | 0 .../{dbLayout.cc => dbLayoutTests.cc} | 0 ...dbLayoutUtils.cc => dbLayoutUtilsTests.cc} | 0 .../{dbLibraries.cc => dbLibrariesTests.cc} | 0 .../{dbMatrix.cc => dbMatrixTests.cc} | 0 .../{dbObject.cc => dbObjectTests.cc} | 0 .../{dbPCells.cc => dbPCellsTests.cc} | 0 .../unit_tests/{dbPath.cc => dbPathTests.cc} | 0 .../{dbPoint.cc => dbPointTests.cc} | 0 .../{dbPolygon.cc => dbPolygonTests.cc} | 0 ...tory.cc => dbPropertiesRepositoryTests.cc} | 0 .../{dbRegion.cc => dbRegionTests.cc} | 0 .../{dbShapeArray.cc => dbShapeArrayTests.cc} | 0 ...epository.cc => dbShapeRepositoryTests.cc} | 0 .../{dbShape.cc => dbShapeTests.cc} | 0 .../{dbShapes.cc => dbShapesTests.cc} | 0 .../unit_tests/{dbText.cc => dbTextTests.cc} | 0 src/db/unit_tests/dbTextsTests.cc | 175 ++++++++++++++++++ ...Processor.cc => dbTilingProcessorTests.cc} | 0 .../{dbTrans.cc => dbTransTests.cc} | 0 ...dthPath.cc => dbVariableWidthPathTests.cc} | 0 .../{dbVector.cc => dbVectorTests.cc} | 0 src/db/unit_tests/unit_tests.pro | 83 +++++---- 42 files changed, 217 insertions(+), 41 deletions(-) rename src/db/unit_tests/{dbArray.cc => dbArrayTests.cc} (100%) rename src/db/unit_tests/{dbBoxScanner.cc => dbBoxScannerTests.cc} (100%) rename src/db/unit_tests/{dbBox.cc => dbBoxTests.cc} (100%) rename src/db/unit_tests/{dbBoxTree.cc => dbBoxTreeTests.cc} (100%) rename src/db/unit_tests/{dbCellGraphUtils.cc => dbCellGraphUtilsTests.cc} (100%) rename src/db/unit_tests/{dbCellHullGenerator.cc => dbCellHullGeneratorTests.cc} (100%) rename src/db/unit_tests/{dbCellMapping.cc => dbCellMappingTests.cc} (100%) rename src/db/unit_tests/{dbCell.cc => dbCellTests.cc} (100%) rename src/db/unit_tests/{dbClip.cc => dbClipTests.cc} (100%) rename src/db/unit_tests/{dbEdgePairRelations.cc => dbEdgePairRelationsTests.cc} (100%) rename src/db/unit_tests/{dbEdgePair.cc => dbEdgePairTests.cc} (100%) rename src/db/unit_tests/{dbEdgePairs.cc => dbEdgePairsTests.cc} (100%) rename src/db/unit_tests/{dbEdgeProcessor.cc => dbEdgeProcessorTests.cc} (100%) rename src/db/unit_tests/{dbEdge.cc => dbEdgeTests.cc} (100%) rename src/db/unit_tests/{dbEdges.cc => dbEdgesTests.cc} (100%) rename src/db/unit_tests/{dbEdgesToContours.cc => dbEdgesToContoursTests.cc} (100%) rename src/db/unit_tests/{dbExpression.cc => dbExpressionTests.cc} (100%) rename src/db/unit_tests/{dbLayerMapping.cc => dbLayerMappingTests.cc} (100%) rename src/db/unit_tests/{dbLayer.cc => dbLayerTests.cc} (100%) rename src/db/unit_tests/{dbLayoutDiff.cc => dbLayoutDiffTests.cc} (100%) rename src/db/unit_tests/{dbLayout.cc => dbLayoutTests.cc} (100%) rename src/db/unit_tests/{dbLayoutUtils.cc => dbLayoutUtilsTests.cc} (100%) rename src/db/unit_tests/{dbLibraries.cc => dbLibrariesTests.cc} (100%) rename src/db/unit_tests/{dbMatrix.cc => dbMatrixTests.cc} (100%) rename src/db/unit_tests/{dbObject.cc => dbObjectTests.cc} (100%) rename src/db/unit_tests/{dbPCells.cc => dbPCellsTests.cc} (100%) rename src/db/unit_tests/{dbPath.cc => dbPathTests.cc} (100%) rename src/db/unit_tests/{dbPoint.cc => dbPointTests.cc} (100%) rename src/db/unit_tests/{dbPolygon.cc => dbPolygonTests.cc} (100%) rename src/db/unit_tests/{dbPropertiesRepository.cc => dbPropertiesRepositoryTests.cc} (100%) rename src/db/unit_tests/{dbRegion.cc => dbRegionTests.cc} (100%) rename src/db/unit_tests/{dbShapeArray.cc => dbShapeArrayTests.cc} (100%) rename src/db/unit_tests/{dbShapeRepository.cc => dbShapeRepositoryTests.cc} (100%) rename src/db/unit_tests/{dbShape.cc => dbShapeTests.cc} (100%) rename src/db/unit_tests/{dbShapes.cc => dbShapesTests.cc} (100%) rename src/db/unit_tests/{dbText.cc => dbTextTests.cc} (100%) create mode 100644 src/db/unit_tests/dbTextsTests.cc rename src/db/unit_tests/{dbTilingProcessor.cc => dbTilingProcessorTests.cc} (100%) rename src/db/unit_tests/{dbTrans.cc => dbTransTests.cc} (100%) rename src/db/unit_tests/{dbVariableWidthPath.cc => dbVariableWidthPathTests.cc} (100%) rename src/db/unit_tests/{dbVector.cc => dbVectorTests.cc} (100%) diff --git a/src/db/unit_tests/dbArray.cc b/src/db/unit_tests/dbArrayTests.cc similarity index 100% rename from src/db/unit_tests/dbArray.cc rename to src/db/unit_tests/dbArrayTests.cc diff --git a/src/db/unit_tests/dbBoxScanner.cc b/src/db/unit_tests/dbBoxScannerTests.cc similarity index 100% rename from src/db/unit_tests/dbBoxScanner.cc rename to src/db/unit_tests/dbBoxScannerTests.cc diff --git a/src/db/unit_tests/dbBox.cc b/src/db/unit_tests/dbBoxTests.cc similarity index 100% rename from src/db/unit_tests/dbBox.cc rename to src/db/unit_tests/dbBoxTests.cc diff --git a/src/db/unit_tests/dbBoxTree.cc b/src/db/unit_tests/dbBoxTreeTests.cc similarity index 100% rename from src/db/unit_tests/dbBoxTree.cc rename to src/db/unit_tests/dbBoxTreeTests.cc diff --git a/src/db/unit_tests/dbCellGraphUtils.cc b/src/db/unit_tests/dbCellGraphUtilsTests.cc similarity index 100% rename from src/db/unit_tests/dbCellGraphUtils.cc rename to src/db/unit_tests/dbCellGraphUtilsTests.cc diff --git a/src/db/unit_tests/dbCellHullGenerator.cc b/src/db/unit_tests/dbCellHullGeneratorTests.cc similarity index 100% rename from src/db/unit_tests/dbCellHullGenerator.cc rename to src/db/unit_tests/dbCellHullGeneratorTests.cc diff --git a/src/db/unit_tests/dbCellMapping.cc b/src/db/unit_tests/dbCellMappingTests.cc similarity index 100% rename from src/db/unit_tests/dbCellMapping.cc rename to src/db/unit_tests/dbCellMappingTests.cc diff --git a/src/db/unit_tests/dbCell.cc b/src/db/unit_tests/dbCellTests.cc similarity index 100% rename from src/db/unit_tests/dbCell.cc rename to src/db/unit_tests/dbCellTests.cc diff --git a/src/db/unit_tests/dbClip.cc b/src/db/unit_tests/dbClipTests.cc similarity index 100% rename from src/db/unit_tests/dbClip.cc rename to src/db/unit_tests/dbClipTests.cc diff --git a/src/db/unit_tests/dbEdgePairRelations.cc b/src/db/unit_tests/dbEdgePairRelationsTests.cc similarity index 100% rename from src/db/unit_tests/dbEdgePairRelations.cc rename to src/db/unit_tests/dbEdgePairRelationsTests.cc diff --git a/src/db/unit_tests/dbEdgePair.cc b/src/db/unit_tests/dbEdgePairTests.cc similarity index 100% rename from src/db/unit_tests/dbEdgePair.cc rename to src/db/unit_tests/dbEdgePairTests.cc diff --git a/src/db/unit_tests/dbEdgePairs.cc b/src/db/unit_tests/dbEdgePairsTests.cc similarity index 100% rename from src/db/unit_tests/dbEdgePairs.cc rename to src/db/unit_tests/dbEdgePairsTests.cc diff --git a/src/db/unit_tests/dbEdgeProcessor.cc b/src/db/unit_tests/dbEdgeProcessorTests.cc similarity index 100% rename from src/db/unit_tests/dbEdgeProcessor.cc rename to src/db/unit_tests/dbEdgeProcessorTests.cc diff --git a/src/db/unit_tests/dbEdge.cc b/src/db/unit_tests/dbEdgeTests.cc similarity index 100% rename from src/db/unit_tests/dbEdge.cc rename to src/db/unit_tests/dbEdgeTests.cc diff --git a/src/db/unit_tests/dbEdges.cc b/src/db/unit_tests/dbEdgesTests.cc similarity index 100% rename from src/db/unit_tests/dbEdges.cc rename to src/db/unit_tests/dbEdgesTests.cc diff --git a/src/db/unit_tests/dbEdgesToContours.cc b/src/db/unit_tests/dbEdgesToContoursTests.cc similarity index 100% rename from src/db/unit_tests/dbEdgesToContours.cc rename to src/db/unit_tests/dbEdgesToContoursTests.cc diff --git a/src/db/unit_tests/dbExpression.cc b/src/db/unit_tests/dbExpressionTests.cc similarity index 100% rename from src/db/unit_tests/dbExpression.cc rename to src/db/unit_tests/dbExpressionTests.cc diff --git a/src/db/unit_tests/dbLayerMapping.cc b/src/db/unit_tests/dbLayerMappingTests.cc similarity index 100% rename from src/db/unit_tests/dbLayerMapping.cc rename to src/db/unit_tests/dbLayerMappingTests.cc diff --git a/src/db/unit_tests/dbLayer.cc b/src/db/unit_tests/dbLayerTests.cc similarity index 100% rename from src/db/unit_tests/dbLayer.cc rename to src/db/unit_tests/dbLayerTests.cc diff --git a/src/db/unit_tests/dbLayoutDiff.cc b/src/db/unit_tests/dbLayoutDiffTests.cc similarity index 100% rename from src/db/unit_tests/dbLayoutDiff.cc rename to src/db/unit_tests/dbLayoutDiffTests.cc diff --git a/src/db/unit_tests/dbLayout.cc b/src/db/unit_tests/dbLayoutTests.cc similarity index 100% rename from src/db/unit_tests/dbLayout.cc rename to src/db/unit_tests/dbLayoutTests.cc diff --git a/src/db/unit_tests/dbLayoutUtils.cc b/src/db/unit_tests/dbLayoutUtilsTests.cc similarity index 100% rename from src/db/unit_tests/dbLayoutUtils.cc rename to src/db/unit_tests/dbLayoutUtilsTests.cc diff --git a/src/db/unit_tests/dbLibraries.cc b/src/db/unit_tests/dbLibrariesTests.cc similarity index 100% rename from src/db/unit_tests/dbLibraries.cc rename to src/db/unit_tests/dbLibrariesTests.cc diff --git a/src/db/unit_tests/dbMatrix.cc b/src/db/unit_tests/dbMatrixTests.cc similarity index 100% rename from src/db/unit_tests/dbMatrix.cc rename to src/db/unit_tests/dbMatrixTests.cc diff --git a/src/db/unit_tests/dbObject.cc b/src/db/unit_tests/dbObjectTests.cc similarity index 100% rename from src/db/unit_tests/dbObject.cc rename to src/db/unit_tests/dbObjectTests.cc diff --git a/src/db/unit_tests/dbPCells.cc b/src/db/unit_tests/dbPCellsTests.cc similarity index 100% rename from src/db/unit_tests/dbPCells.cc rename to src/db/unit_tests/dbPCellsTests.cc diff --git a/src/db/unit_tests/dbPath.cc b/src/db/unit_tests/dbPathTests.cc similarity index 100% rename from src/db/unit_tests/dbPath.cc rename to src/db/unit_tests/dbPathTests.cc diff --git a/src/db/unit_tests/dbPoint.cc b/src/db/unit_tests/dbPointTests.cc similarity index 100% rename from src/db/unit_tests/dbPoint.cc rename to src/db/unit_tests/dbPointTests.cc diff --git a/src/db/unit_tests/dbPolygon.cc b/src/db/unit_tests/dbPolygonTests.cc similarity index 100% rename from src/db/unit_tests/dbPolygon.cc rename to src/db/unit_tests/dbPolygonTests.cc diff --git a/src/db/unit_tests/dbPropertiesRepository.cc b/src/db/unit_tests/dbPropertiesRepositoryTests.cc similarity index 100% rename from src/db/unit_tests/dbPropertiesRepository.cc rename to src/db/unit_tests/dbPropertiesRepositoryTests.cc diff --git a/src/db/unit_tests/dbRegion.cc b/src/db/unit_tests/dbRegionTests.cc similarity index 100% rename from src/db/unit_tests/dbRegion.cc rename to src/db/unit_tests/dbRegionTests.cc diff --git a/src/db/unit_tests/dbShapeArray.cc b/src/db/unit_tests/dbShapeArrayTests.cc similarity index 100% rename from src/db/unit_tests/dbShapeArray.cc rename to src/db/unit_tests/dbShapeArrayTests.cc diff --git a/src/db/unit_tests/dbShapeRepository.cc b/src/db/unit_tests/dbShapeRepositoryTests.cc similarity index 100% rename from src/db/unit_tests/dbShapeRepository.cc rename to src/db/unit_tests/dbShapeRepositoryTests.cc diff --git a/src/db/unit_tests/dbShape.cc b/src/db/unit_tests/dbShapeTests.cc similarity index 100% rename from src/db/unit_tests/dbShape.cc rename to src/db/unit_tests/dbShapeTests.cc diff --git a/src/db/unit_tests/dbShapes.cc b/src/db/unit_tests/dbShapesTests.cc similarity index 100% rename from src/db/unit_tests/dbShapes.cc rename to src/db/unit_tests/dbShapesTests.cc diff --git a/src/db/unit_tests/dbText.cc b/src/db/unit_tests/dbTextTests.cc similarity index 100% rename from src/db/unit_tests/dbText.cc rename to src/db/unit_tests/dbTextTests.cc diff --git a/src/db/unit_tests/dbTextsTests.cc b/src/db/unit_tests/dbTextsTests.cc new file mode 100644 index 000000000..df5ce9c2c --- /dev/null +++ b/src/db/unit_tests/dbTextsTests.cc @@ -0,0 +1,175 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 "tlUnitTest.h" + +#include "dbTexts.h" +#include "dbTextsUtils.h" +#include "dbEdges.h" +#include "dbRegion.h" + +TEST(1) +{ + db::Texts texts; + EXPECT_EQ (texts.empty (), true); + EXPECT_EQ (texts.bbox ().to_string (), "()"); + EXPECT_EQ (texts == db::Texts (), true); + EXPECT_EQ (texts < db::Texts (), false); + EXPECT_EQ (texts != db::Texts (), false); + texts.insert (db::Text ("abc", db::Trans (db::Vector (100, -200)))); + EXPECT_EQ (texts.empty (), false); + EXPECT_EQ (texts.size (), size_t (1)); + EXPECT_EQ (texts.bbox ().to_string (), "(100,-200;100,-200)"); + EXPECT_EQ (texts.to_string (), "('abc',r0 100,-200)"); + + texts.clear (); + EXPECT_EQ (texts.empty (), true); + EXPECT_EQ (texts.size (), size_t (0)); + EXPECT_EQ (texts.bbox ().to_string (), "()"); + texts.insert (db::Text ("uvw", db::Trans (db::Vector (110, 210)))); + EXPECT_EQ (texts == db::Texts (), false); + EXPECT_EQ (texts < db::Texts (), true); + EXPECT_EQ (texts != db::Texts (), true); + EXPECT_EQ (texts != texts, false); + EXPECT_EQ (texts == texts, true); + EXPECT_EQ (texts < texts, false); + EXPECT_EQ (texts.empty (), false); + EXPECT_EQ (texts.bbox ().to_string (), "(110,210;110,210)"); + EXPECT_EQ (texts.to_string (), "('uvw',r0 110,210)"); + + EXPECT_EQ (texts.transformed (db::ICplxTrans (2.0, 0.0, false, db::Vector ())).to_string (), "('uvw',r0 220,420)"); + EXPECT_EQ (texts.to_string (), "('uvw',r0 110,210)"); + texts.transform (db::ICplxTrans (3)); + EXPECT_EQ (texts.empty (), false); + EXPECT_EQ (texts.bbox ().to_string (), "(210,-110;210,-110)"); + EXPECT_EQ (texts.to_string (), "('uvw',r270 210,-110)"); + + db::Texts texts2; + EXPECT_EQ (texts2.empty (), true); + EXPECT_EQ (texts2.size (), size_t (0)); + EXPECT_EQ (texts2.bbox ().to_string (), "()"); + texts2.swap (texts); + EXPECT_EQ (texts.empty (), true); + EXPECT_EQ (texts.size (), size_t (0)); + EXPECT_EQ (texts.bbox ().to_string (), "()"); + EXPECT_EQ (texts2.empty (), false); + EXPECT_EQ (texts2.size (), size_t (1)); + EXPECT_EQ (texts2.bbox ().to_string (), "(210,-110;210,-110)"); +} + +TEST(2) +{ + db::Texts texts; + texts.insert (db::Text ("abc", db::Trans (db::Vector (100, -200)))); + texts.insert (db::Text ("uvw", db::Trans (db::Vector (110, 210)))); + + EXPECT_EQ (texts.to_string (), "('abc',r0 100,-200);('uvw',r0 110,210)"); + + db::Texts ee; + std::string s = texts.to_string (); + tl::Extractor ex (s.c_str ()); + EXPECT_EQ (ex.try_read (ee), true); + EXPECT_EQ (ee.to_string (), "('abc',r0 100,-200);('uvw',r0 110,210)"); + + db::Edges e; + texts.edges (e); + EXPECT_EQ (e.to_string (), "(100,-200;100,-200);(110,210;110,210)"); + + db::Region r; + texts.polygons (r); + EXPECT_EQ (r.to_string (), "(99,-201;99,-199;101,-199;101,-201);(109,209;109,211;111,211;111,209)"); +} + +TEST(3) +{ + db::Texts texts; + texts.insert (db::Text ("abc", db::Trans (db::Vector (100, -200)))); + texts.insert (db::Text ("uvw", db::Trans (db::Vector (110, 210)))); + + db::Texts tcopy = texts; + + db::TextStringFilter f ("abc", false); + EXPECT_EQ (texts.filtered (f).to_string (), "('abc',r0 100,-200)"); + texts.filter (f); + EXPECT_EQ (texts.to_string (), "('abc',r0 100,-200)"); + + texts = tcopy; + + db::TextStringFilter fi ("abc", true); + EXPECT_EQ (texts.filtered (fi).to_string (), "('uvw',r0 110,210)"); + texts.filter (fi); + EXPECT_EQ (texts.to_string (), "('uvw',r0 110,210)"); +} + +TEST(4) +{ + db::Texts texts; + texts.insert (db::Text ("abc", db::Trans (db::Vector (100, -200)))); + texts.insert (db::Text ("uvw", db::Trans (db::Vector (110, 210)))); + + db::Texts tcopy = texts; + + db::TextPatternFilter f ("*v*", false); + EXPECT_EQ (texts.filtered (f).to_string (), "('uvw',r0 110,210)"); + texts.filter (f); + EXPECT_EQ (texts.to_string (), "('uvw',r0 110,210)"); + + texts = tcopy; + + db::TextPatternFilter fi ("*v*", true); + EXPECT_EQ (texts.filtered (fi).to_string (), "('abc',r0 100,-200)"); + texts.filter (fi); + EXPECT_EQ (texts.to_string (), "('abc',r0 100,-200)"); +} + +TEST(5) +{ + db::Texts texts; + texts.insert (db::Text ("abc", db::Trans (db::Vector (100, -200)))); + texts.insert (db::Text ("uvw", db::Trans (db::Vector (110, 210)))); + + db::Layout ly; + unsigned int l1 = ly.insert_layer (db::LayerProperties (1, 0)); + db::cell_index_type top_cell = ly.add_cell ("TOP"); + + texts.insert_into_as_polygons (&ly, top_cell, l1, 1); + + db::Region r (db::RecursiveShapeIterator (ly, ly.cell (top_cell), l1)); + EXPECT_EQ (r.to_string (), "(99,-201;99,-199;101,-199;101,-201);(109,209;109,211;111,211;111,209)"); +} + +TEST(6) +{ + db::Texts texts; + texts.insert (db::Text ("abc", db::Trans (db::Vector (100, -200)))); + texts.insert (db::Text ("uvw", db::Trans (db::Vector (110, 210)))); + + db::Layout ly; + unsigned int l1 = ly.insert_layer (db::LayerProperties (1, 0)); + db::cell_index_type top_cell = ly.add_cell ("TOP"); + + texts.insert_into (&ly, top_cell, l1); + + db::Region r (db::RecursiveShapeIterator (ly, ly.cell (top_cell), l1)); + EXPECT_EQ (r.to_string (), "(-10,-21;9,20;50,51;91,80);(-10,-21;9,20;110,121;91,80)"); +} diff --git a/src/db/unit_tests/dbTilingProcessor.cc b/src/db/unit_tests/dbTilingProcessorTests.cc similarity index 100% rename from src/db/unit_tests/dbTilingProcessor.cc rename to src/db/unit_tests/dbTilingProcessorTests.cc diff --git a/src/db/unit_tests/dbTrans.cc b/src/db/unit_tests/dbTransTests.cc similarity index 100% rename from src/db/unit_tests/dbTrans.cc rename to src/db/unit_tests/dbTransTests.cc diff --git a/src/db/unit_tests/dbVariableWidthPath.cc b/src/db/unit_tests/dbVariableWidthPathTests.cc similarity index 100% rename from src/db/unit_tests/dbVariableWidthPath.cc rename to src/db/unit_tests/dbVariableWidthPathTests.cc diff --git a/src/db/unit_tests/dbVector.cc b/src/db/unit_tests/dbVectorTests.cc similarity index 100% rename from src/db/unit_tests/dbVector.cc rename to src/db/unit_tests/dbVectorTests.cc diff --git a/src/db/unit_tests/unit_tests.pro b/src/db/unit_tests/unit_tests.pro index 5aa37d85e..20e692741 100644 --- a/src/db/unit_tests/unit_tests.pro +++ b/src/db/unit_tests/unit_tests.pro @@ -7,47 +7,7 @@ TARGET = db_tests include($$PWD/../../lib_ut.pri) SOURCES = \ - dbArray.cc \ - dbBox.cc \ - dbBoxScanner.cc \ - dbBoxTree.cc \ - dbCell.cc \ - dbCellGraphUtils.cc \ - dbCellHullGenerator.cc \ - dbCellMapping.cc \ - dbClip.cc \ - dbExpression.cc \ - dbEdge.cc \ - dbEdgePair.cc \ - dbEdgePairRelations.cc \ - dbEdgePairs.cc \ - dbEdgeProcessor.cc \ - dbEdges.cc \ - dbEdgesToContours.cc \ - dbLayer.cc \ - dbLayerMapping.cc \ - dbLayout.cc \ - dbLayoutDiff.cc \ - dbLayoutUtils.cc \ - dbLibraries.cc \ - dbMatrix.cc \ - dbObject.cc \ - dbPath.cc \ - dbPCells.cc \ - dbPoint.cc \ - dbPolygon.cc \ - dbPropertiesRepository.cc \ - dbRegion.cc \ - dbShapeArray.cc \ - dbShape.cc \ - dbShapeRepository.cc \ - dbShapes.cc \ - dbText.cc \ - dbTilingProcessor.cc \ - dbTrans.cc \ - dbVector.cc \ dbWriterTools.cc \ - dbVariableWidthPath.cc \ dbLoadLayoutOptionsTests.cc \ dbSaveLayoutOptionsTests.cc \ dbHierarchyBuilderTests.cc \ @@ -73,7 +33,48 @@ SOURCES = \ dbLayoutQueryTests.cc \ dbPolygonToolsTests.cc \ dbTechnologyTests.cc \ - dbStreamLayerTests.cc + dbStreamLayerTests.cc \ + dbVectorTests.cc \ + dbVariableWidthPathTests.cc \ + dbTransTests.cc \ + dbTilingProcessorTests.cc \ + dbTextsTests.cc \ + dbTextTests.cc \ + dbShapesTests.cc \ + dbShapeRepositoryTests.cc \ + dbShapeArrayTests.cc \ + dbShapeTests.cc \ + dbRegionTests.cc \ + dbPropertiesRepositoryTests.cc \ + dbPolygonTests.cc \ + dbPointTests.cc \ + dbPCellsTests.cc \ + dbPathTests.cc \ + dbObjectTests.cc \ + dbMatrixTests.cc \ + dbLibrariesTests.cc \ + dbLayoutUtilsTests.cc \ + dbLayoutDiffTests.cc \ + dbLayoutTests.cc \ + dbLayerMappingTests.cc \ + dbLayerTests.cc \ + dbExpressionTests.cc \ + dbEdgesToContoursTests.cc \ + dbEdgesTests.cc \ + dbEdgeProcessorTests.cc \ + dbEdgePairsTests.cc \ + dbEdgePairRelationsTests.cc \ + dbEdgePairTests.cc \ + dbEdgeTests.cc \ + dbClipTests.cc \ + dbCellMappingTests.cc \ + dbCellHullGeneratorTests.cc \ + dbCellGraphUtilsTests.cc \ + dbCellTests.cc \ + dbBoxTreeTests.cc \ + dbBoxScannerTests.cc \ + dbBoxTests.cc \ + dbArrayTests.cc INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC DEPENDPATH += $$TL_INC $$DB_INC $$GSI_INC From 4fbb6286ac341c71150ca4e18cdf698e4b817d71 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 12 May 2020 21:16:12 +0200 Subject: [PATCH 03/35] Fixed unit tests. --- src/db/unit_tests/dbTextsTests.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/db/unit_tests/dbTextsTests.cc b/src/db/unit_tests/dbTextsTests.cc index df5ce9c2c..609de5876 100644 --- a/src/db/unit_tests/dbTextsTests.cc +++ b/src/db/unit_tests/dbTextsTests.cc @@ -170,6 +170,6 @@ TEST(6) texts.insert_into (&ly, top_cell, l1); - db::Region r (db::RecursiveShapeIterator (ly, ly.cell (top_cell), l1)); - EXPECT_EQ (r.to_string (), "(-10,-21;9,20;50,51;91,80);(-10,-21;9,20;110,121;91,80)"); + db::Texts r (db::RecursiveShapeIterator (ly, ly.cell (top_cell), l1)); + EXPECT_EQ (r.to_string (), "('abc',r0 100,-200);('uvw',r0 110,210)"); } From c1b1ce6951e3c59ae5f77fc8af44bad4bbf56c9b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 12 May 2020 21:43:11 +0200 Subject: [PATCH 04/35] Provide unit test for DeepTexts. --- src/db/db/dbHierarchyBuilder.cc | 5 +- src/db/unit_tests/dbDeepTextsTests.cc | 85 ++++++++++++++++++++++++++ src/db/unit_tests/unit_tests.pro | 3 +- testdata/algo/deep_texts_au1.gds | Bin 0 -> 848 bytes testdata/algo/deep_texts_l1.gds | Bin 0 -> 2894 bytes 5 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 src/db/unit_tests/dbDeepTextsTests.cc create mode 100644 testdata/algo/deep_texts_au1.gds create mode 100644 testdata/algo/deep_texts_l1.gds diff --git a/src/db/db/dbHierarchyBuilder.cc b/src/db/db/dbHierarchyBuilder.cc index 50340a6a1..5ea489b02 100644 --- a/src/db/db/dbHierarchyBuilder.cc +++ b/src/db/db/dbHierarchyBuilder.cc @@ -714,7 +714,10 @@ TextBuildingHierarchyBuilderShapeReceiver::TextBuildingHierarchyBuilderShapeRece void TextBuildingHierarchyBuilderShapeReceiver::push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box & /*region*/, const db::RecursiveShapeReceiver::box_tree_type * /*complex_region*/, db::Shapes *target) { if (shape.is_text ()) { - target->insert (shape.text ().transformed (trans)); + db::Text t; + shape.text (t); + t.transform (trans); + target->insert (t); } } diff --git a/src/db/unit_tests/dbDeepTextsTests.cc b/src/db/unit_tests/dbDeepTextsTests.cc new file mode 100644 index 000000000..78586ed3e --- /dev/null +++ b/src/db/unit_tests/dbDeepTextsTests.cc @@ -0,0 +1,85 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 "dbTexts.h" +#include "dbDeepShapeStore.h" +#include "dbRegion.h" +#include "dbEdges.h" +#include "tlUnitTest.h" +#include "tlStream.h" + +TEST(1_Basics) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/deep_texts_l1.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly); + } + + db::cell_index_type top_cell_index = *ly.begin_top_down (); + db::Cell &top_cell = ly.cell (top_cell_index); + + db::DeepShapeStore dss; + + unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0)); + unsigned int l3 = ly.get_layer (db::LayerProperties (3, 0)); + unsigned int l100 = ly.get_layer (db::LayerProperties (100, 0)); + + db::Texts texts2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss); + db::Texts texts3 (db::RecursiveShapeIterator (ly, top_cell, l3), dss); + db::Texts texts100 (db::RecursiveShapeIterator (ly, top_cell, l100), dss); + + EXPECT_EQ (texts100.empty (), true); + EXPECT_EQ (texts2.empty (), false); + EXPECT_EQ (texts2.bbox ().to_string (), "(-520,0;24040,2800)"); + EXPECT_EQ (texts2.size (), size_t (40)); + EXPECT_EQ (texts2.to_string ().substr (0, 42), "('L2',r0 -520,0);('L2',r0 -520,2800);('L2'"); + + db::Layout target; + unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index)); + + db::Region polygons; + texts2.polygons (polygons); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), polygons); + + polygons.clear (); + texts3.polygons (polygons); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), polygons); + + db::Edges edges; + texts2.edges (edges); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), edges); + + // NOTE: insert texts2 as layer 14/0 from a copy - this tests the ability to copy-construct an TC + db::Texts texts2_copy (texts2); + texts2_copy.insert_into_as_polygons (&target, target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), 1); + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_texts_au1.gds"); +} diff --git a/src/db/unit_tests/unit_tests.pro b/src/db/unit_tests/unit_tests.pro index 20e692741..7962b945a 100644 --- a/src/db/unit_tests/unit_tests.pro +++ b/src/db/unit_tests/unit_tests.pro @@ -74,7 +74,8 @@ SOURCES = \ dbBoxTreeTests.cc \ dbBoxScannerTests.cc \ dbBoxTests.cc \ - dbArrayTests.cc + dbArrayTests.cc \ + dbDeepTextsTests.cc INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC DEPENDPATH += $$TL_INC $$DB_INC $$GSI_INC diff --git a/testdata/algo/deep_texts_au1.gds b/testdata/algo/deep_texts_au1.gds new file mode 100644 index 0000000000000000000000000000000000000000..ed1dcab44d6c52186e2a22f74f20f40ec3dc3709 GIT binary patch literal 848 zcmZQzV_;&6V31*CVt>NG%D}@Q%Amrajm&1?U}E#}bYfr-VP>^+>@@d2w)}&o%MSeo zv!g;7WLRhA33BucW?*39U|?Y5Wn$oBVB=$AU|`S@VE+IAe>)I^Ks!)`5lDB! zXs{?$o`FRWp!{ z2R}2A1cnRPHyt1*Pz#ub=wfHU8$KLtY@U8$Mhq-m3=CXCu(09*nf9*$WE#X2?6O=R zu*kAWF*YzT08IdTXaWus(A2=pA>dYETn2gix%&g%1auFF5X9wRo51!U+=?Q{6@cOj u6giOvxaH(N;Fi;Lz%6Ht>T4AHY#-p(=V5?bE~o*wT+9W8954h~SQr2>6r8^R literal 0 HcmV?d00001 diff --git a/testdata/algo/deep_texts_l1.gds b/testdata/algo/deep_texts_l1.gds new file mode 100644 index 0000000000000000000000000000000000000000..fbde83f92de493199bf7c060380afe36937d9df4 GIT binary patch literal 2894 zcma)-K}Zx~6vyAr?tU}7u4ZP2AyHCLU>0eHNTRlti?W8hNiBjNy97ZJ5fwrSmIOha ztb+vE!CMdrdWwkf)G;W+L)Sp)&8m>V^s|7wT2I9FM>ZkioLQHrALes>ycv@>phB{N@05VwnDR}X)l5mj;|^9@c69b z_?odU*5Tt)>{aoV|M|C85&tpHdKJ3+h<#Kjc4i=dpB}M)IO`zmP^+v^?4CZQYZZ6n zt0P=7Yfl{i%hXuUB-{SG&LoN-)=}LGLlvwr`ylVEQ{j%?ec9jdYf@y7T1w^eW9XbT zQMy6;)#?`&_nlnq2HzRyw1~do zLQG<3mnIq>r%1xoR9GEx>TRggIFl$fg>!u=6gx9Qzm8a)x_XJ%x(|e6k9P+2(g(;N z@&2Iq6ca7M_wlz-?94DdPIRBM4zdpMYlUKu)^qof1QUMTiddq5ux#^*lK`nqpg zFBCia$mw~s70>LXr$?@>IKO+Ei7^m!NGNtNM2~ZOgH7i(P0auDL*(O9>}o!sH@*0% z?IWDeil+Smb$o#DF2!D1iPA$e#Cqg@k@X(MPD9c9)RNYx-)g;3?5U+_eNB(nXU=N9 zQ0z55S|6B*G5xmVsfqgFZI{ajyf8B`Hyy9-X<#+0k*h@%h~J>Q%t5@XM|1hhBk;sD zvl{eNbfy@x_`Soz!;OX$S(dqED@vq*R zdmm&vJM*l19+W@ndBFUid9XPMzdqat&_t{f=7CV`s!yN28{aoih$fD+UXyi`%UaJA zdzC(LpEh5>Zw~Q6a|ZYEnMbj!xj=lMp6Gf9>ov_8U(o(KtD~G7aXzMSfQ}XZg^+2UpDLd;eI6& F^bf!QOOF5m literal 0 HcmV?d00001 From 08026e8b3509980d9e19d48fe7f4ca19161b699d Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 12 May 2020 23:01:54 +0200 Subject: [PATCH 05/35] Bugfix: in-place filter not working for region, edges. Implemented hierarchical filter for texts. Added Ruby tests for Texts. --- src/db/db/dbDeepEdges.cc | 9 +- src/db/db/dbDeepEdges.h | 2 + src/db/db/dbDeepRegion.cc | 9 +- src/db/db/dbDeepRegion.h | 1 + src/db/db/dbDeepShapeStore.cc | 6 + src/db/db/dbDeepTexts.cc | 80 +++++++++- src/db/db/dbDeepTexts.h | 1 + src/db/db/dbFlatTexts.cc | 2 +- src/db/db/dbTexts.h | 1 + src/db/db/gsiDeclDbTexts.cc | 4 +- src/rba/unit_tests/rba.cc | 1 + testdata/ruby/dbTextsTest.rb | 275 ++++++++++++++++++++++++++++++++++ 12 files changed, 382 insertions(+), 9 deletions(-) create mode 100644 testdata/ruby/dbTextsTest.rb diff --git a/src/db/db/dbDeepEdges.cc b/src/db/db/dbDeepEdges.cc index 4b9eec059..5f556ad5a 100644 --- a/src/db/db/dbDeepEdges.cc +++ b/src/db/db/dbDeepEdges.cc @@ -650,11 +650,18 @@ EdgesDelegate * DeepEdges::filter_in_place (const EdgeFilterBase &filter) { // TODO: implement to be really in-place - return filtered (filter); + *this = *apply_filter (filter); + return this; } EdgesDelegate * DeepEdges::filtered (const EdgeFilterBase &filter) const +{ + return apply_filter (filter); +} + +DeepEdges * +DeepEdges::apply_filter (const EdgeFilterBase &filter) const { const db::DeepLayer &edges = filter.requires_raw_input () ? deep_layer () : merged_deep_layer (); diff --git a/src/db/db/dbDeepEdges.h b/src/db/db/dbDeepEdges.h index 662ac5cd1..2cfa35e2f 100644 --- a/src/db/db/dbDeepEdges.h +++ b/src/db/db/dbDeepEdges.h @@ -178,6 +178,8 @@ private: virtual RegionDelegate *pull_generic (const Region ®ion) const; virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, bool invert) const; virtual EdgesDelegate *selected_interacting_generic (const Region ®ion, bool invert) const; + DeepEdges *apply_filter (const EdgeFilterBase &filter) const; + template OutputContainer *processed_impl (const edge_processor &filter) const; }; diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index 078924859..893eba147 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -1085,11 +1085,18 @@ RegionDelegate * DeepRegion::filter_in_place (const PolygonFilterBase &filter) { // TODO: implement to be really in-place - return filtered (filter); + *this = *apply_filter (filter); + return this; } RegionDelegate * DeepRegion::filtered (const PolygonFilterBase &filter) const +{ + return apply_filter (filter); +} + +DeepRegion * +DeepRegion::apply_filter (const PolygonFilterBase &filter) const { const db::DeepLayer &polygons = filter.requires_raw_input () ? deep_layer () : merged_deep_layer (); diff --git a/src/db/db/dbDeepRegion.h b/src/db/db/dbDeepRegion.h index c1665d658..2dc7f6a0c 100644 --- a/src/db/db/dbDeepRegion.h +++ b/src/db/db/dbDeepRegion.h @@ -194,6 +194,7 @@ private: virtual RegionDelegate *selected_interacting_generic (const Edges &other, bool inverse) const; virtual RegionDelegate *pull_generic (const Region &other, int mode, bool touching) const; virtual EdgesDelegate *pull_generic (const Edges &other) const; + DeepRegion *apply_filter (const PolygonFilterBase &filter) const; template OutputContainer *processed_impl (const polygon_processor &filter) const; }; diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index 061b4b180..db7a95c55 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -1079,6 +1079,12 @@ DeepShapeStore::insert_as_polygons (const DeepLayer &deep_layer, db::Layout *int s->polygon (poly); out.insert (poly); + } else if (s->is_text ()) { + + db::Text t; + s->text (t); + out.insert (db::SimplePolygon (t.box ().enlarged (db::Vector (enl, enl)))); + } } diff --git a/src/db/db/dbDeepTexts.cc b/src/db/db/dbDeepTexts.cc index 479ee93c5..4878f95a1 100644 --- a/src/db/db/dbDeepTexts.cc +++ b/src/db/db/dbDeepTexts.cc @@ -231,14 +231,86 @@ TextsDelegate *DeepTexts::add (const Texts &other) const TextsDelegate *DeepTexts::filter_in_place (const TextFilterBase &filter) { - // TODO: implement - return AsIfFlatTexts::filter_in_place (filter); + // TODO: implement as really in place + *this = *apply_filter (filter); + return this; } TextsDelegate *DeepTexts::filtered (const TextFilterBase &filter) const { - // TODO: implement - return AsIfFlatTexts::filtered (filter); + return apply_filter (filter); +} + +DeepTexts *DeepTexts::apply_filter (const TextFilterBase &filter) const +{ + const db::DeepLayer &texts = deep_layer (); + + std::auto_ptr vars; + if (filter.vars ()) { + + vars.reset (new db::VariantsCollectorBase (filter.vars ())); + + vars->collect (texts.layout (), texts.initial_cell ()); + + if (filter.wants_variants ()) { + const_cast (texts).separate_variants (*vars); + } + + } + + db::Layout &layout = const_cast (texts.layout ()); + std::map > to_commit; + + std::auto_ptr res (new db::DeepTexts (texts.derived ())); + for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { + + const db::Shapes &s = c->shapes (texts.layer ()); + + if (vars.get ()) { + + const std::map &vv = vars->variants (c->cell_index ()); + for (std::map::const_iterator v = vv.begin (); v != vv.end (); ++v) { + + db::Shapes *st; + if (vv.size () == 1) { + st = & c->shapes (res->deep_layer ().layer ()); + } else { + st = & to_commit [c->cell_index ()] [v->first]; + } + + const db::ICplxTrans &tr = v->first; + + for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Texts); ! si.at_end (); ++si) { + db::Text text; + si->text (text); + if (filter.selected (text.transformed (tr))) { + st->insert (*si); + } + } + + } + + } else { + + db::Shapes &st = c->shapes (res->deep_layer ().layer ()); + + for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Texts); ! si.at_end (); ++si) { + db::Text text; + si->text (text); + if (filter.selected (text)) { + st.insert (*si); + } + } + + } + + } + + if (! to_commit.empty () && vars.get ()) { + res->deep_layer ().commit_shapes (*vars, to_commit); + } + + return res.release (); } RegionDelegate *DeepTexts::polygons (db::Coord e) const diff --git a/src/db/db/dbDeepTexts.h b/src/db/db/dbDeepTexts.h index bac1c081b..384febb33 100644 --- a/src/db/db/dbDeepTexts.h +++ b/src/db/db/dbDeepTexts.h @@ -94,6 +94,7 @@ private: DeepLayer m_deep_layer; void init (); + DeepTexts *apply_filter (const TextFilterBase &filter) const; }; } diff --git a/src/db/db/dbFlatTexts.cc b/src/db/db/dbFlatTexts.cc index 4e4152d3a..96668a150 100644 --- a/src/db/db/dbFlatTexts.cc +++ b/src/db/db/dbFlatTexts.cc @@ -207,7 +207,7 @@ FlatTexts::insert (const db::Text &t) void FlatTexts::insert (const db::Shape &shape) { - if (shape.is_edge_pair ()) { + if (shape.is_text ()) { db::Text t; shape.text (t); diff --git a/src/db/db/dbTexts.h b/src/db/db/dbTexts.h index bfba8ac50..173ce1e25 100644 --- a/src/db/db/dbTexts.h +++ b/src/db/db/dbTexts.h @@ -215,6 +215,7 @@ public: virtual bool selected (const db::Text &text) const = 0; virtual const TransformationReducer *vars () const = 0; + virtual bool wants_variants () const = 0; }; /** diff --git a/src/db/db/gsiDeclDbTexts.cc b/src/db/db/gsiDeclDbTexts.cc index c701d2a1a..749bcfbc3 100644 --- a/src/db/db/gsiDeclDbTexts.cc +++ b/src/db/db/gsiDeclDbTexts.cc @@ -159,7 +159,7 @@ static db::Texts with_text (const db::Texts *r, const std::string &text, bool in return r->filtered (f); } -static db::Texts with_pattern (const db::Texts *r, const std::string &pattern, bool inverse) +static db::Texts with_match (const db::Texts *r, const std::string &pattern, bool inverse) { db::TextPatternFilter f (pattern, inverse); return r->filtered (f); @@ -391,7 +391,7 @@ Class decl_Texts ("db", "Texts", "If \"inverse\" is false, this method returns the texts with the given string.\n" "If \"inverse\" is true, this method returns the texts not having the given string.\n" ) + - method_ext ("with_match", with_pattern, gsi::arg ("pattern"), gsi::arg ("inverse"), + method_ext ("with_match", with_match, gsi::arg ("pattern"), gsi::arg ("inverse"), "@brief Filter the text by glob pattern\n" "\"pattern\" is a glob-style pattern (e.g. \"A*\" will select all texts starting with a capital \"A\").\n" "If \"inverse\" is false, this method returns the texts matching the pattern.\n" diff --git a/src/rba/unit_tests/rba.cc b/src/rba/unit_tests/rba.cc index c7ac735e6..924514fc9 100644 --- a/src/rba/unit_tests/rba.cc +++ b/src/rba/unit_tests/rba.cc @@ -127,6 +127,7 @@ RUBYTEST (dbReaders, "dbReaders.rb") RUBYTEST (dbShapesTest, "dbShapesTest.rb") RUBYTEST (dbSimplePolygonTest, "dbSimplePolygonTest.rb") RUBYTEST (dbTextTest, "dbTextTest.rb") +RUBYTEST (dbTextsTest, "dbTextsTest.rb") RUBYTEST (dbTilingProcessorTest, "dbTilingProcessorTest.rb") RUBYTEST (dbTransTest, "dbTransTest.rb") RUBYTEST (dbVectorTest, "dbVectorTest.rb") diff --git a/testdata/ruby/dbTextsTest.rb b/testdata/ruby/dbTextsTest.rb new file mode 100644 index 000000000..9cbb4b82c --- /dev/null +++ b/testdata/ruby/dbTextsTest.rb @@ -0,0 +1,275 @@ +# encoding: UTF-8 + +# KLayout Layout Viewer +# Copyright (C) 2006-2020 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 + +if !$:.member?(File::dirname($0)) + $:.push(File::dirname($0)) +end + +load("test_prologue.rb") + +class DBTexts_TestClass < TestBase + + # Basics + def test_1 + + r = RBA::Texts::new + assert_equal(r.to_s, "") + assert_equal(r.is_empty?, true) + assert_equal(r.size, 0) + assert_equal(r.bbox.to_s, "()") + data_id = r.data_id + + r.insert(RBA::Text::new("abc", RBA::Trans::new(RBA::Vector::new(100, -200)))) + assert_equal(data_id != r.data_id, true) + assert_equal(r.to_s, "('abc',r0 100,-200)") + r.clear + + r.insert(RBA::Text::new("uvw", RBA::Trans::new(RBA::Vector::new(110, 210)))) + assert_equal(r.to_s, "('uvw',r0 110,210)") + assert_equal(r.extents.to_s, "(109,209;109,211;111,211;111,209)") + assert_equal(r.extents(10).to_s, "(100,200;100,220;120,220;120,200)") + assert_equal(r.extents(5, 10).to_s, "(105,200;105,220;115,220;115,200)") + assert_equal(r.edges.to_s, "(110,210;110,210)") + assert_equal(r.is_empty?, false) + assert_equal(r.size, 1) + assert_equal(r[0].to_s, "('uvw',r0 110,210)") + assert_equal(r[1].to_s, "") + assert_equal(r.bbox.to_s, "(110,210;110,210)") + + assert_equal(r.moved(-10, 10).to_s, "('uvw',r0 100,220)") + assert_equal(r.moved(RBA::Point::new(-10, 10)).to_s, "('uvw',r0 100,220)") + rr = r.dup + assert_equal(rr.data_id != r.data_id, true) + rr.move(-10, 10) + assert_equal(rr.to_s, "('uvw',r0 100,220)") + rr = r.dup + rr.move(RBA::Point::new(-10, 10)) + assert_equal(rr.to_s, "('uvw',r0 100,220)") + + assert_equal(r.transformed(RBA::Trans::new(1)).to_s, "('uvw',r90 -210,110)") + assert_equal(r.transformed(RBA::ICplxTrans::new(2.0)).to_s, "('uvw',r0 220,420)") + rr = r.dup + rr.transform(RBA::Trans::new(1)) + assert_equal(rr.to_s, "('uvw',r90 -210,110)") + rr = r.dup + rr.transform(RBA::ICplxTrans::new(2.0)) + assert_equal(rr.to_s, "('uvw',r0 220,420)") + + rr = RBA::Texts::new + rr.swap(r) + assert_equal(rr.to_s, "('uvw',r0 110,210)") + assert_equal(r.to_s, "") + rr.swap(r) + assert_equal(r.to_s, "('uvw',r0 110,210)") + r.clear + + assert_equal(r.to_s, "") + assert_equal(r.is_empty?, true) + assert_equal(r.size, 0) + assert_equal(r.bbox.to_s, "()") + + texts = RBA::Texts::new + t = RBA::Texts::new + t.insert(RBA::Text::new("uvw", RBA::Trans::new(RBA::Vector::new(-110, 210)))) + texts.insert(t) + assert_equal(texts.to_s, "('uvw',r0 -110,210)") + + end + + # Basics + def test_2 + + r1 = RBA::Texts::new + r1.insert(RBA::Text::new("abc", RBA::Trans::new(RBA::Vector::new(100, -200)))) + r1.insert(RBA::Text::new("uvm", RBA::Trans::new(RBA::Vector::new(110, 210)))) + + r2 = RBA::Texts::new + r1.insert(RBA::Text::new("abc", RBA::Trans::new(RBA::Vector::new(101, -201)))) + r1.insert(RBA::Text::new("uvm", RBA::Trans::new(RBA::Vector::new(111, 211)))) + + assert_equal((r1 + r2).to_s, "('abc',r0 100,-200);('uvm',r0 110,210);('abc',r0 101,-201);('uvm',r0 111,211)") + r1 += r2 + assert_equal(r1.to_s, "('abc',r0 100,-200);('uvm',r0 110,210);('abc',r0 101,-201);('uvm',r0 111,211)") + + end + + def test_3 + + text1 = RBA::Text::new("abc", RBA::Trans::new(RBA::Vector::new(100, -200))) + text2 = RBA::Text::new("uvm", RBA::Trans::new(RBA::Vector::new(110, 210))) + text3 = RBA::Text::new("xyz", RBA::Trans::new(RBA::Vector::new(-101, 201))) + + r1 = RBA::Texts::new([ text1, text2 ]) + assert_equal(r1.to_s, "('abc',r0 100,-200);('uvm',r0 110,210)") + assert_equal(r1.with_text("abc", false).to_s, "('abc',r0 100,-200)") + assert_equal(r1.with_text("abc", true).to_s, "('uvm',r0 110,210)") + assert_equal(r1.with_match("*b*", false).to_s, "('abc',r0 100,-200)") + assert_equal(r1.with_match("*b*", true).to_s, "('uvm',r0 110,210)") + + r1 = RBA::Texts::new(text1) + assert_equal(r1.to_s, "('abc',r0 100,-200)") + + s = RBA::Shapes::new + s.insert(text1) + s.insert(text2) + r1 = RBA::Texts::new(s) + assert_equal(r1.to_s, "('abc',r0 100,-200);('uvm',r0 110,210)") + + ly = RBA::Layout::new + l1 = ly.layer("l1") + l2 = ly.layer("l2") + l3 = ly.layer("l3") + c1 = ly.create_cell("C1") + c2 = ly.create_cell("C2") + c1.insert(RBA::CellInstArray::new(c2.cell_index, RBA::Trans::new(0, 0))) + c1.insert(RBA::CellInstArray::new(c2.cell_index, RBA::Trans::new(0, 100))) + c1.insert(RBA::CellInstArray::new(c2.cell_index, RBA::Trans::new(200, 100))) + c2.shapes(l1).insert(text1) + c2.shapes(l2).insert(text2) + c2.shapes(l3).insert(text3) + + r = RBA::Texts::new(ly.begin_shapes(c1.cell_index, l1)) + assert_equal(r.to_s(30), "('abc',r0 100,-200);('abc',r0 100,-100);('abc',r0 300,-100)") + assert_equal(r.to_s(2), "('abc',r0 100,-200);('abc',r0 100,-100)...") + assert_equal(r.is_empty?, false) + assert_equal(r.size, 3) + + assert_equal(r.has_valid_texts?, false) + assert_equal(r.bbox.to_s, "(100,-200;300,-100)") + + assert_equal(r.is_deep?, false) + + r.flatten + assert_equal(r.has_valid_texts?, true) + assert_equal(r[1].to_s, "('abc',r0 100,-100)") + assert_equal(r[100].inspect, "nil") + assert_equal(r.bbox.to_s, "(100,-200;300,-100)") + + dss = RBA::DeepShapeStore::new + r = RBA::Texts::new(ly.begin_shapes(c1.cell_index, l1), dss) + assert_equal(r.to_s(30), "('abc',r0 100,-200);('abc',r0 100,-100);('abc',r0 300,-100)") + assert_equal(r.to_s(2), "('abc',r0 100,-200);('abc',r0 100,-100)...") + assert_equal(r.is_empty?, false) + assert_equal(r.size, 3) + + assert_equal(r.has_valid_texts?, false) + assert_equal(r.bbox.to_s, "(100,-200;300,-100)") + + assert_equal(r.is_deep?, true) + + r.flatten + assert_equal(r.has_valid_texts?, true) + assert_equal(r[1].to_s, "('abc',r0 100,-100)") + assert_equal(r[100].inspect, "nil") + assert_equal(r.bbox.to_s, "(100,-200;300,-100)") + + assert_equal(r.is_deep?, false) + + end + + def test_4 + + # insert_into and insert_into_as_polygons + + text1 = RBA::Text::new("abc", RBA::Trans::new(RBA::Vector::new(100, -200))) + + ly = RBA::Layout::new + l1 = ly.layer("l1") + c1 = ly.create_cell("C1") + c2 = ly.create_cell("C2") + c1.insert(RBA::CellInstArray::new(c2.cell_index, RBA::Trans::new(0, 0))) + c1.insert(RBA::CellInstArray::new(c2.cell_index, RBA::Trans::new(0, 100))) + c1.insert(RBA::CellInstArray::new(c2.cell_index, RBA::Trans::new(200, 100))) + c2.shapes(l1).insert(text1) + + dss = RBA::DeepShapeStore::new + r = RBA::Texts::new(ly.begin_shapes(c1.cell_index, l1), dss) + + target = RBA::Layout::new + target_top = target.add_cell("TOP") + target_li = target.layer + r.insert_into(target, target_top, target_li) + cells = [] + target.each_cell { |c| cells << c.name } + assert_equal(cells.join(","), "TOP,C2") + assert_equal(RBA::Texts::new(target.cell("TOP").shapes(target_li)).to_s, "") + assert_equal(RBA::Texts::new(target.cell("C2").shapes(target_li)).to_s, "('abc',r0 100,-200)") + + target_li = target.layer + r.with_text("abc", false).insert_into(target, target_top, target_li) + cells = [] + target.each_cell { |c| cells << c.name } + assert_equal(cells.join(","), "TOP,C2") + assert_equal(RBA::Texts::new(target.cell("TOP").shapes(target_li)).to_s, "") + assert_equal(RBA::Texts::new(target.cell("C2").shapes(target_li)).to_s, "('abc',r0 100,-200)") + + target_li = target.layer + r.with_text("abd", true).insert_into(target, target_top, target_li) + cells = [] + target.each_cell { |c| cells << c.name } + assert_equal(cells.join(","), "TOP,C2") + assert_equal(RBA::Texts::new(target.cell("TOP").shapes(target_li)).to_s, "") + assert_equal(RBA::Texts::new(target.cell("C2").shapes(target_li)).to_s, "('abc',r0 100,-200)") + + target_li = target.layer + r.with_text("abc", true).insert_into(target, target_top, target_li) + cells = [] + target.each_cell { |c| cells << c.name } + assert_equal(cells.join(","), "TOP,C2") + assert_equal(RBA::Texts::new(target.cell("TOP").shapes(target_li)).to_s, "") + assert_equal(RBA::Texts::new(target.cell("C2").shapes(target_li)).to_s, "") + + target_li = target.layer + r.with_match("*b*", false).insert_into(target, target_top, target_li) + cells = [] + target.each_cell { |c| cells << c.name } + assert_equal(cells.join(","), "TOP,C2") + assert_equal(RBA::Texts::new(target.cell("TOP").shapes(target_li)).to_s, "") + assert_equal(RBA::Texts::new(target.cell("C2").shapes(target_li)).to_s, "('abc',r0 100,-200)") + + target_li = target.layer + r.with_match("*bb*", true).insert_into(target, target_top, target_li) + cells = [] + target.each_cell { |c| cells << c.name } + assert_equal(cells.join(","), "TOP,C2") + assert_equal(RBA::Texts::new(target.cell("TOP").shapes(target_li)).to_s, "") + assert_equal(RBA::Texts::new(target.cell("C2").shapes(target_li)).to_s, "('abc',r0 100,-200)") + + target_li = target.layer + r.with_match("*b*", true).insert_into(target, target_top, target_li) + cells = [] + target.each_cell { |c| cells << c.name } + assert_equal(cells.join(","), "TOP,C2") + assert_equal(RBA::Texts::new(target.cell("TOP").shapes(target_li)).to_s, "") + assert_equal(RBA::Texts::new(target.cell("C2").shapes(target_li)).to_s, "") + + target_li = target.layer + r.insert_into_as_polygons(target, target_top, target_li, 1) + cells = [] + target.each_cell { |c| cells << c.name } + assert_equal(cells.join(","), "TOP,C2") + assert_equal(RBA::Region::new(target.cell("TOP").shapes(target_li)).to_s, "") + assert_equal(RBA::Region::new(target.cell("C2").shapes(target_li)).to_s, "(99,-201;99,-199;101,-199;101,-201)") + + end + +end + + +load("test_epilogue.rb") From 4e7d0a81b840a3322e05e641a2092c9c2a964b53 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 13 May 2020 17:29:10 +0200 Subject: [PATCH 06/35] 'interact' between regions and texts. --- src/db/db/dbAsIfFlatTexts.cc | 97 ++++++++++++ src/db/db/dbAsIfFlatTexts.h | 8 + src/db/db/dbDeepEdges.cc | 6 +- src/db/db/dbDeepRegion.h | 1 + src/db/db/dbDeepTexts.cc | 210 ++++++++++++++++++++++++++ src/db/db/dbDeepTexts.h | 3 + src/db/db/dbEmptyTexts.cc | 18 +++ src/db/db/dbEmptyTexts.h | 4 + src/db/db/dbFlatTexts.h | 2 + src/db/db/dbHierProcessor.cc | 21 ++- src/db/db/dbPolygonTools.h | 17 +++ src/db/db/dbTexts.cc | 5 + src/db/db/dbTexts.h | 46 ++++++ src/db/db/dbTextsDelegate.h | 5 + src/db/db/dbTextsUtils.h | 41 +++++ src/db/db/gsiDeclDbEdges.cc | 16 +- src/db/db/gsiDeclDbTexts.cc | 42 ++++++ src/db/unit_tests/dbDeepTextsTests.cc | 60 ++++++++ testdata/algo/deep_texts_au1.gds | Bin 848 -> 912 bytes testdata/algo/deep_texts_au2.gds | Bin 0 -> 7706 bytes testdata/algo/deep_texts_l2.gds | Bin 0 -> 2986 bytes 21 files changed, 588 insertions(+), 14 deletions(-) create mode 100644 testdata/algo/deep_texts_au2.gds create mode 100644 testdata/algo/deep_texts_l2.gds diff --git a/src/db/db/dbAsIfFlatTexts.cc b/src/db/db/dbAsIfFlatTexts.cc index 968988311..d3b67790d 100644 --- a/src/db/db/dbAsIfFlatTexts.cc +++ b/src/db/db/dbAsIfFlatTexts.cc @@ -26,8 +26,11 @@ #include "dbFlatRegion.h" #include "dbFlatEdges.h" #include "dbEmptyTexts.h" +#include "dbEmptyRegion.h" #include "dbTexts.h" #include "dbBoxConvert.h" +#include "dbRegion.h" +#include "dbTextsUtils.h" #include @@ -273,5 +276,99 @@ AsIfFlatTexts::insert_into_as_polygons (Layout *layout, db::cell_index_type into } } +TextsDelegate * +AsIfFlatTexts::selected_interacting_generic (const Region &other, bool inverse) const +{ + // shortcuts + if (other.empty () || empty ()) { + return new EmptyTexts (); + } + + db::box_scanner2 scanner (report_progress (), progress_desc ()); + + AddressableTextDelivery e (begin (), has_valid_texts ()); + + for ( ; ! e.at_end (); ++e) { + scanner.insert1 (e.operator-> (), 0); + } + + AddressablePolygonDelivery p = other.addressable_polygons (); + + for ( ; ! p.at_end (); ++p) { + scanner.insert2 (p.operator-> (), 1); + } + + std::auto_ptr output (new FlatTexts (true)); + + if (! inverse) { + + text_to_region_interaction_filter filter (*output); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + + } else { + + std::set interacting; + text_to_region_interaction_filter > filter (interacting); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + + for (TextsIterator o (begin ()); ! o.at_end (); ++o) { + if (interacting.find (*o) == interacting.end ()) { + output->insert (*o); + } + } + + } + + return output.release (); +} + +RegionDelegate * +AsIfFlatTexts::pull_generic (const Region &other) const +{ + // shortcuts + if (other.empty () || empty ()) { + return new EmptyRegion (); + } + + db::box_scanner2 scanner (report_progress (), progress_desc ()); + + AddressableTextDelivery e (begin (), true); + + for ( ; ! e.at_end (); ++e) { + scanner.insert1 (e.operator-> (), 0); + } + + AddressablePolygonDelivery p = other.addressable_merged_polygons (); + + for ( ; ! p.at_end (); ++p) { + scanner.insert2 (p.operator-> (), 1); + } + + std::auto_ptr output (new FlatRegion (true)); + + text_to_region_interaction_filter filter (*output); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + + return output.release (); +} + +RegionDelegate * +AsIfFlatTexts::pull_interacting (const Region &other) const +{ + return pull_generic (other); +} + +TextsDelegate * +AsIfFlatTexts::selected_interacting (const Region &other) const +{ + return selected_interacting_generic (other, false); +} + +TextsDelegate * +AsIfFlatTexts::selected_not_interacting (const Region &other) const +{ + return selected_interacting_generic (other, true); +} + } diff --git a/src/db/db/dbAsIfFlatTexts.h b/src/db/db/dbAsIfFlatTexts.h index a2236cc7f..f10d7bdea 100644 --- a/src/db/db/dbAsIfFlatTexts.h +++ b/src/db/db/dbAsIfFlatTexts.h @@ -30,6 +30,8 @@ namespace db { +class Region; + /** * @brief Provides default flat implementations */ @@ -69,6 +71,10 @@ public: virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const; virtual void insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const; + virtual RegionDelegate *pull_interacting (const Region &) const; + virtual TextsDelegate *selected_interacting (const Region &other) const; + virtual TextsDelegate *selected_not_interacting (const Region &other) const; + protected: void update_bbox (const db::Box &box); void invalidate_bbox (); @@ -80,6 +86,8 @@ private: mutable db::Box m_bbox; virtual db::Box compute_bbox () const; + virtual TextsDelegate *selected_interacting_generic (const Region &other, bool inverse) const; + virtual RegionDelegate *pull_generic (const Region &other) const; }; } diff --git a/src/db/db/dbDeepEdges.cc b/src/db/db/dbDeepEdges.cc index 5f556ad5a..fd99ab58a 100644 --- a/src/db/db/dbDeepEdges.cc +++ b/src/db/db/dbDeepEdges.cc @@ -1285,7 +1285,7 @@ public: } } - for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { const db::Edge &subject = interactions.subject_shape (i->first); scanner.insert1 (&subject, 0); } @@ -1302,7 +1302,7 @@ public: edge_to_region_interaction_filter > filter (interacting); scanner.process (filter, 1, db::box_convert (), db::box_convert ()); - for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { const db::Edge &subject = interactions.subject_shape (i->first); if (interacting.find (subject) == interacting.end ()) { result.insert (subject); @@ -1381,7 +1381,7 @@ public: } } - for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { const db::Edge &subject = interactions.subject_shape (i->first); scanner.insert1 (&subject, 1); } diff --git a/src/db/db/dbDeepRegion.h b/src/db/db/dbDeepRegion.h index 2dc7f6a0c..e1cdc57c3 100644 --- a/src/db/db/dbDeepRegion.h +++ b/src/db/db/dbDeepRegion.h @@ -176,6 +176,7 @@ protected: private: friend class DeepEdges; + friend class DeepTexts; DeepRegion &operator= (const DeepRegion &other); diff --git a/src/db/db/dbDeepTexts.cc b/src/db/db/dbDeepTexts.cc index 4878f95a1..3145b2bf3 100644 --- a/src/db/db/dbDeepTexts.cc +++ b/src/db/db/dbDeepTexts.cc @@ -27,8 +27,13 @@ #include "dbDeepRegion.h" #include "dbCellMapping.h" #include "dbLayoutUtils.h" +#include "dbLocalOperation.h" +#include "dbTextsUtils.h" +#include "dbHierProcessor.h" +#include "dbRegion.h" #include +#include namespace db { @@ -384,5 +389,210 @@ void DeepTexts::insert_into_as_polygons (Layout *layout, db::cell_index_type int m_deep_layer.insert_into_as_polygons (layout, into_cell, into_layer, enl); } +namespace { + +class Text2PolygonInteractingLocalOperation + : public local_operation +{ +public: + Text2PolygonInteractingLocalOperation (bool inverse) + : m_inverse (inverse) + { + // .. nothing yet .. + } + + virtual db::Coord dist () const + { + // touching is sufficient + return 1; + } + + virtual void compute_local (db::Layout * /*layout*/, const shape_interactions &interactions, std::unordered_set &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const + { + db::box_scanner2 scanner; + + std::set others; + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { + others.insert (interactions.intruder_shape (*j)); + } + } + + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + const db::Text &subject = interactions.subject_shape (i->first); + scanner.insert1 (&subject, 0); + } + + std::list heap; + for (std::set::const_iterator o = others.begin (); o != others.end (); ++o) { + heap.push_back (o->obj ().transformed (o->trans ())); + scanner.insert2 (& heap.back (), 1); + } + + if (m_inverse) { + + std::unordered_set interacting; + text_to_region_interaction_filter > filter (interacting); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + const db::Text &subject = interactions.subject_shape (i->first); + if (interacting.find (subject) == interacting.end ()) { + result.insert (subject); + } + } + + } else { + + text_to_region_interaction_filter > filter (result); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + + } + } + + virtual on_empty_intruder_mode on_empty_intruder_hint () const + { + if (m_inverse) { + return Copy; + } else { + return Drop; + } + } + + virtual std::string description () const + { + return tl::to_string (tr ("Select interacting texts")); + } + +private: + bool m_inverse; +}; + +struct ResultInserter +{ + typedef db::Polygon value_type; + + ResultInserter (db::Layout *layout, std::unordered_set &result) + : mp_layout (layout), mp_result (&result) + { + // .. nothing yet .. + } + + void insert (const db::Polygon &p) + { + (*mp_result).insert (db::PolygonRef (p, mp_layout->shape_repository ())); + } + +private: + db::Layout *mp_layout; + std::unordered_set *mp_result; +}; + +class Text2PolygonPullLocalOperation + : public local_operation +{ +public: + Text2PolygonPullLocalOperation () + { + // .. nothing yet .. + } + + virtual db::Coord dist () const + { + // touching is sufficient + return 1; + } + + virtual void compute_local (db::Layout *layout, const shape_interactions &interactions, std::unordered_set &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const + { + db::box_scanner2 scanner; + + std::set others; + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { + others.insert (interactions.intruder_shape (*j)); + } + } + + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + const db::Text &subject = interactions.subject_shape (i->first); + scanner.insert1 (&subject, 1); + } + + std::list heap; + for (std::set::const_iterator o = others.begin (); o != others.end (); ++o) { + heap.push_back (o->obj ().transformed (o->trans ())); + scanner.insert2 (& heap.back (), 0); + } + + ResultInserter inserter (layout, result); + text_to_region_interaction_filter filter (inserter); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + } + + virtual on_empty_intruder_mode on_empty_intruder_hint () const + { + return Drop; + } + + virtual std::string description () const + { + return tl::to_string (tr ("Select interacting regions")); + } +}; + +} + +TextsDelegate * +DeepTexts::selected_interacting_generic (const Region &other, bool inverse) const +{ + std::auto_ptr dr_holder; + const db::DeepRegion *other_deep = dynamic_cast (other.delegate ()); + if (! other_deep) { + // if the other region isn't deep, turn into a top-level only deep region to facilitate re-hierarchisation + dr_holder.reset (new db::DeepRegion (other, const_cast (*deep_layer ().store ()))); + other_deep = dr_holder.get (); + } + + const db::DeepLayer &texts = deep_layer (); + + DeepLayer dl_out (texts.derived ()); + + db::Text2PolygonInteractingLocalOperation op (inverse); + + db::local_processor proc (const_cast (&texts.layout ()), const_cast (&texts.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ()); + proc.set_base_verbosity (other.base_verbosity ()); + proc.set_threads (texts.store ()->threads ()); + + proc.run (&op, texts.layer (), other_deep->deep_layer ().layer (), dl_out.layer ()); + + return new db::DeepTexts (dl_out); +} + +RegionDelegate *DeepTexts::pull_generic (const Region &other) const +{ + std::auto_ptr dr_holder; + const db::DeepRegion *other_deep = dynamic_cast (other.delegate ()); + if (! other_deep) { + // if the other region isn't deep, turn into a top-level only deep region to facilitate re-hierarchisation + dr_holder.reset (new db::DeepRegion (other, const_cast (*deep_layer ().store ()))); + other_deep = dr_holder.get (); + } + + const db::DeepLayer &texts = deep_layer (); + const db::DeepLayer &other_polygons = other_deep->merged_deep_layer (); + + DeepLayer dl_out (other_polygons.derived ()); + + db::Text2PolygonPullLocalOperation op; + + db::local_processor proc (const_cast (&texts.layout ()), const_cast (&texts.initial_cell ()), &other_polygons.layout (), &other_polygons.initial_cell ()); + proc.set_base_verbosity (other.base_verbosity ()); + proc.set_threads (texts.store ()->threads ()); + + proc.run (&op, texts.layer (), other_polygons.layer (), dl_out.layer ()); + + return new db::DeepRegion (dl_out); +} } diff --git a/src/db/db/dbDeepTexts.h b/src/db/db/dbDeepTexts.h index 384febb33..21da58c39 100644 --- a/src/db/db/dbDeepTexts.h +++ b/src/db/db/dbDeepTexts.h @@ -95,6 +95,9 @@ private: void init (); DeepTexts *apply_filter (const TextFilterBase &filter) const; + + virtual TextsDelegate *selected_interacting_generic (const Region &other, bool inverse) const; + virtual RegionDelegate *pull_generic (const Region &other) const; }; } diff --git a/src/db/db/dbEmptyTexts.cc b/src/db/db/dbEmptyTexts.cc index 1037a078b..9ef48abc2 100644 --- a/src/db/db/dbEmptyTexts.cc +++ b/src/db/db/dbEmptyTexts.cc @@ -84,5 +84,23 @@ EmptyTexts::less (const Texts &other) const return other.empty () ? false : true; } +RegionDelegate * +EmptyTexts::pull_interacting (const Region &) const +{ + return new EmptyRegion (); +} + +TextsDelegate * +EmptyTexts::selected_interacting (const Region &) const +{ + return new EmptyTexts (); +} + +TextsDelegate * +EmptyTexts::selected_not_interacting (const Region &) const +{ + return new EmptyTexts (); +} + } diff --git a/src/db/db/dbEmptyTexts.h b/src/db/db/dbEmptyTexts.h index 59520928b..99b1623ac 100644 --- a/src/db/db/dbEmptyTexts.h +++ b/src/db/db/dbEmptyTexts.h @@ -75,6 +75,10 @@ public: virtual void insert_into (Layout *, db::cell_index_type, unsigned int) const { } virtual void insert_into_as_polygons (Layout *, db::cell_index_type, unsigned int, db::Coord) const { } + virtual RegionDelegate *pull_interacting (const Region &) const; + virtual TextsDelegate *selected_interacting (const Region &) const; + virtual TextsDelegate *selected_not_interacting (const Region &) const; + private: EmptyTexts &operator= (const EmptyTexts &other); }; diff --git a/src/db/db/dbFlatTexts.h b/src/db/db/dbFlatTexts.h index 38a249fbe..90b3e9b24 100644 --- a/src/db/db/dbFlatTexts.h +++ b/src/db/db/dbFlatTexts.h @@ -80,6 +80,8 @@ class DB_PUBLIC FlatTexts : public AsIfFlatTexts { public: + typedef db::Text value_type; + typedef db::layer text_layer_type; typedef text_layer_type::iterator text_iterator_type; diff --git a/src/db/db/dbHierProcessor.cc b/src/db/db/dbHierProcessor.cc index c3adf6449..23870f6d9 100644 --- a/src/db/db/dbHierProcessor.cc +++ b/src/db/db/dbHierProcessor.cc @@ -635,6 +635,8 @@ template class DB_PUBLIC shape_interactions; template class DB_PUBLIC shape_interactions; template class DB_PUBLIC shape_interactions; template class DB_PUBLIC shape_interactions; +template class DB_PUBLIC shape_interactions; +template class DB_PUBLIC shape_interactions; // --------------------------------------------------------------------------------------------- // Helper classes for the LocalProcessor @@ -656,6 +658,12 @@ inline unsigned int shape_flags () return db::ShapeIterator::Edges; } +template <> +inline unsigned int shape_flags () +{ + return db::ShapeIterator::Texts; +} + template struct interaction_registration_shape2shape : db::box_scanner_receiver2 @@ -850,8 +858,11 @@ instances_interact (const db::Layout *layout1, const db::CellInstArray *inst1, u // not very strong, but already useful: the cells interact if there is a layer1 in cell1 // in the common box and a layer2 in the cell2 in the common box - if (! db::RecursiveShapeIterator (*layout1, cell1, layer1, tni1 * cbox, true).at_end () && - ! db::RecursiveShapeIterator (*layout2, cell2, layer2, tni2 * cbox, true).at_end ()) { + // NOTE: don't use overlap mode for the RecursiveShapeIterator as this would not capture dot-like + // objects like texts. Instead safe-shrink the search box and use touching mode ("false" for the last + // argument) + if (! db::RecursiveShapeIterator (*layout1, cell1, layer1, safe_box_enlarged (tni1 * cbox, -1, -1), false).at_end () && + ! db::RecursiveShapeIterator (*layout2, cell2, layer2, safe_box_enlarged (tni2 * cbox, -1, -1), false).at_end ()) { return true; } @@ -929,7 +940,9 @@ instance_shape_interacts (const db::Layout *layout, const db::CellInstArray *ins // not very strong, but already useful: the cells interact if there is a layer in cell // in the common box - if (! db::RecursiveShapeIterator (*layout, cell, layer, tni * cbox, true).at_end ()) { + // NOTE: don't use overlapping mode here, because this will not select point-like objects as texts or + // dot edges. Instead safe-shrink the search box and use touching mode. + if (! db::RecursiveShapeIterator (*layout, cell, layer, safe_box_enlarged (tni * cbox, -1, -1), false).at_end ()) { return true; } @@ -1748,6 +1761,8 @@ template class DB_PUBLIC local_processor; template class DB_PUBLIC local_processor; template class DB_PUBLIC local_processor; template class DB_PUBLIC local_processor; +template class DB_PUBLIC local_processor; +template class DB_PUBLIC local_processor; } diff --git a/src/db/db/dbPolygonTools.h b/src/db/db/dbPolygonTools.h index 2300bde6d..0b5719f65 100644 --- a/src/db/db/dbPolygonTools.h +++ b/src/db/db/dbPolygonTools.h @@ -27,6 +27,7 @@ #include "dbCommon.h" #include "dbPolygon.h" +#include "dbText.h" #include #include @@ -346,6 +347,18 @@ bool interact_pe (const Polygon &poly, const Edge &edge) return false; } +/** + * @brief Determines whether the text is inside the polygon + */ +template +bool interact_pt (const Polygon &poly, const Text &text) +{ + typedef typename Text::point_type point_type; + point_type p; + p += text.trans ().disp (); + return (poly.box ().contains (p) && db::inside_poly (poly.begin_edge (), p) >= 0); +} + // Some specializations that map all combinations to template versions inline bool interact (const db::Box &box1, const db::Box &box2) { return box1.touches (box2); } inline bool interact (const db::DBox &box1, const db::DBox &box2) { return box1.touches (box2); } @@ -365,6 +378,10 @@ inline bool interact (const db::DPolygon &poly1, const db::DPolygon &poly inline bool interact (const db::DSimplePolygon &poly1, const db::DPolygon &poly2) { return interact_pp (poly1, poly2); } inline bool interact (const db::DPolygon &poly1, const db::DSimplePolygon &poly2) { return interact_pp (poly1, poly2); } inline bool interact (const db::DSimplePolygon &poly1, const db::DSimplePolygon &poly2) { return interact_pp (poly1, poly2); } +inline bool interact (const db::Polygon &poly, const db::Text &text) { return interact_pt (poly, text); } +inline bool interact (const db::SimplePolygon &poly, const db::Text &text) { return interact_pt (poly, text); } +inline bool interact (const db::DPolygon &poly, const db::DText &text) { return interact_pt (poly, text); } +inline bool interact (const db::DSimplePolygon &poly, const db::DText &text) { return interact_pt (poly, text); } /** * @brief Extract a corner radius from a contour diff --git a/src/db/db/dbTexts.cc b/src/db/db/dbTexts.cc index 1ab956aa0..7683633d5 100644 --- a/src/db/db/dbTexts.cc +++ b/src/db/db/dbTexts.cc @@ -176,6 +176,11 @@ FlatTexts *Texts::flat_texts () return texts; } +void Texts::pull_interacting (Region &output, const Region &other) const +{ + output = Region (mp_delegate->pull_interacting (other)); +} + } namespace tl diff --git a/src/db/db/dbTexts.h b/src/db/db/dbTexts.h index 173ce1e25..e087b3432 100644 --- a/src/db/db/dbTexts.h +++ b/src/db/db/dbTexts.h @@ -447,6 +447,52 @@ public: return Texts (mp_delegate->filtered (filter)); } + /** + * @brief Selects all polygons of the other region set which include the texts of this text collection + * + * Merged semantics applies for the other region. Merged polygons will be selected from the other region + * if merged semantics is enabled. + */ + void pull_interacting (Region &output, const Region &other) const; + + /** + * @brief Selects all texts of this text set which are inside the polygons from the region + */ + Texts &select_interacting (const Region &other) + { + set_delegate (mp_delegate->selected_interacting (other)); + return *this; + } + + /** + * @brief Returns all texts of this text set which are inside the polygons from the region + * + * This method is an out-of-place version of select_interacting. + */ + Texts selected_interacting (const Region &other) const + { + return Texts (mp_delegate->selected_interacting (other)); + } + + /** + * @brief Selects all texts of this text set which are not inside the polygons from the region + */ + Texts &select_not_interacting (const Region &other) + { + set_delegate (mp_delegate->selected_not_interacting (other)); + return *this; + } + + /** + * @brief Returns all texts of this text set which are not inside the polygons from the region + * + * This method is an out-of-place version of select_not_interacting. + */ + Texts selected_not_interacting (const Region &other) const + { + return Texts (mp_delegate->selected_not_interacting (other)); + } + /** * @brief Transforms the text set */ diff --git a/src/db/db/dbTextsDelegate.h b/src/db/db/dbTextsDelegate.h index d25eef6a3..29f9a2c72 100644 --- a/src/db/db/dbTextsDelegate.h +++ b/src/db/db/dbTextsDelegate.h @@ -33,6 +33,7 @@ namespace db { class RecursiveShapeIterator; class Texts; +class Region; class TextFilterBase; class RegionDelegate; class EdgesDelegate; @@ -118,6 +119,10 @@ public: virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const = 0; virtual void insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const = 0; + virtual RegionDelegate *pull_interacting (const Region &) const = 0; + virtual TextsDelegate *selected_interacting (const Region &other) const = 0; + virtual TextsDelegate *selected_not_interacting (const Region &other) const = 0; + protected: const std::string &progress_desc () const { diff --git a/src/db/db/dbTextsUtils.h b/src/db/db/dbTextsUtils.h index 5b604f89f..4f72c23c9 100644 --- a/src/db/db/dbTextsUtils.h +++ b/src/db/db/dbTextsUtils.h @@ -25,7 +25,10 @@ #include "dbCommon.h" #include "dbTexts.h" +#include "dbBoxScanner.h" +#include "dbPolygonTools.h" #include "tlGlobPattern.h" +#include "tlSelect.h" namespace db { @@ -149,6 +152,44 @@ private: bool m_inverse; }; +/** + * @brief A helper class for the text to region interaction functionality which acts as an text receiver + * + * Note: This special scanner uses pointers to two different objects: texts and polygons. + * It uses odd value pointers to indicate pointers to polygons and even value pointers to indicate + * pointers to edges. + * + * There is a special box converter which is able to sort that out as well. + */ +template +class text_to_region_interaction_filter + : public db::box_scanner_receiver2 +{ +public: + text_to_region_interaction_filter (OutputContainer &output) + : mp_output (&output) + { + // .. nothing yet .. + } + + void add (const db::Text *t, size_t, const db::Polygon *p, size_t) + { + const OutputType *tt = 0; + tl::select (tt, t, p); + + if (m_seen.find (tt) == m_seen.end ()) { + if (db::interact (*p, *t)) { + m_seen.insert (tt); + mp_output->insert (*tt); + } + } + } + +private: + OutputContainer *mp_output; + std::set m_seen; +}; + } // namespace db #endif diff --git a/src/db/db/gsiDeclDbEdges.cc b/src/db/db/gsiDeclDbEdges.cc index 2d375fc40..0eaf6dcff 100644 --- a/src/db/db/gsiDeclDbEdges.cc +++ b/src/db/db/gsiDeclDbEdges.cc @@ -426,13 +426,13 @@ Class dec_Edges ("db", "Edges", constructor ("new", &new_a1, gsi::arg ("array"), "@brief Constructor from a polygon array\n" "\n" - "This constructor creates a region from an array of polygons.\n" + "This constructor creates an edge collection from an array of polygons.\n" "The edges form the contours of the polygons.\n" ) + constructor ("new", &new_a2, gsi::arg ("array"), "@brief Constructor from an edge array\n" "\n" - "This constructor creates a region from an array of edges.\n" + "This constructor creates an edge collection from an array of edges.\n" ) + constructor ("new", &new_b, gsi::arg ("box"), "@brief Box constructor\n" @@ -859,7 +859,7 @@ Class dec_Edges ("db", "Edges", method ("interacting", (db::Edges (db::Edges::*) (const db::Edges &) const) &db::Edges::selected_interacting, gsi::arg ("other"), "@brief Returns the edges of this edge collection which overlap or touch edges from the other edge collection\n" "\n" - "@return A new edge collection containing the edges overlapping or touching edges from the other region\n" + "@return A new edge collection containing the edges overlapping or touching edges from the other edge collection\n" "\n" "This method does not merge the edges before they are selected. If you want to select coherent " "edges, make sure the edge collection is merged before this method is used.\n" @@ -867,7 +867,7 @@ Class dec_Edges ("db", "Edges", method ("not_interacting", (db::Edges (db::Edges::*) (const db::Edges &) const) &db::Edges::selected_not_interacting, gsi::arg ("other"), "@brief Returns the edges of this edge collection which do not overlap or touch edges from the other edge collection\n" "\n" - "@return A new edge collection containing the edges not overlapping or touching edges from the other region\n" + "@return A new edge collection containing the edges not overlapping or touching edges from the other edge collection\n" "\n" "This method does not merge the edges before they are selected. If you want to select coherent " "edges, make sure the edge collection is merged before this method is used.\n" @@ -889,7 +889,7 @@ Class dec_Edges ("db", "Edges", "edges, make sure the edge collection is merged before this method is used.\n" ) + method ("interacting", (db::Edges (db::Edges::*) (const db::Region &) const) &db::Edges::selected_interacting, gsi::arg ("other"), - "@brief Returns the edges from this region which overlap or touch polygons from the region\n" + "@brief Returns the edges from this edge collection which overlap or touch polygons from the region\n" "\n" "@return A new edge collection containing the edges overlapping or touching polygons from the region\n" "\n" @@ -897,7 +897,7 @@ Class dec_Edges ("db", "Edges", "edges, make sure the edge collection is merged before this method is used.\n" ) + method ("not_interacting", (db::Edges (db::Edges::*) (const db::Region &) const) &db::Edges::selected_not_interacting, gsi::arg ("other"), - "@brief Returns the edges from this region which do not overlap or touch polygons from the region\n" + "@brief Returns the edges from this edge collection which do not overlap or touch polygons from the region\n" "\n" "@return A new edge collection containing the edges not overlapping or touching polygons from the region\n" "\n" @@ -905,7 +905,7 @@ Class dec_Edges ("db", "Edges", "edges, make sure the edge collection is merged before this method is used.\n" ) + method ("select_interacting", (db::Edges &(db::Edges::*) (const db::Region &)) &db::Edges::select_interacting, gsi::arg ("other"), - "@brief Selects the edges from this region which overlap or touch polygons from the region\n" + "@brief Selects the edges from this edge collection which overlap or touch polygons from the region\n" "\n" "@return The edge collection after the edges have been selected (self)\n" "\n" @@ -913,7 +913,7 @@ Class dec_Edges ("db", "Edges", "edges, make sure the edge collection is merged before this method is used.\n" ) + method ("select_not_interacting", (db::Edges &(db::Edges::*) (const db::Region &)) &db::Edges::select_not_interacting, gsi::arg ("other"), - "@brief Selects the edges from this region which do not overlap or touch polygons from the region\n" + "@brief Selects the edges from this edge collection which do not overlap or touch polygons from the region\n" "\n" "@return The edge collection after the edges have been selected (self)\n" "\n" diff --git a/src/db/db/gsiDeclDbTexts.cc b/src/db/db/gsiDeclDbTexts.cc index 749bcfbc3..9ea593ac3 100644 --- a/src/db/db/gsiDeclDbTexts.cc +++ b/src/db/db/gsiDeclDbTexts.cc @@ -165,6 +165,13 @@ static db::Texts with_match (const db::Texts *r, const std::string &pattern, boo return r->filtered (f); } +static db::Region pull_interacting (const db::Texts *r, const db::Region &other) +{ + db::Region out; + r->pull_interacting (out, other); + return out; +} + Class decl_Texts ("db", "Texts", constructor ("new", &new_v, "@brief Default constructor\n" @@ -397,6 +404,41 @@ Class decl_Texts ("db", "Texts", "If \"inverse\" is false, this method returns the texts matching the pattern.\n" "If \"inverse\" is true, this method returns the texts not matching the pattern.\n" ) + + method ("interacting", (db::Edges (db::Edges::*) (const db::Region &) const) &db::Edges::selected_interacting, gsi::arg ("other"), + "@brief Returns the texts from this text collection which are inside or on the edge of polygons from the given region\n" + "\n" + "@return A new text collection containing the texts inside or on the edge of polygons from the region\n" + ) + + method ("not_interacting", (db::Edges (db::Edges::*) (const db::Region &) const) &db::Edges::selected_not_interacting, gsi::arg ("other"), + "@brief Returns the texts from this text collection which are not inside or on the edge of polygons from the given region\n" + "\n" + "@return A new text collection containing the texts not inside or on the edge of polygons from the region\n" + ) + + method ("select_interacting", (db::Edges &(db::Edges::*) (const db::Region &)) &db::Edges::select_interacting, gsi::arg ("other"), + "@brief Selects the texts from this text collection which are inside or on the edge of polygons from the given region\n" + "\n" + "@return A text collection after the texts have been selected (self)\n" + "\n" + "In contrast to \\interacting, this method will modify self.\n" + ) + + method ("select_not_interacting", (db::Edges &(db::Edges::*) (const db::Region &)) &db::Edges::select_not_interacting, gsi::arg ("other"), + "@brief Selects the texts from this text collection which are not inside or on the edge of polygons from the given region\n" + "\n" + "@return A text collection after the texts have been selected (self)\n" + "\n" + "In contrast to \\interacting, this method will modify self.\n" + ) + + method_ext ("pull_interacting", &pull_interacting, gsi::arg ("other"), + "@brief Returns all polygons of \"other\" which are including texts of this text set\n" + "The \"pull_...\" method is similar to \"select_...\" but works the opposite way: it " + "selects shapes from the argument region rather than self. In a deep (hierarchical) context " + "the output region will be hierarchically aligned with self, so the \"pull_...\" method " + "provide a way for rehierarchisation.\n" + "\n" + "@return The region after the polygons have been selected (from other)\n" + "\n" + "Merged semantics applies for the polygon region.\n" + ) + method ("clear", &db::Texts::clear, "@brief Clears the text collection\n" ) + diff --git a/src/db/unit_tests/dbDeepTextsTests.cc b/src/db/unit_tests/dbDeepTextsTests.cc index 78586ed3e..0c30659ab 100644 --- a/src/db/unit_tests/dbDeepTextsTests.cc +++ b/src/db/unit_tests/dbDeepTextsTests.cc @@ -83,3 +83,63 @@ TEST(1_Basics) CHECKPOINT(); db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_texts_au1.gds"); } + +TEST(2_Interactions) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/deep_texts_l2.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly); + } + + db::cell_index_type top_cell_index = *ly.begin_top_down (); + db::Cell &top_cell = ly.cell (top_cell_index); + + db::DeepShapeStore dss; + + unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0)); + unsigned int l8 = ly.get_layer (db::LayerProperties (8, 0)); + + db::Texts texts2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss); + db::Region polygons8 (db::RecursiveShapeIterator (ly, top_cell, l8), dss); + + db::Layout target; + unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index)); + + db::Region polygons; + texts2.selected_interacting (polygons8).polygons (polygons); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), polygons); + + polygons.clear (); + texts2.selected_not_interacting (polygons8).polygons (polygons); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), polygons); + + { + db::Texts texts2_copy = texts2; + texts2_copy.select_interacting (polygons8); + polygons.clear (); + texts2_copy.polygons (polygons); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), polygons); + } + + { + db::Texts texts2_copy = texts2; + texts2_copy.select_not_interacting (polygons8); + polygons.clear (); + texts2_copy.polygons (polygons); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), polygons); + } + + { + db::Texts texts2_copy = texts2; + db::Region polygons; + texts2_copy.pull_interacting (polygons, polygons8); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), polygons); + } + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_texts_au2.gds"); +} diff --git a/testdata/algo/deep_texts_au1.gds b/testdata/algo/deep_texts_au1.gds index ed1dcab44d6c52186e2a22f74f20f40ec3dc3709..6efbcec7924d7616030e7cc850398bfe433c68eb 100644 GIT binary patch delta 138 zcmcb>Hi2DYWXX)yu-TKW&< delta 126 zcmbQhet}JifsKKQDS|UY_|ewxkkcm12w3*2cd=Q^cfc6%%UG+7wf&*>n{UK@cGzLU(O< zE(FJ%EzIN>NuitMTe|PP*o8MkMANKb8 zy8dSK{JH7*g%BF85Sl~Xp+7XA?hYZm`b>fO=2+L|5abucr*E8J$e!WvSgr@Ev2G89FnmM20e&YqR6(BKNOJv%zHv+Sjh|Hi zKl1#RrRT~d8S(HrmTyAG>9qUgJhs6L|Tjd%5jK2?20 z(I5Iu^$|sHysKaMLG=+uzwo2#BZ}U5S3fnN`iP>R8d7~k(HrmT_dT!rh@#*3g6boR z-gsAk^k>ya6#da(R3B0F##i-~8z6+G`>Ky9`lW}ek0^TMtNQe|e*F5a=sT+4MBhRE zCi)KQH_>-czlpws`c3p5)Ni8ipnem52lboiJE-5}2JfJLlN<0Ac?<^8*O`#=H9I6@3l}{aO1RAoRw&diaa?1dM&ZRU*#?UH#ao#>u`# zz2f~HSmt>|SD*L)r5V*Y|`#L8@BYB5Do!@#czvJrj`pfgzuKsfWIR`iw+WDW)Pdtw}_`Alt{-yL3_ju29?hsKw?e2fhdCvXZ zzVWXAi(6X1K-wk3zVWU;-+%J{G2YdqUSS6ayZfbnh&&f`^{6{M$NzGL`h%Wx-FR2O zxTW=rI8lFj{~7P<^ZMZ)$+_6Bey}&de<1Tt#eje}7=^X#AKzh@W|2UW|AB$G!(Yx%cJq8}I5_ zXF&MPKD54z@1w5%xaV^3&HLYY*FN?Y88@vfeA#=7Ho4BxBqt{&gp$REGE z^ZXg_>ht-*Im*7QpC9FS3cnxn{I&ajI4ykx|A9O0@5a0SPuO=7`yTTbb$D`3>(Y2v zk9`I9xwqu`Gv3w19^O9?^*7flk>_>w$3A7>G7lDa+wV`t$+%%3@z1q1e&eJ6@_%p| Gjqo1@^43lO literal 0 HcmV?d00001 diff --git a/testdata/algo/deep_texts_l2.gds b/testdata/algo/deep_texts_l2.gds new file mode 100644 index 0000000000000000000000000000000000000000..4db693c1a7c752b0a923420345f4b35b13ad2cf6 GIT binary patch literal 2986 zcma);K}Zx~6vyAp?tU}7uBK*1AyHCLU>0dcNTRltqG-6A)FSAyOAsUxQ6ZFINf6Y@ zI!KTmyhIQPdWwkf)G;W+L)Sp4i%ahGfAh_AW)^2mSbxj=-v4`VzW2U2ONvbM3N;$0 z^^;OmO?9-3I)dNHHq}614^cxR)!F^%bpNL}YiDwc$LC%Y3)Gm3)@76`40jLaiIO&v zsy4|aRbvuSb8W(LHf}ji`7o2n_(o(t7K)uo$vWt>oBG|XS9=VyDa*S!FR}cV?7eE> zBy!x&dm3u!*<1U1nI(gnl}$um!3T8a!5==wUS5gQBSw++c%pXJ`xHABqxA4?f@Ve2 znFq@pUsLSS@ma_5HH~)G;p0*474cQ@`8Spk{~;=~4BcJCJ|q-7Gn9WokJ#Vcb&z$a zY)&Y4U!T^MO?dIuL9Va8BZ2=VYN%zBz1Cc)!tmiiwus`}j*Jc4m|wC%V&J2U&;s)k3ky>$!iCpWDZhw@~bH z`LB@E(??q3Lv-(lnms15xU>Q0&Y&J?hn>_1Sk?FBE&a zC8RgP@wrd5zUHge3&oB;a(fyc{{&hL(9as}ocoxBU31?E{?8lBV+>b-ah~9>rc>iqk{W&wAv3p7lP(PW|!v^n%uBUTeKj z?CFJgeN~6nXHRLpQ0!G5S|6H-hJH8l)I@#ow(A=Vd0}Q?Zn|EZ(*SSKq00pnh~Kx{ z%t5@_hx-OE4#5-C%&yl{(Vb$*lK*55hSoBdqSqScqSyAXMXw$0ie76CPt;H@XIG+)!y=vk4{d+OC27jCDG?YK*)oCj~uDQNt f7kc#5M0vpxyN%@Y+w6unJp1Kxo*!;wGD-gcN)}f_ literal 0 HcmV?d00001 From 16d6c75b0e23de14c411810cda74060dc37d58cd Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 13 May 2020 17:58:00 +0200 Subject: [PATCH 07/35] Fixed build, added tests for filter in deep texts object. --- src/db/db/dbAsIfFlatEdges.cc | 10 ++++++++ src/db/db/dbAsIfFlatEdges.h | 3 +-- src/db/db/dbAsIfFlatRegion.cc | 11 ++++++++ src/db/db/dbAsIfFlatRegion.h | 3 ++- src/db/db/dbAsIfFlatTexts.cc | 10 ++++++++ src/db/db/dbAsIfFlatTexts.h | 2 +- src/db/db/dbDeepEdges.cc | 19 ++++++++++++++ src/db/db/dbDeepRegion.cc | 19 ++++++++++++++ src/db/db/dbDeepTexts.cc | 10 ++++++++ src/db/db/dbLayout.cc | 9 +++++++ src/db/db/dbLayout.h | 10 ++++++++ src/db/db/gsiDeclDbLayout.cc | 27 ++++++++++++++++++++ src/db/unit_tests/dbDeepTextsTests.cc | 35 ++++++++++++++++++++++++++ testdata/algo/deep_texts_au3.gds | Bin 0 -> 874 bytes testdata/algo/deep_texts_l3.gds | Bin 0 -> 2986 bytes 15 files changed, 164 insertions(+), 4 deletions(-) create mode 100644 testdata/algo/deep_texts_au3.gds create mode 100644 testdata/algo/deep_texts_l3.gds diff --git a/src/db/db/dbAsIfFlatEdges.cc b/src/db/db/dbAsIfFlatEdges.cc index 26bfe7689..9cb62ba1a 100644 --- a/src/db/db/dbAsIfFlatEdges.cc +++ b/src/db/db/dbAsIfFlatEdges.cc @@ -59,6 +59,16 @@ AsIfFlatEdges::~AsIfFlatEdges () // .. nothing yet .. } +AsIfFlatEdges & +AsIfFlatEdges::operator= (const AsIfFlatEdges &other) +{ + if (this != &other) { + m_bbox_valid = other.m_bbox_valid; + m_bbox = other.m_bbox; + } + return *this; +} + std::string AsIfFlatEdges::to_string (size_t nmax) const { diff --git a/src/db/db/dbAsIfFlatEdges.h b/src/db/db/dbAsIfFlatEdges.h index 7a94c35c5..55c79ade0 100644 --- a/src/db/db/dbAsIfFlatEdges.h +++ b/src/db/db/dbAsIfFlatEdges.h @@ -185,10 +185,9 @@ protected: virtual RegionDelegate *pull_generic (const Region ®ion) const; virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, bool inverse) const; virtual EdgesDelegate *selected_interacting_generic (const Region ®ion, bool inverse) const; - -private: AsIfFlatEdges &operator= (const AsIfFlatEdges &other); +private: mutable bool m_bbox_valid; mutable db::Box m_bbox; diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index 0a9278df1..37481614e 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -55,6 +55,17 @@ AsIfFlatRegion::~AsIfFlatRegion () // .. nothing yet .. } +AsIfFlatRegion & +AsIfFlatRegion::operator= (const AsIfFlatRegion &other) +{ + if (this != &other) { + m_bbox_valid = other.m_bbox_valid; + m_bbox = other.m_bbox; + } + + return *this; +} + std::string AsIfFlatRegion::to_string (size_t nmax) const { diff --git a/src/db/db/dbAsIfFlatRegion.h b/src/db/db/dbAsIfFlatRegion.h index ed232d858..fb3a1c548 100644 --- a/src/db/db/dbAsIfFlatRegion.h +++ b/src/db/db/dbAsIfFlatRegion.h @@ -255,9 +255,10 @@ protected: template static void produce_markers_for_angle_check (const db::Polygon &poly, const Trans &tr, double min, double max, bool inverse, db::Shapes &shapes); -private: AsIfFlatRegion &operator= (const AsIfFlatRegion &other); +private: + mutable bool m_bbox_valid; mutable db::Box m_bbox; diff --git a/src/db/db/dbAsIfFlatTexts.cc b/src/db/db/dbAsIfFlatTexts.cc index d3b67790d..df65c4a25 100644 --- a/src/db/db/dbAsIfFlatTexts.cc +++ b/src/db/db/dbAsIfFlatTexts.cc @@ -51,6 +51,16 @@ AsIfFlatTexts::~AsIfFlatTexts () // .. nothing yet .. } +AsIfFlatTexts & +AsIfFlatTexts::operator= (const AsIfFlatTexts &other) +{ + if (this != &other) { + m_bbox_valid = other.m_bbox_valid; + m_bbox = other.m_bbox; + } + return *this; +} + std::string AsIfFlatTexts::to_string (size_t nmax) const { diff --git a/src/db/db/dbAsIfFlatTexts.h b/src/db/db/dbAsIfFlatTexts.h index f10d7bdea..b0f4611fe 100644 --- a/src/db/db/dbAsIfFlatTexts.h +++ b/src/db/db/dbAsIfFlatTexts.h @@ -78,9 +78,9 @@ public: protected: void update_bbox (const db::Box &box); void invalidate_bbox (); + AsIfFlatTexts &operator= (const AsIfFlatTexts &other); private: - AsIfFlatTexts &operator= (const AsIfFlatTexts &other); mutable bool m_bbox_valid; mutable db::Box m_bbox; diff --git a/src/db/db/dbDeepEdges.cc b/src/db/db/dbDeepEdges.cc index fd99ab58a..d8371e563 100644 --- a/src/db/db/dbDeepEdges.cc +++ b/src/db/db/dbDeepEdges.cc @@ -145,6 +145,25 @@ DeepEdges::DeepEdges (const DeepEdges &other) } } +DeepEdges & +DeepEdges::operator= (const DeepEdges &other) +{ + if (this != &other) { + + AsIfFlatEdges::operator= (other); + + m_deep_layer = other.m_deep_layer.copy (); + m_merged_edges_valid = other.m_merged_edges_valid; + m_is_merged = other.m_is_merged; + if (m_merged_edges_valid) { + m_merged_edges = other.m_merged_edges; + } + + } + + return *this; +} + void DeepEdges::init () { m_merged_edges_valid = false; diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index 893eba147..f56fc2be6 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -150,6 +150,25 @@ DeepRegion::DeepRegion (const DeepRegion &other) } } +DeepRegion & +DeepRegion::operator= (const DeepRegion &other) +{ + if (this != &other) { + + AsIfFlatRegion::operator= (other); + + m_deep_layer = other.m_deep_layer.copy (); + m_merged_polygons_valid = other.m_merged_polygons_valid; + m_is_merged = other.m_is_merged; + if (m_merged_polygons_valid) { + m_merged_polygons = other.m_merged_polygons; + } + + } + + return *this; +} + void DeepRegion::init () { m_merged_polygons_valid = false; diff --git a/src/db/db/dbDeepTexts.cc b/src/db/db/dbDeepTexts.cc index 3145b2bf3..1def0413e 100644 --- a/src/db/db/dbDeepTexts.cc +++ b/src/db/db/dbDeepTexts.cc @@ -115,6 +115,16 @@ DeepTexts::DeepTexts (const DeepTexts &other) // .. nothing yet .. } +DeepTexts & +DeepTexts::operator= (const DeepTexts &other) +{ + if (this != &other) { + AsIfFlatTexts::operator= (other); + m_deep_layer = other.m_deep_layer.copy (); + } + return *this; +} + DeepTexts::DeepTexts (const DeepLayer &dl) : AsIfFlatTexts (), m_deep_layer (dl) { diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index c82051019..b4e626d99 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -32,6 +32,9 @@ #include "dbLibraryManager.h" #include "dbLibrary.h" #include "dbRegion.h" +#include "dbEdgePairs.h" +#include "dbEdges.h" +#include "dbTexts.h" #include "tlTimer.h" #include "tlLog.h" #include "tlInternational.h" @@ -661,6 +664,12 @@ Layout::insert (db::cell_index_type cell, int layer, const db::EdgePairs &edge_p edge_pairs.insert_into (this, cell, layer); } +void +Layout::insert (db::cell_index_type cell, int layer, const db::Texts &texts) +{ + texts.insert_into (this, cell, layer); +} + void Layout::flatten (const db::Cell &source_cell, db::Cell &target_cell, const db::ICplxTrans &t, int levels) { diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h index 670248cbc..dd39be48e 100644 --- a/src/db/db/dbLayout.h +++ b/src/db/db/dbLayout.h @@ -66,6 +66,7 @@ class LayerMapping; class Region; class Edges; class EdgePairs; +class Texts; template class generic_repository; typedef generic_repository GenericRepository; @@ -1123,6 +1124,15 @@ public: */ void insert (db::cell_index_type cell, int layer, const db::EdgePairs &edge_pairs); + /** + * @brief Inserts a text collection (potentially hierarchical) into the given cell and layer + * + * If the text collection is flat (conceptionally), it will be put into the cell. + * If the text collection is hierarchical, a cell hierarchy will be built below the + * given cell. + */ + void insert (db::cell_index_type cell, int layer, const db::Texts &texts); + /** * @brief Delete a cell plus all subcells * diff --git a/src/db/db/gsiDeclDbLayout.cc b/src/db/db/gsiDeclDbLayout.cc index 685dfbd22..d6d5c9975 100644 --- a/src/db/db/gsiDeclDbLayout.cc +++ b/src/db/db/gsiDeclDbLayout.cc @@ -33,6 +33,9 @@ #include "dbPCellDeclaration.h" #include "dbHash.h" #include "dbRegion.h" +#include "dbEdges.h" +#include "dbEdgePairs.h" +#include "dbTexts.h" #include "dbLayoutUtils.h" #include "tlStream.h" @@ -1188,6 +1191,30 @@ Class decl_Layout ("db", "Layout", "\n" "This method has been introduced in version 0.26.\n" ) + + gsi::method ("insert", (void (db::Layout::*) (db::cell_index_type, int, const db::EdgePairs &)) &db::Layout::insert, + gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("edge_pairs"), + "@brief Inserts an edge pair collection into the given cell and layer\n" + "If the edge pair collection is (conceptionally) flat, it will be inserted into the cell's shapes " + "list as a flat sequence of edge pairs.\n" + "If the edge pair collection is deep (hierarchical), it will create a subhierarchy below the given " + "cell and it's edge pairs will be put into the respective cells. Suitable subcells will be picked " + "for inserting the edge pairs. If a hierarchy already exists below the given cell, the algorithm will " + "try to reuse this hierarchy.\n" + "\n" + "This method has been introduced in version 0.27.\n" + ) + + gsi::method ("insert", (void (db::Layout::*) (db::cell_index_type, int, const db::Texts &)) &db::Layout::insert, + gsi::arg ("cell_index"), gsi::arg ("layer"), gsi::arg ("texts"), + "@brief Inserts an text collection into the given cell and layer\n" + "If the text collection is (conceptionally) flat, it will be inserted into the cell's shapes " + "list as a flat sequence of texts.\n" + "If the text collection is deep (hierarchical), it will create a subhierarchy below the given " + "cell and it's texts will be put into the respective cells. Suitable subcells will be picked " + "for inserting the texts. If a hierarchy already exists below the given cell, the algorithm will " + "try to reuse this hierarchy.\n" + "\n" + "This method has been introduced in version 0.27.\n" + ) + gsi::method_ext ("flatten", &flatten, gsi::arg ("cell_index"), gsi::arg ("levels"), gsi::arg ("prune"), "@brief Flattens the given cell\n" "\n" diff --git a/src/db/unit_tests/dbDeepTextsTests.cc b/src/db/unit_tests/dbDeepTextsTests.cc index 0c30659ab..a833feb89 100644 --- a/src/db/unit_tests/dbDeepTextsTests.cc +++ b/src/db/unit_tests/dbDeepTextsTests.cc @@ -28,6 +28,7 @@ #include "dbDeepShapeStore.h" #include "dbRegion.h" #include "dbEdges.h" +#include "dbTextsUtils.h" #include "tlUnitTest.h" #include "tlStream.h" @@ -143,3 +144,37 @@ TEST(2_Interactions) CHECKPOINT(); db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_texts_au2.gds"); } + +TEST(3_Filtering) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/deep_texts_l3.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly); + } + + db::cell_index_type top_cell_index = *ly.begin_top_down (); + db::Cell &top_cell = ly.cell (top_cell_index); + + db::DeepShapeStore dss; + + unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0)); + + db::Texts texts2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss); + + 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)), texts2.filtered (db::TextStringFilter ("L2", false))); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), texts2.filtered (db::TextStringFilter ("L2", true))); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), texts2.filtered (db::TextPatternFilter ("L*A", false))); + + texts2.filter (db::TextPatternFilter ("L*A", true)); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), texts2); + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_texts_au3.gds"); +} diff --git a/testdata/algo/deep_texts_au3.gds b/testdata/algo/deep_texts_au3.gds new file mode 100644 index 0000000000000000000000000000000000000000..766da2bcc1d87e73722697a5550624b19d1e74b1 GIT binary patch literal 874 zcmZQzV_;&6V31*CVt>NG%D~GY$Y8<1i_B)=U}E#}bYfr-VP>^+>@@d2w)}&o%MSeo zv!g;7WLRhA33BucW?*39VPIh6Wn$oBU=w3v0J6my88{et1epK-|K9=R14Sg+ ze2f@a1QBYvv8bH`l-|I=0a6Qe53*`ridAE{gPj4d?>N}lJpICeZsuZO;1YuQ6zr#e z1zjT8~D6(u)j13H+P+?$ToPfgwG&L}D2)Gp(6G5JS?*70q1KP+T1aUdo zCa^uwutb;R3P5oMiawDAxaH(N;Fi;Lz%6Ht>T4AHY#-p(=V5?bE~o*wT+9W895jVu cOLZl{Ksv19S@dNheb6oc34;#0LQ~(TmS$7 literal 0 HcmV?d00001 diff --git a/testdata/algo/deep_texts_l3.gds b/testdata/algo/deep_texts_l3.gds new file mode 100644 index 0000000000000000000000000000000000000000..4db693c1a7c752b0a923420345f4b35b13ad2cf6 GIT binary patch literal 2986 zcma);K}Zx~6vyAp?tU}7uBK*1AyHCLU>0dcNTRltqG-6A)FSAyOAsUxQ6ZFINf6Y@ zI!KTmyhIQPdWwkf)G;W+L)Sp4i%ahGfAh_AW)^2mSbxj=-v4`VzW2U2ONvbM3N;$0 z^^;OmO?9-3I)dNHHq}614^cxR)!F^%bpNL}YiDwc$LC%Y3)Gm3)@76`40jLaiIO&v zsy4|aRbvuSb8W(LHf}ji`7o2n_(o(t7K)uo$vWt>oBG|XS9=VyDa*S!FR}cV?7eE> zBy!x&dm3u!*<1U1nI(gnl}$um!3T8a!5==wUS5gQBSw++c%pXJ`xHABqxA4?f@Ve2 znFq@pUsLSS@ma_5HH~)G;p0*474cQ@`8Spk{~;=~4BcJCJ|q-7Gn9WokJ#Vcb&z$a zY)&Y4U!T^MO?dIuL9Va8BZ2=VYN%zBz1Cc)!tmiiwus`}j*Jc4m|wC%V&J2U&;s)k3ky>$!iCpWDZhw@~bH z`LB@E(??q3Lv-(lnms15xU>Q0&Y&J?hn>_1Sk?FBE&a zC8RgP@wrd5zUHge3&oB;a(fyc{{&hL(9as}ocoxBU31?E{?8lBV+>b-ah~9>rc>iqk{W&wAv3p7lP(PW|!v^n%uBUTeKj z?CFJgeN~6nXHRLpQ0!G5S|6H-hJH8l)I@#ow(A=Vd0}Q?Zn|EZ(*SSKq00pnh~Kx{ z%t5@_hx-OE4#5-C%&yl{(Vb$*lK*55hSoBdqSqScqSyAXMXw$0ie76CPt;H@XIG+)!y=vk4{d+OC27jCDG?YK*)oCj~uDQNt f7kc#5M0vpxyN%@Y+w6unJp1Kxo*!;wGD-gcN)}f_ literal 0 HcmV?d00001 From 831acb2c40b21c37235050b361ba90eaf493fe80 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 13 May 2020 18:25:43 +0200 Subject: [PATCH 08/35] Bugfixes, tests for flat interact between region and texts. --- src/db/db/dbAsIfFlatEdgePairs.cc | 2 +- src/db/db/dbAsIfFlatTexts.cc | 4 ++-- src/db/unit_tests/dbTextsTests.cc | 29 +++++++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/db/db/dbAsIfFlatEdgePairs.cc b/src/db/db/dbAsIfFlatEdgePairs.cc index bac1a9495..4ed4ee3e9 100644 --- a/src/db/db/dbAsIfFlatEdgePairs.cc +++ b/src/db/db/dbAsIfFlatEdgePairs.cc @@ -75,7 +75,7 @@ AsIfFlatEdgePairs::in (const EdgePairs &other, bool invert) const op.insert (*o); } - std::auto_ptr new_edge_pairs (new FlatEdgePairs (false)); + std::auto_ptr new_edge_pairs (new FlatEdgePairs ()); for (EdgePairsIterator o (begin ()); ! o.at_end (); ++o) { if ((op.find (*o) == op.end ()) == invert) { diff --git a/src/db/db/dbAsIfFlatTexts.cc b/src/db/db/dbAsIfFlatTexts.cc index df65c4a25..4bad031a1 100644 --- a/src/db/db/dbAsIfFlatTexts.cc +++ b/src/db/db/dbAsIfFlatTexts.cc @@ -88,7 +88,7 @@ AsIfFlatTexts::in (const Texts &other, bool invert) const op.insert (*o); } - std::auto_ptr new_texts (new FlatTexts (false)); + std::auto_ptr new_texts (new FlatTexts ()); for (TextsIterator o (begin ()); ! o.at_end (); ++o) { if ((op.find (*o) == op.end ()) == invert) { @@ -308,7 +308,7 @@ AsIfFlatTexts::selected_interacting_generic (const Region &other, bool inverse) scanner.insert2 (p.operator-> (), 1); } - std::auto_ptr output (new FlatTexts (true)); + std::auto_ptr output (new FlatTexts ()); if (! inverse) { diff --git a/src/db/unit_tests/dbTextsTests.cc b/src/db/unit_tests/dbTextsTests.cc index 609de5876..e99bb6960 100644 --- a/src/db/unit_tests/dbTextsTests.cc +++ b/src/db/unit_tests/dbTextsTests.cc @@ -173,3 +173,32 @@ TEST(6) db::Texts r (db::RecursiveShapeIterator (ly, ly.cell (top_cell), l1)); EXPECT_EQ (r.to_string (), "('abc',r0 100,-200);('uvw',r0 110,210)"); } + +TEST(7) +{ + db::Texts texts; + texts.insert (db::Text ("abc", db::Trans (db::Vector (100, -200)))); + texts.insert (db::Text ("uvw", db::Trans (db::Vector (110, 210)))); + + db::Region region; + region.insert (db::Polygon (db::Box (50, -300, 150, -100))); + + EXPECT_EQ (texts.selected_interacting (region).to_string (), "('abc',r0 100,-200)"); + EXPECT_EQ (texts.selected_not_interacting (region).to_string (), "('uvw',r0 110,210)"); + + { + db::Texts tcopy = texts; + tcopy.select_interacting (region); + EXPECT_EQ (tcopy.to_string (), "('abc',r0 100,-200)"); + } + + { + db::Texts tcopy = texts; + tcopy.select_not_interacting (region); + EXPECT_EQ (tcopy.to_string (), "('uvw',r0 110,210)"); + } + + db::Region region_out; + texts.pull_interacting (region_out, region); + EXPECT_EQ (region_out.to_string (), "(50,-300;50,-100;150,-100;150,-300)"); +} From 58ca9b87307ca2dee3847601465fd64548ff3f49 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 13 May 2020 21:56:49 +0200 Subject: [PATCH 09/35] Some bug fixes, added tests --- src/db/db/gsiDeclDbTexts.cc | 8 ++++---- testdata/ruby/dbTextsTest.rb | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/db/db/gsiDeclDbTexts.cc b/src/db/db/gsiDeclDbTexts.cc index 9ea593ac3..4088142f8 100644 --- a/src/db/db/gsiDeclDbTexts.cc +++ b/src/db/db/gsiDeclDbTexts.cc @@ -404,24 +404,24 @@ Class decl_Texts ("db", "Texts", "If \"inverse\" is false, this method returns the texts matching the pattern.\n" "If \"inverse\" is true, this method returns the texts not matching the pattern.\n" ) + - method ("interacting", (db::Edges (db::Edges::*) (const db::Region &) const) &db::Edges::selected_interacting, gsi::arg ("other"), + method ("interacting", (db::Texts (db::Texts::*) (const db::Region &) const) &db::Texts::selected_interacting, gsi::arg ("other"), "@brief Returns the texts from this text collection which are inside or on the edge of polygons from the given region\n" "\n" "@return A new text collection containing the texts inside or on the edge of polygons from the region\n" ) + - method ("not_interacting", (db::Edges (db::Edges::*) (const db::Region &) const) &db::Edges::selected_not_interacting, gsi::arg ("other"), + method ("not_interacting", (db::Texts (db::Texts::*) (const db::Region &) const) &db::Texts::selected_not_interacting, gsi::arg ("other"), "@brief Returns the texts from this text collection which are not inside or on the edge of polygons from the given region\n" "\n" "@return A new text collection containing the texts not inside or on the edge of polygons from the region\n" ) + - method ("select_interacting", (db::Edges &(db::Edges::*) (const db::Region &)) &db::Edges::select_interacting, gsi::arg ("other"), + method ("select_interacting", (db::Texts &(db::Texts::*) (const db::Region &)) &db::Texts::select_interacting, gsi::arg ("other"), "@brief Selects the texts from this text collection which are inside or on the edge of polygons from the given region\n" "\n" "@return A text collection after the texts have been selected (self)\n" "\n" "In contrast to \\interacting, this method will modify self.\n" ) + - method ("select_not_interacting", (db::Edges &(db::Edges::*) (const db::Region &)) &db::Edges::select_not_interacting, gsi::arg ("other"), + method ("select_not_interacting", (db::Texts &(db::Texts::*) (const db::Region &)) &db::Texts::select_not_interacting, gsi::arg ("other"), "@brief Selects the texts from this text collection which are not inside or on the edge of polygons from the given region\n" "\n" "@return A text collection after the texts have been selected (self)\n" diff --git a/testdata/ruby/dbTextsTest.rb b/testdata/ruby/dbTextsTest.rb index 9cbb4b82c..dcd30d305 100644 --- a/testdata/ruby/dbTextsTest.rb +++ b/testdata/ruby/dbTextsTest.rb @@ -211,6 +211,8 @@ class DBTexts_TestClass < TestBase assert_equal(RBA::Texts::new(target.cell("TOP").shapes(target_li)).to_s, "") assert_equal(RBA::Texts::new(target.cell("C2").shapes(target_li)).to_s, "('abc',r0 100,-200)") + target = RBA::Layout::new + target_top = target.add_cell("TOP") target_li = target.layer r.with_text("abc", false).insert_into(target, target_top, target_li) cells = [] @@ -259,6 +261,8 @@ class DBTexts_TestClass < TestBase assert_equal(RBA::Texts::new(target.cell("TOP").shapes(target_li)).to_s, "") assert_equal(RBA::Texts::new(target.cell("C2").shapes(target_li)).to_s, "") + target = RBA::Layout::new + target_top = target.add_cell("TOP") target_li = target.layer r.insert_into_as_polygons(target, target_top, target_li, 1) cells = [] @@ -267,6 +271,38 @@ class DBTexts_TestClass < TestBase assert_equal(RBA::Region::new(target.cell("TOP").shapes(target_li)).to_s, "") assert_equal(RBA::Region::new(target.cell("C2").shapes(target_li)).to_s, "(99,-201;99,-199;101,-199;101,-201)") + target_li = target.layer + target.insert(target_top, target_li, r) + cells = [] + target.each_cell { |c| cells << c.name } + assert_equal(cells.join(","), "TOP,C2") + assert_equal(RBA::Texts::new(target.cell("TOP").shapes(target_li)).to_s, "") + assert_equal(RBA::Region::new(target.cell("TOP").shapes(target_li)).to_s, "") + assert_equal(RBA::Texts::new(target.cell("C2").shapes(target_li)).to_s, "('abc',r0 100,-200)") + assert_equal(RBA::Region::new(target.cell("C2").shapes(target_li)).to_s, "") + + end + + # interact + def test_5 + + r = RBA::Texts::new + r.insert(RBA::Text::new("abc", RBA::Trans::new(RBA::Vector::new(100, 200)))) + r.insert(RBA::Text::new("uvw", RBA::Trans::new(RBA::Vector::new(110, -210)))) + g2 = RBA::Region::new + g2.insert(RBA::Box::new(0, 100, 200, 200)) + + assert_equal(r.interacting(g2).to_s, "('abc',r0 100,200)") + assert_equal(r.not_interacting(g2).to_s, "('uvw',r0 110,-210)") + rr = r.dup + rr.select_interacting(g2) + assert_equal(rr.to_s, "('abc',r0 100,200)") + rr = r.dup + rr.select_not_interacting(g2) + assert_equal(rr.to_s, "('uvw',r0 110,-210)") + + assert_equal(r.pull_interacting(g2).to_s, "(0,100;0,200;200,200;200,100)") + end end From 8a2742d43680b91094d832566dd3fd9f610d27bf Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 13 May 2020 22:39:25 +0200 Subject: [PATCH 10/35] Small doc updates --- src/db/db/gsiDeclDbTexts.cc | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/db/db/gsiDeclDbTexts.cc b/src/db/db/gsiDeclDbTexts.cc index 4088142f8..365990f14 100644 --- a/src/db/db/gsiDeclDbTexts.cc +++ b/src/db/db/gsiDeclDbTexts.cc @@ -490,7 +490,7 @@ Class decl_Texts ("db", "Texts", ) + method_ext ("to_s", &to_string0, "@brief Converts the text collection to a string\n" - "The length of the output is limited to 20 edge pairs to avoid giant strings on large collections. " + "The length of the output is limited to 20 texts to avoid giant strings on large collections. " "For full output use \"to_s\" with a maximum count parameter.\n" ) + method_ext ("to_s", &to_string1, gsi::arg ("max_count"), @@ -500,11 +500,15 @@ Class decl_Texts ("db", "Texts", "@brief Texts (a collection of texts)\n" "\n" "Text objects are useful as labels for net names, to identify certain regions and to specify specific locations in general. " - "Text collections provide a way to store - also in a hierarchical fashion - and manipulate collection of text objects. " - "Text objects can be turned into polygons by creating small boxes around the texts. Texts can also be turned into dot-like " - "edges. Texts can be filtered by string, either by matching against a fixed string or a glob-style pattern.\n" + "Text collections provide a way to store - also in a hierarchical fashion - and manipulate collection of text objects.\n" "\n" - "Beside that, text collections can be transformed and combined, similar to \\EdgePairs.\n" + "Text objects can be turned into polygons by creating small boxes around the texts (\\polygons). Texts can also be turned into dot-like " + "edges (\\edges). Texts can be filtered by string, either by matching against a fixed string (\\with_string) or a glob-style pattern (\\with_pattern).\n" + "\n" + "Text collections can be filtered geometrically against a polygon \\Region using \\interacting or \\non-interacting. " + "Vice versa, texts can be used to select polygons from a \\Region using \\pull_interacting.\n" + "\n" + "Beside that, text collections can be transformed, flattened and combined, similar to \\EdgePairs.\n" "\n" "This class has been introduced in version 0.27.\n" ); From 878a494abbbcb7ad21ff19c0d5e315d15b759870 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 15 May 2020 22:24:18 +0200 Subject: [PATCH 11/35] AND and NOT for texts vs. region, DRC generalization. --- src/db/db/gsiDeclDbTexts.cc | 8 +- src/drc/drc/built-in-macros/_drc_engine.rb | 32 ++++-- src/drc/drc/built-in-macros/_drc_layer.rb | 118 ++++++++++++++++++--- src/drc/drc/built-in-macros/_drc_source.rb | 69 ++++++++++-- 4 files changed, 193 insertions(+), 34 deletions(-) diff --git a/src/db/db/gsiDeclDbTexts.cc b/src/db/db/gsiDeclDbTexts.cc index 365990f14..003179a9d 100644 --- a/src/db/db/gsiDeclDbTexts.cc +++ b/src/db/db/gsiDeclDbTexts.cc @@ -404,12 +404,12 @@ Class decl_Texts ("db", "Texts", "If \"inverse\" is false, this method returns the texts matching the pattern.\n" "If \"inverse\" is true, this method returns the texts not matching the pattern.\n" ) + - method ("interacting", (db::Texts (db::Texts::*) (const db::Region &) const) &db::Texts::selected_interacting, gsi::arg ("other"), + method ("interacting|&", (db::Texts (db::Texts::*) (const db::Region &) const) &db::Texts::selected_interacting, gsi::arg ("other"), "@brief Returns the texts from this text collection which are inside or on the edge of polygons from the given region\n" "\n" "@return A new text collection containing the texts inside or on the edge of polygons from the region\n" ) + - method ("not_interacting", (db::Texts (db::Texts::*) (const db::Region &) const) &db::Texts::selected_not_interacting, gsi::arg ("other"), + method ("not_interacting|-", (db::Texts (db::Texts::*) (const db::Region &) const) &db::Texts::selected_not_interacting, gsi::arg ("other"), "@brief Returns the texts from this text collection which are not inside or on the edge of polygons from the given region\n" "\n" "@return A new text collection containing the texts not inside or on the edge of polygons from the region\n" @@ -500,10 +500,10 @@ Class decl_Texts ("db", "Texts", "@brief Texts (a collection of texts)\n" "\n" "Text objects are useful as labels for net names, to identify certain regions and to specify specific locations in general. " - "Text collections provide a way to store - also in a hierarchical fashion - and manipulate collection of text objects.\n" + "Text collections provide a way to store - also in a hierarchical fashion - and manipulate a collection of text objects.\n" "\n" "Text objects can be turned into polygons by creating small boxes around the texts (\\polygons). Texts can also be turned into dot-like " - "edges (\\edges). Texts can be filtered by string, either by matching against a fixed string (\\with_string) or a glob-style pattern (\\with_pattern).\n" + "edges (\\edges). Texts can be filtered by string, either by matching against a fixed string (\\with_text) or a glob-style pattern (\\with_match).\n" "\n" "Text collections can be filtered geometrically against a polygon \\Region using \\interacting or \\non-interacting. " "Vice versa, texts can be used to select polygons from a \\Region using \\pull_interacting.\n" diff --git a/src/drc/drc/built-in-macros/_drc_engine.rb b/src/drc/drc/built-in-macros/_drc_engine.rb index 7ffcc1b28..5e1ce030d 100644 --- a/src/drc/drc/built-in-macros/_drc_engine.rb +++ b/src/drc/drc/built-in-macros/_drc_engine.rb @@ -1083,13 +1083,33 @@ module DRC # %DRC% # @name labels # @brief Gets the labels (text) from an original layer - # @synopsis labels + # @synopsis labels(args) # See \Source#labels for a description of that function. def labels(*args) layout.labels(*args) end + # %DRC% + # @name edges + # @brief Gets the edges from an original layer + # @synopsis edges(args) + # See \Source#edges for a description of that function. + + def edges(*args) + layout.edges(*args) + end + + # %DRC% + # @name edge_pairs + # @brief Gets the edges from an original layer + # @synopsis edge_pairs(args) + # See \Source#edge_pairs for a description of that function. + + def edge_pairs(*args) + layout.edge_pairs(*args) + end + # %DRC% # @name output # @brief Outputs a layer to the report database or output layout @@ -1757,11 +1777,11 @@ CODE end end - def _input(layout, cell_index, layers, sel, box, clip, overlapping, shape_flags) + def _input(layout, cell_index, layers, sel, box, clip, overlapping, shape_flags, cls) if layers.empty? && ! @deep - r = RBA::Region::new + r = cls.new else @@ -1795,13 +1815,13 @@ CODE # object which keeps the DSS. @dss.text_property_name = "LABEL" @dss.text_enlargement = 1 - r = RBA::Region::new(iter, @dss, RBA::ICplxTrans::new(sf.to_f)) + r = cls.new(iter, @dss, RBA::ICplxTrans::new(sf.to_f)) else - r = RBA::Region::new(iter, RBA::ICplxTrans::new(sf.to_f)) + r = cls.new(iter, RBA::ICplxTrans::new(sf.to_f)) end # clip if a box is specified - if box && clip + if box && clip && (cls == RBA::Region || cls == RBA::Edge) r &= RBA::Region::new(box) end diff --git a/src/drc/drc/built-in-macros/_drc_layer.rb b/src/drc/drc/built-in-macros/_drc_layer.rb index 7b42e7a02..363234287 100644 --- a/src/drc/drc/built-in-macros/_drc_layer.rb +++ b/src/drc/drc/built-in-macros/_drc_layer.rb @@ -593,6 +593,10 @@ CODE # selected text. By using the "as_dots" option, degenerated point-like edges will be # produced. # + # This method can also be applied to true text layers obtained with \labels. + # In this case, without specifying "as_dots" or "as_boxes" retains the text + # objects as such. Only text filtering is applied. + # # Texts can be selected either by exact match string or a pattern match with a # glob-style pattern. By default, glob-style pattern are used. # The options available are: @@ -615,14 +619,39 @@ CODE # # Selects all texts whose string is "A*" # t = input(1, 0).texts(text("A*")) # @/code + # def texts(*args) + requires_texts_or_region("texts") + self._texts_impl(false, *args) + end - requires_region("texts") + # %DRC% + # @name texts_not + # @brief Selects texts from an original layer not matching a specific selection + # @synopsis layer.texts_not + # @synopsis layer.texts_not(p) + # @synopsis layer.texts_not([ options ]) + # + # This method can be applied to true text layers obtained with \labels. + # In this case, without specifying "as_dots" or "as_boxes" retains the text + # objects as such. Only text filtering is applied. + # + # Beside that this method acts like \texts, but will select the text objects + # not matching the filter. + + def texts_not(*args) + requires_texts("texts_not") + self._texts_impl(true, *args) + end + + # Implementation of texts or texts_not + + def _texts_impl(invert, *args) as_pattern = true pattern = "*" - as_dots = false + as_dots = nil args.each do |a| if a.is_a?(String) @@ -637,15 +666,28 @@ CODE raise("Invalid argument for 'texts' method") end end - - if as_dots - DRCLayer::new(@engine, @engine._tcmd(@data, 0, RBA::Region, :texts_dots, pattern, as_pattern)) - else - DRCLayer::new(@engine, @engine._tcmd(@data, 0, RBA::Region, :texts, pattern, as_pattern)) + + if @data.is_a?(RBA::Texts) + if as_pattern + DRCLayer::new(@engine, @engine._tcmd(@data, 0, RBA::Texts, :with_match, pattern, invert)) + else + DRCLayer::new(@engine, @engine._tcmd(@data, 0, RBA::Texts, :with_text, pattern, invert)) + end + if as_dots + DRCLayer::new(@engine, @engine._tcmd(@data, 0, RBA::Region, :edges)) + elsif as_dots == false + DRCLayer::new(@engine, @engine._tcmd(@data, 0, RBA::Region, :polygons)) + end + else + if as_dots + DRCLayer::new(@engine, @engine._tcmd(@data, 0, RBA::Region, :texts_dots, pattern, as_pattern)) + else + DRCLayer::new(@engine, @engine._tcmd(@data, 0, RBA::Region, :texts, pattern, as_pattern)) + end end end - + # %DRC% # @name corners # @brief Selects corners of polygons @@ -1695,7 +1737,35 @@ CODE requires_region("#{f}") other.requires_region("#{f}") else - requires_edges_or_region("#{f}") + requires_edges_texts_or_region("#{f}") + if @data.is_a?(RBA::Text) + other.requires_region("#{f}") + else + other.requires_edges_or_region("#{f}") + end + end + DRCLayer::new(@engine, @engine._tcmd(@data, 0, other.data.class, :#{f}, other.data)) + end +CODE + end + + %w(| ^ overlapping not_overlapping inside not_inside outside not_outside in not_in).each do |f| + eval <<"CODE" + def #{f}(other) + requires_same_type(other, "#{f}") + requires_edges_or_region("#{f}") + DRCLayer::new(@engine, @engine._tcmd(@data, 0, @data.class, :#{f}, other.data)) + end +CODE + end + + %w(& -).each do |f| + eval <<"CODE" + def #{f}(other) + other.requires_edges_texts_or_region("#{f}") + if @data.is_a?(RBA::Texts) + other.requires_region("#{f}") + else other.requires_edges_or_region("#{f}") end DRCLayer::new(@engine, @engine._tcmd(@data, 0, @data.class, :#{f}, other.data)) @@ -1703,15 +1773,22 @@ CODE CODE end - %w(& | ^ - + interacting not_interacting overlapping not_overlapping inside not_inside outside not_outside in not_in).each do |f| + %w(+).each do |f| eval <<"CODE" def #{f}(other) - if :#{f} != :interacting && :#{f} != :not_interacting && :#{f} != :& && :#{f} != :- - requires_same_type(other, "#{f}") + requires_same_type(other, "#{f}") + DRCLayer::new(@engine, @engine._tcmd(@data, 0, @data.class, :#{f}, other.data)) + end +CODE + end + + %w(interacting not_interacting).each do |f| + eval <<"CODE" + def #{f}(other) + other.requires_edges_texts_or_region("#{f}") + if @data.is_a?(RBA::Texts) + other.requires_region("#{f}") else - other.requires_edges_or_region("#{f}") - end - if :#{f} != :+ requires_edges_or_region("#{f}") end DRCLayer::new(@engine, @engine._tcmd(@data, 0, @data.class, :#{f}, other.data)) @@ -2207,7 +2284,7 @@ CODE # If the layer already is a flat one, this method does nothing. # If the layer is a hierarchical layer (an original layer or # a derived layer in deep mode), this method will convert it - # to a flat collection of polygons, edges or edge pairs. + # to a flat collection of texts, polygons, edges or edge pairs. def flatten DRC::DRCLayer::new(@engine, @engine._cmd(@data, :flatten)) @@ -2235,7 +2312,6 @@ CODE # @synopsis layer.is_empty? def is_empty? - requires_edges_or_region("is_empty?") @data.is_empty? end @@ -3006,6 +3082,10 @@ CODE @data.is_a?(RBA::Region) || raise("#{f}: Requires a polygon layer") end + def requires_texts_or_region(f) + @data.is_a?(RBA::Region) || @data.is_a?(RBA::Texts) || raise("#{f}: Requires a polygon or text layer") + end + def requires_edge_pairs(f) @data.is_a?(RBA::EdgePairs) || raise("#{f}: Requires a edge pair layer") end @@ -3018,6 +3098,10 @@ CODE @data.is_a?(RBA::Edges) || @data.is_a?(RBA::Region) || raise("#{f}: Requires an edge or polygon layer") end + def requires_edges_texts_or_region(f) + @data.is_a?(RBA::Edges) || @data.is_a?(RBA::Region) || @data.is_a?(RBA::Texts) || raise("#{f}: Requires an edge, text or polygon layer") + end + def requires_same_type(other, f) @data.class == other.data.class || raise("#{f}: Requires input of the same kind") end diff --git a/src/drc/drc/built-in-macros/_drc_source.rb b/src/drc/drc/built-in-macros/_drc_source.rb index f047ff4a2..c7c846692 100644 --- a/src/drc/drc/built-in-macros/_drc_source.rb +++ b/src/drc/drc/built-in-macros/_drc_source.rb @@ -262,7 +262,7 @@ CODE # not have names)@/li # @/ul # - # Layers created with "input" contain both texts and polygons. There is a subtle + # Layers created with "input" may contain both texts (labels) 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 @@ -273,11 +273,16 @@ CODE # 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. # + # \labels also produces a true "text layer" which contains text objects. A variety of + # operations is available for these objects, such as boolean "and" and "not" with a polygon layer. + # True text layers should be preferred over mixed polygon/text layers if text object processing + # is required. + # # Use the global version of "input" without a source object to address the default source. 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, RBA::Shapes::SAll)) + DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SAll, RBA::Region)) end # %DRC% @@ -288,16 +293,18 @@ CODE # @synopsis source.labels(layer_into) # @synopsis source.labels(filter, ...) # - # Creates a layer with the labels from the given layer of the source. + # Creates a true text 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. + # layer. Starting with version 0.27, the result is no longer a polygon layer that tries + # to provide text support but a layer type which is provided for carrying text objects + # explicitly. # # Use the global version of "labels" without a source object to address the default source. 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, RBA::Shapes::STexts)) + DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::STexts, RBA::Texts)) end # %DRC% @@ -318,7 +325,55 @@ CODE 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 | RBA::Shapes::SEdgePairs)) + 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 | RBA::Shapes::SEdgePairs, RBA::Region)) + end + + # %DRC% + # @name edges + # @brief Gets the edge shapes (or shapes that can be converted edges) from an input layer + # @synopsis source.edges(layer) + # @synopsis source.edges(layer, datatype) + # @synopsis source.edges(layer_into) + # @synopsis source.edges(filter, ...) + # + # Creates a layer with the edges from the given layer of the source. + # Edge layers are formed from shapes by decomposing the shapes into edges: polygons + # for example are decomposed into their outline edges. Some file formats support egdes + # as native objects. + # + # This method is identical to \input with respect to the options supported. + # + # Use the global version of "edges" without a source object to address the default source. + # + # This method has been introduced in version 0.27. + + def edges(*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 | RBA::Shapes::SEdgePairs | RBA::Shapes::SEdges, RBA::Edges)) + end + + # %DRC% + # @name edge_pairs + # @brief Gets the edge pairs from an input layer + # @synopsis source.edge_pairs(layer) + # @synopsis source.edge_pairs(layer, datatype) + # @synopsis source.edge_pairs(layer_into) + # @synopsis source.edge_pairs(filter, ...) + # + # Creates a layer with the edge_pairs from the given layer of the source. + # Edge pairs are not supported by layout formats so far. So except if the source is + # a custom-built layout object, this method has little use. It is provided for future + # extensions which may include edge pairs in file streams. + # + # This method is identical to \input with respect to the options supported. + # + # Use the global version of "edge_pairs" without a source object to address the default source. + # + # This method has been introduced in version 0.27. + + def edge_pairs(*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::SEdgePairs, RBA::EdgePairs)) end # %DRC% @@ -329,7 +384,7 @@ CODE def make_layer layers = [] - DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SAll)) + DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SAll, RBA::Region)) end # %DRC% From 7dab87b881624c8f99becfad7865c1998d9cabff Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 15 May 2020 23:48:21 +0200 Subject: [PATCH 12/35] Added tests, Region#pull_interacting with texts --- src/db/db/dbAsIfFlatRegion.cc | 78 ++++++++++ src/db/db/dbAsIfFlatRegion.h | 17 +++ src/db/db/dbDeepRegion.cc | 204 +++++++++++++++++++++++++ src/db/db/dbDeepRegion.h | 2 + src/db/db/dbDeepShapeStore.cc | 30 ++++ src/db/db/dbDeepShapeStore.h | 13 +- src/db/db/dbDeepTexts.cc | 6 + src/db/db/dbDeepTexts.h | 1 + src/db/db/dbEmptyRegion.h | 4 + src/db/db/dbHierProcessor.cc | 26 ++++ src/db/db/dbRegion.h | 56 +++++++ src/db/db/dbRegionDelegate.h | 4 + src/db/db/dbRegionUtils.cc | 55 +++++++ src/db/db/dbRegionUtils.h | 46 ++++++ src/db/db/gsiDeclDbRegion.cc | 46 ++++++ src/db/unit_tests/dbDeepRegionTests.cc | 53 +++++++ src/db/unit_tests/dbRegionTests.cc | 78 ++++++++++ testdata/algo/deep_region_au29.gds | Bin 0 -> 1816 bytes 18 files changed, 718 insertions(+), 1 deletion(-) create mode 100644 testdata/algo/deep_region_au29.gds diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index 37481614e..65966361e 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -25,6 +25,7 @@ #include "dbFlatRegion.h" #include "dbFlatEdgePairs.h" #include "dbFlatEdges.h" +#include "dbFlatTexts.h" #include "dbEmptyRegion.h" #include "dbEmptyEdgePairs.h" #include "dbEmptyEdges.h" @@ -375,6 +376,50 @@ AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse) return output.release (); } +RegionDelegate * +AsIfFlatRegion::selected_interacting_generic (const Texts &other, bool inverse) const +{ + if (other.empty ()) { + if (! inverse) { + return new EmptyRegion (); + } else { + return clone (); + } + } else if (empty ()) { + return clone (); + } + + db::box_scanner2 scanner (report_progress (), progress_desc ()); + scanner.reserve1 (size ()); + scanner.reserve2 (other.size ()); + + std::auto_ptr output (new FlatRegion (false)); + region_to_text_interaction_filter filter (output->raw_polygons (), inverse); + + AddressablePolygonDelivery p (begin_merged (), has_valid_merged_polygons ()); + + for ( ; ! p.at_end (); ++p) { + scanner.insert1 (p.operator-> (), 0); + if (inverse) { + filter.preset (p.operator-> ()); + } + } + + AddressableTextDelivery e (other.addressable_texts ()); + + for ( ; ! e.at_end (); ++e) { + scanner.insert2 (e.operator-> (), 0); + } + + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + + if (inverse) { + filter.fill_output (); + } + + return output.release (); +} + RegionDelegate * AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const { @@ -468,6 +513,39 @@ AsIfFlatRegion::pull_generic (const Edges &other) const return output.release (); } +TextsDelegate * +AsIfFlatRegion::pull_generic (const Texts &other) const +{ + if (other.empty ()) { + return other.delegate ()->clone (); + } else if (empty ()) { + return new EmptyTexts (); + } + + db::box_scanner2 scanner (report_progress (), progress_desc ()); + scanner.reserve1 (size ()); + scanner.reserve2 (other.size ()); + + std::auto_ptr output (new FlatTexts (false)); + region_to_text_interaction_filter filter (output->raw_texts (), false); + + AddressablePolygonDelivery p (begin (), has_valid_merged_polygons ()); + + for ( ; ! p.at_end (); ++p) { + scanner.insert1 (p.operator-> (), 0); + } + + AddressableTextDelivery e (other.addressable_texts ()); + + for ( ; ! e.at_end (); ++e) { + scanner.insert2 (e.operator-> (), 0); + } + + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + + return output.release (); +} + RegionDelegate * AsIfFlatRegion::pull_generic (const Region &other, int mode, bool touching) const { diff --git a/src/db/db/dbAsIfFlatRegion.h b/src/db/db/dbAsIfFlatRegion.h index fb3a1c548..631026f4d 100644 --- a/src/db/db/dbAsIfFlatRegion.h +++ b/src/db/db/dbAsIfFlatRegion.h @@ -202,6 +202,16 @@ public: return selected_interacting_generic (other, true); } + virtual RegionDelegate *selected_interacting (const Texts &other) const + { + return selected_interacting_generic (other, false); + } + + virtual RegionDelegate *selected_not_interacting (const Texts &other) const + { + return selected_interacting_generic (other, true); + } + virtual RegionDelegate *selected_overlapping (const Region &other) const { return selected_interacting_generic (other, 0, false, false); @@ -227,6 +237,11 @@ public: return pull_generic (other); } + virtual TextsDelegate *pull_interacting (const Texts &other) const + { + return pull_generic (other); + } + virtual RegionDelegate *pull_overlapping (const Region &other) const { return pull_generic (other, 0, false); @@ -247,8 +262,10 @@ protected: EdgePairsDelegate *run_single_polygon_check (db::edge_relation_type rel, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const; virtual RegionDelegate *selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const; virtual RegionDelegate *selected_interacting_generic (const Edges &other, bool inverse) const; + virtual RegionDelegate *selected_interacting_generic (const Texts &other, bool inverse) const; virtual RegionDelegate *pull_generic (const Region &other, int mode, bool touching) const; virtual EdgesDelegate *pull_generic (const Edges &other) const; + virtual TextsDelegate *pull_generic (const Texts &other) const; template static void produce_markers_for_grid_check (const db::Polygon &poly, const Trans &tr, db::Coord gx, db::Coord gy, db::Shapes &shapes); diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index f56fc2be6..42510cb7d 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -28,6 +28,7 @@ #include "dbRegionUtils.h" #include "dbDeepEdges.h" #include "dbDeepEdgePairs.h" +#include "dbDeepTexts.h" #include "dbShapeProcessor.h" #include "dbFlatRegion.h" #include "dbHierProcessor.h" @@ -1896,6 +1897,143 @@ public: } }; +struct TextResultInserter +{ + typedef db::Text value_type; + + TextResultInserter (std::unordered_set &result) + : mp_result (&result) + { + // .. nothing yet .. + } + + void insert (const db::Text &e) + { + (*mp_result).insert (e); + } + +private: + std::unordered_set *mp_result; +}; + +class PullWithTextLocalOperation + : public local_operation +{ +public: + PullWithTextLocalOperation () + { + // .. nothing yet .. + } + + virtual db::Coord dist () const + { + // touching is sufficient + return 1; + } + + virtual void compute_local (db::Layout *, const shape_interactions &interactions, std::unordered_set &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const + { + db::box_scanner2 scanner; + + TextResultInserter inserter (result); + region_to_text_interaction_filter filter (inserter, false); + + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { + scanner.insert2 (& interactions.intruder_shape (*j), 0); + } + } + + std::list heap; + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + + const db::PolygonRef &subject = interactions.subject_shape (i->first); + heap.push_back (subject.obj ().transformed (subject.trans ())); + + scanner.insert1 (&heap.back (), 0); + + } + + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + } + + virtual on_empty_intruder_mode on_empty_intruder_hint () const + { + return Drop; + } + + virtual std::string description () const + { + return tl::to_string (tr ("Pull texts from second by their geometric relation to first")); + } +}; + +class InteractingWithTextLocalOperation + : public local_operation +{ +public: + InteractingWithTextLocalOperation (bool inverse) + : m_inverse (inverse) + { + // .. nothing yet .. + } + + virtual db::Coord dist () const + { + // touching is sufficient + return 1; + } + + virtual void compute_local (db::Layout *layout, const shape_interactions &interactions, std::unordered_set &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const + { + db::box_scanner2 scanner; + + ResultInserter inserter (layout, result); + region_to_text_interaction_filter filter (inserter, m_inverse); + + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { + scanner.insert2 (& interactions.intruder_shape (*j), 0); + } + } + + std::list heap; + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + + const db::PolygonRef &subject = interactions.subject_shape (i->first); + heap.push_back (subject.obj ().transformed (subject.trans ())); + + scanner.insert1 (&heap.back (), 0); + if (m_inverse) { + filter.preset (&heap.back ()); + } + + } + + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + if (m_inverse) { + filter.fill_output (); + } + } + + virtual on_empty_intruder_mode on_empty_intruder_hint () const + { + if (!m_inverse) { + return Drop; + } else { + return Copy; + } + } + + virtual std::string description () const + { + return tl::to_string (tr ("Select regions by their geometric relation to texts")); + } + +private: + bool m_inverse; +}; + } RegionDelegate * @@ -2042,4 +2180,70 @@ DeepRegion::pull_generic (const Edges &other) const return res; } +TextsDelegate * +DeepRegion::pull_generic (const Texts &other) const +{ + std::auto_ptr dr_holder; + const db::DeepTexts *other_deep = dynamic_cast (other.delegate ()); + if (! other_deep) { + // if the other region isn't deep, turn into a top-level only deep region to facilitate re-hierarchisation + dr_holder.reset (new db::DeepTexts (other, const_cast (*deep_layer ().store ()))); + other_deep = dr_holder.get (); + } + + // in "inside" mode, the first argument needs to be merged too + const db::DeepLayer &polygons = deep_layer (); + const db::DeepLayer &other_texts = other_deep->deep_layer (); + + DeepLayer dl_out (polygons.derived ()); + + db::PullWithTextLocalOperation op; + + db::local_processor proc (const_cast (&polygons.layout ()), const_cast (&polygons.initial_cell ()), &other_texts.layout (), &other_texts.initial_cell (), polygons.breakout_cells (), other_texts.breakout_cells ()); + proc.set_base_verbosity (base_verbosity ()); + proc.set_threads (polygons.store ()->threads ()); + proc.run (&op, polygons.layer (), other_texts.layer (), dl_out.layer ()); + + db::DeepTexts *res = new db::DeepTexts (dl_out); + res->set_is_merged (is_merged ()); + return res; +} + +RegionDelegate * +DeepRegion::selected_interacting_generic (const Texts &other, bool inverse) const +{ + // with these flag set to true, the resulting polygons are broken again. + bool split_after = false; + + std::auto_ptr dr_holder; + const db::DeepTexts *other_deep = dynamic_cast (other.delegate ()); + if (! other_deep) { + // if the other region isn't deep, turn into a top-level only deep region to facilitate re-hierarchisation + dr_holder.reset (new db::DeepTexts (other, const_cast (*deep_layer ().store ()))); + other_deep = dr_holder.get (); + } + + const db::DeepLayer &polygons = merged_deep_layer (); + + DeepLayer dl_out (polygons.derived ()); + + db::InteractingWithTextLocalOperation op (inverse); + + db::local_processor proc (const_cast (&polygons.layout ()), const_cast (&polygons.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), polygons.breakout_cells (), other_deep->deep_layer ().breakout_cells ()); + proc.set_base_verbosity (base_verbosity ()); + proc.set_threads (polygons.store ()->threads ()); + if (split_after) { + proc.set_area_ratio (polygons.store ()->max_area_ratio ()); + proc.set_max_vertex_count (polygons.store ()->max_vertex_count ()); + } + + proc.run (&op, polygons.layer (), other_deep->deep_layer ().layer (), dl_out.layer ()); + + db::DeepRegion *res = new db::DeepRegion (dl_out); + if (! split_after) { + res->set_is_merged (merged_semantics () || is_merged ()); + } + return res; +} + } diff --git a/src/db/db/dbDeepRegion.h b/src/db/db/dbDeepRegion.h index e1cdc57c3..bf794ec48 100644 --- a/src/db/db/dbDeepRegion.h +++ b/src/db/db/dbDeepRegion.h @@ -193,8 +193,10 @@ private: EdgePairsDelegate *run_single_polygon_check (db::edge_relation_type rel, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const; virtual RegionDelegate *selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const; virtual RegionDelegate *selected_interacting_generic (const Edges &other, bool inverse) const; + virtual RegionDelegate *selected_interacting_generic (const Texts &other, bool inverse) const; virtual RegionDelegate *pull_generic (const Region &other, int mode, bool touching) const; virtual EdgesDelegate *pull_generic (const Edges &other) const; + virtual TextsDelegate *pull_generic (const Texts &other) const; DeepRegion *apply_filter (const PolygonFilterBase &filter) const; template OutputContainer *processed_impl (const polygon_processor &filter) const; diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index db7a95c55..b678b302f 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -459,6 +459,36 @@ DeepLayer DeepShapeStore::create_from_flat (const db::Edges &edges, const db::IC return dl; } +DeepLayer DeepShapeStore::create_from_flat (const db::Texts &texts, const db::ICplxTrans &trans) +{ + // reuse existing layer + std::pair lff = layer_for_flat (tl::id_of (texts.delegate ())); + if (lff.first) { + return lff.second; + } + + require_singular (); + + unsigned int layer = layout ().insert_layer (); + + db::Shapes *shapes = &initial_cell ().shapes (layer); + db::Box world = db::Box::world (); + + db::TextBuildingHierarchyBuilderShapeReceiver tb; + + std::pair ii = texts.begin_iter (); + db::ICplxTrans ttop = trans * ii.second; + while (! ii.first.at_end ()) { + tb.push (*ii.first, ttop * ii.first.trans (), world, 0, shapes); + ++ii.first; + } + + DeepLayer dl (this, 0 /*singular layout index*/, layer); + m_layers_for_flat [tl::id_of (texts.delegate ())] = std::make_pair (dl.layout_index (), dl.layer ()); + m_flat_region_id [std::make_pair (dl.layout_index (), dl.layer ())] = tl::id_of (texts.delegate ()); + return dl; +} + std::pair DeepShapeStore::layer_for_flat (const db::Region ®ion) const { return layer_for_flat (tl::id_of (region.delegate ())); diff --git a/src/db/db/dbDeepShapeStore.h b/src/db/db/dbDeepShapeStore.h index 3c4e678ec..032fb8aad 100644 --- a/src/db/db/dbDeepShapeStore.h +++ b/src/db/db/dbDeepShapeStore.h @@ -338,7 +338,18 @@ public: * After a flat layer has been created for a region, it can be retrieved * from the region later with layer_for_flat (region). */ - DeepLayer create_from_flat (const db::Edges ®ion, const db::ICplxTrans &trans = db::ICplxTrans ()); + DeepLayer create_from_flat (const db::Edges &edges, const db::ICplxTrans &trans = db::ICplxTrans ()); + + /** + * @brief Creates a new layer from a flat text collection (or the text collection is made flat) + * + * This method is intended for use with singular-created DSS objects (see + * singular constructor). + * + * After a flat layer has been created for a region, it can be retrieved + * from the region later with layer_for_flat (region). + */ + DeepLayer create_from_flat (const db::Texts &texts, const db::ICplxTrans &trans = db::ICplxTrans ()); /** * @brief Gets the layer for a given flat region. diff --git a/src/db/db/dbDeepTexts.cc b/src/db/db/dbDeepTexts.cc index 1def0413e..73739984f 100644 --- a/src/db/db/dbDeepTexts.cc +++ b/src/db/db/dbDeepTexts.cc @@ -96,6 +96,12 @@ DeepTexts::DeepTexts () // .. nothing yet .. } +DeepTexts::DeepTexts (const db::Texts &other, DeepShapeStore &dss) + : AsIfFlatTexts () +{ + m_deep_layer = dss.create_from_flat (other); +} + DeepTexts::DeepTexts (const RecursiveShapeIterator &si, DeepShapeStore &dss) : AsIfFlatTexts (), m_deep_layer (dss.create_text_layer (si)) { diff --git a/src/db/db/dbDeepTexts.h b/src/db/db/dbDeepTexts.h index 21da58c39..ef877be8d 100644 --- a/src/db/db/dbDeepTexts.h +++ b/src/db/db/dbDeepTexts.h @@ -40,6 +40,7 @@ class DB_PUBLIC DeepTexts { public: DeepTexts (); + DeepTexts (const db::Texts &other, DeepShapeStore &dss); DeepTexts (const RecursiveShapeIterator &si, DeepShapeStore &dss); DeepTexts (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans); diff --git a/src/db/db/dbEmptyRegion.h b/src/db/db/dbEmptyRegion.h index 5ab62f825..ec40deffa 100644 --- a/src/db/db/dbEmptyRegion.h +++ b/src/db/db/dbEmptyRegion.h @@ -27,6 +27,7 @@ #include "dbCommon.h" #include "dbRegionDelegate.h" #include "dbEmptyEdges.h" +#include "dbEmptyTexts.h" namespace db { @@ -107,11 +108,14 @@ public: virtual RegionDelegate *selected_not_interacting (const Region &) const { return new EmptyRegion (); } virtual RegionDelegate *selected_interacting (const Edges &) const { return new EmptyRegion (); } virtual RegionDelegate *selected_not_interacting (const Edges &) const { return new EmptyRegion (); } + virtual RegionDelegate *selected_interacting (const Texts &) const { return new EmptyRegion (); } + virtual RegionDelegate *selected_not_interacting (const Texts &) const { return new EmptyRegion (); } virtual RegionDelegate *selected_overlapping (const Region &) const { return new EmptyRegion (); } virtual RegionDelegate *selected_not_overlapping (const Region &) const { return new EmptyRegion (); } virtual RegionDelegate *pull_inside (const Region &) const { return new EmptyRegion (); } virtual RegionDelegate *pull_interacting (const Region &) const { return new EmptyRegion (); } virtual EdgesDelegate *pull_interacting (const Edges &) const { return new EmptyEdges (); } + virtual TextsDelegate *pull_interacting (const Texts &) const { return new EmptyTexts (); } virtual RegionDelegate *pull_overlapping (const Region &) const { return new EmptyRegion (); } virtual RegionDelegate *in (const Region &, bool) const { return new EmptyRegion (); } diff --git a/src/db/db/dbHierProcessor.cc b/src/db/db/dbHierProcessor.cc index 23870f6d9..2db262ac4 100644 --- a/src/db/db/dbHierProcessor.cc +++ b/src/db/db/dbHierProcessor.cc @@ -157,6 +157,29 @@ public: } }; +template <> +class shape_reference_translator +{ +public: + typedef db::Text shape_type; + + shape_reference_translator (db::Layout * /*target_layout*/) + { + // .. nothing yet .. + } + + const shape_type &operator() (const shape_type &s) const + { + return s; + } + + template + shape_type operator() (const shape_type &s, const Trans &tr) const + { + return s.transformed (tr); + } +}; + template class shape_reference_translator_with_trans_from_shape_ref { @@ -633,6 +656,7 @@ shape_interactions::intruder_shape (unsigned int id) const template class DB_PUBLIC shape_interactions; template class DB_PUBLIC shape_interactions; +template class DB_PUBLIC shape_interactions; template class DB_PUBLIC shape_interactions; template class DB_PUBLIC shape_interactions; template class DB_PUBLIC shape_interactions; @@ -1756,6 +1780,8 @@ local_processor::compute_local_cell (const db::local_processor_conte template class DB_PUBLIC local_processor; template class DB_PUBLIC local_processor; template class DB_PUBLIC local_processor; +template class DB_PUBLIC local_processor; +template class DB_PUBLIC local_processor; template class DB_PUBLIC local_processor; template class DB_PUBLIC local_processor; template class DB_PUBLIC local_processor; diff --git a/src/db/db/dbRegion.h b/src/db/db/dbRegion.h index 5ac56c8d4..f3f8bf576 100644 --- a/src/db/db/dbRegion.h +++ b/src/db/db/dbRegion.h @@ -1322,6 +1322,52 @@ public: return Region (mp_delegate->selected_not_interacting (other)); } + /** + * @brief Selects all polygons of this region which overlap or touch texts from the text collection + * + * Merged semantics applies. + */ + Region &select_interacting (const Texts &other) + { + set_delegate (mp_delegate->selected_interacting (other)); + return *this; + } + + /** + * @brief Selects all polygons of this region which do not overlap or touch texts from the text collection + * + * Merged semantics applies. + */ + Region &select_not_interacting (const Texts &other) + { + set_delegate (mp_delegate->selected_not_interacting (other)); + return *this; + } + + /** + * @brief Returns all polygons of this which overlap or touch texts from the text collection + * + * This method is an out-of-place version of select_interacting. + * + * Merged semantics applies. + */ + Region selected_interacting (const Texts &other) const + { + return Region (mp_delegate->selected_interacting (other)); + } + + /** + * @brief Returns all polygons of this which do not overlap or touch texts from the text collection + * + * This method is an out-of-place version of select_not_interacting. + * + * Merged semantics applies. + */ + Region selected_not_interacting (const Texts &other) const + { + return Region (mp_delegate->selected_not_interacting (other)); + } + /** * @brief Selects all polygons of this region which overlap polygons from the other region * @@ -1388,6 +1434,16 @@ public: return Edges (mp_delegate->pull_interacting (other)); } + /** + * @brief Returns all texts of "other" which are interacting (touching or overlapping with) polygons of this region + * + * Merged semantics applies. + */ + Texts pull_interacting (const Texts &other) const + { + return Texts (mp_delegate->pull_interacting (other)); + } + /** * @brief Returns all polygons of "other" which are interacting (touching or overlapping with) polygons of this region * diff --git a/src/db/db/dbRegionDelegate.h b/src/db/db/dbRegionDelegate.h index 9909145f2..f38e25688 100644 --- a/src/db/db/dbRegionDelegate.h +++ b/src/db/db/dbRegionDelegate.h @@ -28,6 +28,7 @@ #include "dbPolygon.h" #include "dbEdges.h" +#include "dbTexts.h" #include "dbEdgePairs.h" #include "dbEdgePairRelations.h" #include "tlUniqueId.h" @@ -294,12 +295,15 @@ public: virtual RegionDelegate *selected_not_interacting (const Region &other) const = 0; virtual RegionDelegate *selected_interacting (const Edges &other) const = 0; virtual RegionDelegate *selected_not_interacting (const Edges &other) const = 0; + virtual RegionDelegate *selected_interacting (const Texts &other) const = 0; + virtual RegionDelegate *selected_not_interacting (const Texts &other) const = 0; virtual RegionDelegate *selected_overlapping (const Region &other) const = 0; virtual RegionDelegate *selected_not_overlapping (const Region &other) const = 0; virtual RegionDelegate *pull_inside (const Region &other) const = 0; virtual RegionDelegate *pull_interacting (const Region &other) const = 0; virtual EdgesDelegate *pull_interacting (const Edges &other) const = 0; virtual RegionDelegate *pull_overlapping (const Region &other) const = 0; + virtual TextsDelegate *pull_interacting (const Texts &other) const = 0; virtual RegionDelegate *in (const Region &other, bool invert) const = 0; virtual const db::Polygon *nth (size_t n) const = 0; diff --git a/src/db/db/dbRegionUtils.cc b/src/db/db/dbRegionUtils.cc index 3214fa747..6748fc954 100644 --- a/src/db/db/dbRegionUtils.cc +++ b/src/db/db/dbRegionUtils.cc @@ -350,6 +350,61 @@ region_to_edge_interaction_filter_base::fill_output () template class region_to_edge_interaction_filter_base; template class region_to_edge_interaction_filter_base; +// ------------------------------------------------------------------------------------- +// RegionToTextInteractionFilterBase implementation + +template +region_to_text_interaction_filter_base::region_to_text_interaction_filter_base (bool inverse) + : m_inverse (inverse) +{ + // .. nothing yet .. +} + +template +void +region_to_text_interaction_filter_base::preset (const OutputType *s) +{ + m_seen.insert (s); +} + +template +void +region_to_text_interaction_filter_base::add (const db::Polygon *p, size_t, const db::Text *t, size_t) +{ + const OutputType *o = 0; + tl::select (o, p, t); + + if ((m_seen.find (o) == m_seen.end ()) != m_inverse) { + + // A polygon and an text interact if the text is either inside completely + // of at least one text of the polygon intersects with the text + db::Point pt; + pt += t->trans ().disp (); + if (p->box ().contains (pt) && db::inside_poly (p->begin_edge (), pt) >= 0) { + if (m_inverse) { + m_seen.erase (o); + } else { + m_seen.insert (o); + put (*o); + } + } + + } +} + +template +void +region_to_text_interaction_filter_base::fill_output () +{ + for (typename std::set::const_iterator s = m_seen.begin (); s != m_seen.end (); ++s) { + put (**s); + } +} + +// explicit instantiations +template class region_to_text_interaction_filter_base; +template class region_to_text_interaction_filter_base; + // ------------------------------------------------------------------------------------- // Polygon snapping diff --git a/src/db/db/dbRegionUtils.h b/src/db/db/dbRegionUtils.h index 46ef4d9cc..4229e087b 100644 --- a/src/db/db/dbRegionUtils.h +++ b/src/db/db/dbRegionUtils.h @@ -524,6 +524,52 @@ private: OutputContainer *mp_output; }; +/** + * @brief A helper class for the region to text interaction functionality + */ +template +class DB_PUBLIC region_to_text_interaction_filter_base + : public db::box_scanner_receiver2 +{ +public: + region_to_text_interaction_filter_base (bool inverse); + + void preset (const OutputType *s); + void add (const db::Polygon *p, size_t, const db::Text *e, size_t); + void fill_output (); + +protected: + virtual void put (const OutputType &s) const = 0; + +private: + std::set m_seen; + bool m_inverse; +}; + +/** + * @brief A helper class for the region to text interaction functionality + */ +template +class DB_PUBLIC_TEMPLATE region_to_text_interaction_filter + : public region_to_text_interaction_filter_base +{ +public: + region_to_text_interaction_filter (OutputContainer &output, bool inverse) + : region_to_text_interaction_filter_base (inverse), mp_output (&output) + { + // .. nothing yet .. + } + +protected: + virtual void put (const OutputType &poly) const + { + mp_output->insert (poly); + } + +private: + OutputContainer *mp_output; +}; + template static inline C snap_to_grid (C c, C g) { diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index 54b210363..099ee25d4 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -1509,6 +1509,42 @@ Class decl_Region ("db", "Region", "\n" "This method has been introduced in version 0.25\n" ) + + method ("interacting", (db::Region (db::Region::*) (const db::Texts &) const) &db::Region::selected_interacting, gsi::arg ("other"), + "@brief Returns the polygons of this region which overlap or touch texts\n" + "\n" + "@return A new region containing the polygons overlapping or touching texts\n" + "\n" + "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "\n" + "This method has been introduced in version 0.27\n" + ) + + method ("not_interacting", (db::Region (db::Region::*) (const db::Texts &) const) &db::Region::selected_not_interacting, gsi::arg ("other"), + "@brief Returns the polygons of this region which do not overlap or touch texts\n" + "\n" + "@return A new region containing the polygons not overlapping or touching texts\n" + "\n" + "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "\n" + "This method has been introduced in version 0.27\n" + ) + + method ("select_interacting", (db::Region &(db::Region::*) (const db::Texts &)) &db::Region::select_interacting, gsi::arg ("other"), + "@brief Selects the polygons of this region which overlap or touch texts\n" + "\n" + "@return The region after the polygons have been selected (self)\n" + "\n" + "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "\n" + "This method has been introduced in version 0.27\n" + ) + + method ("select_not_interacting", (db::Region &(db::Region::*) (const db::Texts &)) &db::Region::select_not_interacting, gsi::arg ("other"), + "@brief Selects the polygons of this region which do not overlap or touch texts\n" + "\n" + "@return The region after the polygons have been selected (self)\n" + "\n" + "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "\n" + "This method has been introduced in version 0.27\n" + ) + method ("overlapping", &db::Region::selected_overlapping, gsi::arg ("other"), "@brief Returns the polygons of this region which overlap polygons from the other region\n" "\n" @@ -1580,6 +1616,16 @@ Class decl_Region ("db", "Region", "\n" "This method has been introduced in version 0.26.1\n" ) + + method ("pull_interacting", static_cast (&db::Region::pull_interacting), gsi::arg ("other"), + "@brief Returns all texts of \"other\" which are interacting with polygons of this region\n" + "See \\pull_inside for a description of the \"pull_...\" methods.\n" + "\n" + "@return The text collection after the texts have been selected (from other)\n" + "\n" + "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "\n" + "This method has been introduced in version 0.27\n" + ) + method ("is_box?", &db::Region::is_box, "@brief Returns true, if the region is a simple box\n" "\n" diff --git a/src/db/unit_tests/dbDeepRegionTests.cc b/src/db/unit_tests/dbDeepRegionTests.cc index 10d95ea3a..22b4e6ef3 100644 --- a/src/db/unit_tests/dbDeepRegionTests.cc +++ b/src/db/unit_tests/dbDeepRegionTests.cc @@ -1598,6 +1598,59 @@ TEST(28b_snap) db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/deep_region_au28.gds"); } +TEST(29_InteractionsWithTexts) +{ + db::Layout ly; + { + std::string fn (tl::testsrc ()); + fn += "/testdata/algo/deep_texts_l2.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly); + } + + db::cell_index_type top_cell_index = *ly.begin_top_down (); + db::Cell &top_cell = ly.cell (top_cell_index); + + db::DeepShapeStore dss; + + unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0)); + unsigned int l8 = ly.get_layer (db::LayerProperties (8, 0)); + + db::Texts texts2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss); + db::Region polygons8 (db::RecursiveShapeIterator (ly, top_cell, l8), dss); + + db::Layout target; + unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index)); + + db::Region polygons; + polygons = polygons8.selected_interacting (texts2); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), polygons); + + polygons = polygons8.selected_not_interacting (texts2); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), polygons); + + { + db::Region polygons8_copy = polygons8; + polygons8_copy.select_interacting (texts2); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), polygons8_copy); + } + + { + db::Region polygons8_copy = polygons8; + polygons8_copy.select_not_interacting (texts2); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), polygons8_copy); + } + + { + db::Texts t = polygons8.pull_interacting (texts2); + target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), t); + } + + CHECKPOINT(); + db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au29.gds"); +} + TEST(100_Integration) { db::Layout ly; diff --git a/src/db/unit_tests/dbRegionTests.cc b/src/db/unit_tests/dbRegionTests.cc index 86f52f6db..6addaa424 100644 --- a/src/db/unit_tests/dbRegionTests.cc +++ b/src/db/unit_tests/dbRegionTests.cc @@ -1495,6 +1495,84 @@ TEST(33b_snap) db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/region_au33.gds"); } +TEST(34a) +{ + db::Region r; + EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), ""); + r.insert (db::Box (db::Point (0, 0), db::Point (100, 200))); + r.insert (db::Box (db::Point (-100, -100), db::Point (0, 0))); + r.set_merged_semantics (false); + EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), "(0,0;0,200;100,200;100,0)"); + EXPECT_EQ (r.selected_not_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), "(-100,-100;-100,0;0,0;0,-100)"); + db::Texts tt; + tt.insert (db::Text ("abc", db::Trans (db::Vector (30, 30)))); + tt.insert (db::Text ("xyz", db::Trans (db::Vector (-100, 0)))); + EXPECT_EQ (r.selected_interacting (tt).to_string (), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)"); + EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (300, 30))))).to_string (), ""); + db::Region rr = r; + r.select_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (-10, -10))))); + EXPECT_EQ (r.to_string (), "(-100,-100;-100,0;0,0;0,-100)"); + rr.select_not_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (-10, -10))))); + EXPECT_EQ (rr.to_string (), "(0,0;0,200;100,200;100,0)"); + + r.clear (); + r.insert(db::Box (db::Point (1000, 0), db::Point (6000, 4000))); + EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (2000, 6000))))).to_string (), ""); + EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (2000, 2000))))).to_string (), "(1000,0;1000,4000;6000,4000;6000,0)"); + EXPECT_EQ (db::Texts (db::Text ("abc", db::Trans (db::Vector (2000, 6000)))).selected_interacting (r).to_string (), ""); + EXPECT_EQ (db::Texts (db::Text ("abc", db::Trans (db::Vector (2000, 2000)))).selected_interacting (r).to_string (), "('abc',r0 2000,2000)"); + EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (2000, 6000))))).to_string (), ""); + EXPECT_EQ (db::Texts (db::Text ("abc", db::Trans (db::Vector (2000, 6000)))).selected_interacting (r).to_string (), ""); + EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (1000, 2000))))).to_string (), "(1000,0;1000,4000;6000,4000;6000,0)"); + EXPECT_EQ (db::Texts (db::Text ("abc", db::Trans (db::Vector (1000, 2000)))).selected_interacting (r).to_string (), "('abc',r0 1000,2000)"); +} + +TEST(34b) +{ + db::Region r; + EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), ""); + r.insert (db::Box (db::Point (0, 0), db::Point (100, 200))); + r.insert (db::Box (db::Point (-100, -100), db::Point (0, 0))); + r.set_merged_semantics (true); + r.set_min_coherence (true); + EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), "(0,0;0,200;100,200;100,0)"); + db::Texts tt; + tt.insert (db::Text ("abc", db::Trans (db::Vector (30, 30)))); + tt.insert (db::Text ("xyz", db::Trans (db::Vector (-100, 0)))); + EXPECT_EQ (r.selected_interacting (tt).to_string (), "(-100,-100;-100,0;0,0;0,-100);(0,0;0,200;100,200;100,0)"); + EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (-190, -190))))).to_string (), ""); + r.select_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (-10, -10))))); + EXPECT_EQ (r.to_string (), "(-100,-100;-100,0;0,0;0,-100)"); +} + +TEST(34c) +{ + db::Region r; + EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), ""); + r.insert (db::Box (db::Point (0, 0), db::Point (100, 200))); + r.insert (db::Box (db::Point (-100, -100), db::Point (0, 0))); + r.set_merged_semantics (true); + r.set_min_coherence (false); + EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)"); + EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (0, 0))))).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)"); + EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (-190, -190))))).to_string (), ""); + r.select_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (-10, -10))))); + EXPECT_EQ (r.to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)"); +} + +TEST(34d) +{ + db::Region r; + EXPECT_EQ (r.pull_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), ""); + r.insert (db::Box (db::Point (0, 0), db::Point (100, 200))); + r.insert (db::Box (db::Point (-100, -100), db::Point (0, 0))); + r.set_merged_semantics (true); + r.set_min_coherence (false); + EXPECT_EQ (r.pull_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), "('abc',r0 30,30)"); + EXPECT_EQ (r.pull_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (0, 0))))).to_string (), "('abc',r0 0,0)"); + EXPECT_EQ (r.pull_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (-190, -190))))).to_string (), ""); +} + TEST(100_Processors) { db::Region r; diff --git a/testdata/algo/deep_region_au29.gds b/testdata/algo/deep_region_au29.gds new file mode 100644 index 0000000000000000000000000000000000000000..96a5c0c0f200a0e5675ae2909712c2721874c20d GIT binary patch literal 1816 zcmbW1Jx{_w7{~uD8iJk^`^sV-Ru7LFxR4DwAR% z2gH2-boO#(>+zmeC>o$eO)5O()AjEY zu%9wa|IVt`a!|>HR0pUBK)Mom=-OlY2?Hb|BL*@mQx4d+=lOfqdYxYZELOvQ~X3Y z^Yk32IWIkMo?COBSuy`XjL`80&K`SbLg(I@ktgrWRN^l~-%v%t4?`d70{{R3 literal 0 HcmV?d00001 From 33a909a32723112c05b288faa46da7febd7fda7e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 15 May 2020 23:57:31 +0200 Subject: [PATCH 13/35] Added RBA tests for region to text interactions. --- testdata/ruby/dbTextsTest.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/testdata/ruby/dbTextsTest.rb b/testdata/ruby/dbTextsTest.rb index dcd30d305..42e1a520b 100644 --- a/testdata/ruby/dbTextsTest.rb +++ b/testdata/ruby/dbTextsTest.rb @@ -291,9 +291,12 @@ class DBTexts_TestClass < TestBase r.insert(RBA::Text::new("uvw", RBA::Trans::new(RBA::Vector::new(110, -210)))) g2 = RBA::Region::new g2.insert(RBA::Box::new(0, 100, 200, 200)) + g2.insert(RBA::Box::new(-200, 100, -100, 200)) assert_equal(r.interacting(g2).to_s, "('abc',r0 100,200)") + assert_equal(g2.interacting(r).to_s, "(0,100;0,200;200,200;200,100)") assert_equal(r.not_interacting(g2).to_s, "('uvw',r0 110,-210)") + assert_equal(g2.not_interacting(r).to_s, "(-200,100;-200,200;-100,200;-100,100)") rr = r.dup rr.select_interacting(g2) assert_equal(rr.to_s, "('abc',r0 100,200)") @@ -302,6 +305,7 @@ class DBTexts_TestClass < TestBase assert_equal(rr.to_s, "('uvw',r0 110,-210)") assert_equal(r.pull_interacting(g2).to_s, "(0,100;0,200;200,200;200,100)") + assert_equal(g2.pull_interacting(r).to_s, "('abc',r0 100,200)") end From ad0cd2f10c36fbb371cc1fd6ea9cd221bb9bd0d8 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 16 May 2020 00:18:54 +0200 Subject: [PATCH 14/35] pull_interacting and interacting/not_interacting for region/text combinations in DRC. --- src/drc/drc/built-in-macros/_drc_layer.rb | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/drc/drc/built-in-macros/_drc_layer.rb b/src/drc/drc/built-in-macros/_drc_layer.rb index 363234287..211fc45fa 100644 --- a/src/drc/drc/built-in-macros/_drc_layer.rb +++ b/src/drc/drc/built-in-macros/_drc_layer.rb @@ -1740,6 +1740,8 @@ CODE requires_edges_texts_or_region("#{f}") if @data.is_a?(RBA::Text) other.requires_region("#{f}") + elsif @data.is_a?(RBA::Region) + other.requires_edges_texts_or_region("#{f}") else other.requires_edges_or_region("#{f}") end @@ -1786,10 +1788,12 @@ CODE eval <<"CODE" def #{f}(other) other.requires_edges_texts_or_region("#{f}") - if @data.is_a?(RBA::Texts) + if @data.is_a?(RBA::Text) other.requires_region("#{f}") + elsif @data.is_a?(RBA::Region) + other.requires_edges_texts_or_region("#{f}") else - requires_edges_or_region("#{f}") + other.requires_edges_or_region("#{f}") end DRCLayer::new(@engine, @engine._tcmd(@data, 0, @data.class, :#{f}, other.data)) end @@ -1822,12 +1826,7 @@ CODE def #{f}(other) other.requires_region("#{f}") requires_edges("#{f}") - if @engine.is_tiled? - @data = @engine._tcmd(@data, 0, @data.class, :#{f}, other.data) - DRCLayer::new(@engine, @data) - else - DRCLayer::new(@engine, @engine._tcmd(@data, 0, @data.class, :#{f}, other.data)) - end + DRCLayer::new(@engine, @engine._tcmd(@data, 0, @data.class, :#{f}, other.data)) end CODE end @@ -1837,12 +1836,7 @@ CODE def #{f}(other) other.requires_edges("#{f}") requires_edges("#{f}") - if @engine.is_tiled? - @data = @engine._tcmd(@data, 0, @data.class, :#{f}, other.data) - DRCLayer::new(@engine, @data) - else - DRCLayer::new(@engine, @engine._tcmd(@data, 0, @data.class, :#{f}, other.data)) - end + DRCLayer::new(@engine, @engine._tcmd(@data, 0, @data.class, :#{f}, other.data)) end CODE end From 371009ba80d4c5579dba0077158e765c98ddec44 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 18 May 2020 21:08:59 +0200 Subject: [PATCH 15/35] Fixed small typos in LVS doc text. --- src/lay/lay/doc/manual/lvs_compare.xml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/lay/lay/doc/manual/lvs_compare.xml b/src/lay/lay/doc/manual/lvs_compare.xml index 168cea4a1..d5de64f78 100644 --- a/src/lay/lay/doc/manual/lvs_compare.xml +++ b/src/lay/lay/doc/manual/lvs_compare.xml @@ -140,7 +140,7 @@ same_device_classes("POLYRES", nil)

- A relative tolerance is specified as an additonal forth parameter. You can set + A relative tolerance is specified as an additional forth parameter. You can set the absolute tolerance to zero to specify only relative tolerances. This will specify 1% tolerance for the "L" parameter of "NMOS" devices:

@@ -151,13 +151,14 @@ same_device_classes("POLYRES", nil) There is also a more explicit notation for the tolerance:

-
tolerance("NMOS", "L", :absolute => 0.05)
-tolerance("NMOS", "L", :relative => 0.01)
+
tolerance("NMOS", "L", :absolute => 0.05)

- This notation is equivalent to the two forms above. + or

+
tolerance("NMOS", "L", :relative => 0.01)
+

An absolute plus relative tolerance can be specified by giving both. The following calls will give you 50nm absolute and 1% relative tolerance for the "L" From 4c13bb96a050ef76b0d18eb4106917b81a9a430e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 20 May 2020 00:21:06 +0200 Subject: [PATCH 16/35] WIP: refactoring - texts for net extractor. --- src/db/db/db.pro | 6 +- src/db/db/dbAsIfFlatRegion.cc | 4 +- src/db/db/dbAsIfFlatTexts.cc | 6 +- src/db/db/dbDeepEdges.cc | 4 +- src/db/db/dbDeepRegion.cc | 40 ++-- src/db/db/dbDeepShapeStore.cc | 7 +- src/db/db/dbDeepTexts.cc | 50 ++-- src/db/db/dbHierNetworkProcessor.cc | 181 +++++++++++++-- src/db/db/dbHierNetworkProcessor.h | 43 +++- src/db/db/dbHierProcessor.cc | 39 +--- src/db/db/dbHierarchyBuilder.cc | 11 +- src/db/db/dbHierarchyBuilder.h | 5 +- src/db/db/dbLayout.h | 16 ++ src/db/db/dbLayoutToNetlist.cc | 95 +++++--- src/db/db/dbLayoutToNetlist.h | 8 +- src/db/db/dbLayoutToNetlistReader.cc | 10 +- src/db/db/dbLayoutToNetlistReader.h | 2 +- src/db/db/dbLayoutToNetlistWriter.cc | 21 +- src/db/db/dbLayoutToNetlistWriter.h | 3 +- src/db/db/dbNetShape.cc | 218 ++++++++++++++++++ src/db/db/dbNetShape.h | 178 ++++++++++++++ src/db/db/dbNetlistDeviceExtractor.cc | 36 +-- src/db/db/dbNetlistDeviceExtractor.h | 9 +- src/db/db/dbNetlistExtractor.cc | 62 +++-- src/db/db/dbNetlistExtractor.h | 7 +- src/db/db/dbRegionUtils.cc | 24 +- src/db/db/dbRegionUtils.h | 12 +- src/db/db/dbShapeRepository.h | 9 + src/db/db/dbShapes.cc | 36 ++- src/db/db/dbText.h | 34 +++ src/db/db/dbTextsUtils.h | 19 +- .../unit_tests/dbHierNetworkProcessorTests.cc | 46 ++-- src/db/unit_tests/dbLayoutToNetlistTests.cc | 2 +- src/db/unit_tests/dbNetShapeTests.cc | 187 +++++++++++++++ .../dbNetlistDeviceExtractorTests.cc | 24 +- src/db/unit_tests/dbNetlistExtractorTests.cc | 40 ++-- src/db/unit_tests/unit_tests.pro | 3 +- src/laybasic/laybasic/layNetInfoDialog.cc | 10 +- .../laybasic/layNetlistBrowserPage.cc | 12 +- 39 files changed, 1217 insertions(+), 302 deletions(-) create mode 100644 src/db/db/dbNetShape.cc create mode 100644 src/db/db/dbNetShape.h create mode 100644 src/db/unit_tests/dbNetShapeTests.cc diff --git a/src/db/db/db.pro b/src/db/db/db.pro index 0d7823d6c..0c46d7302 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -193,7 +193,8 @@ SOURCES = \ dbEmptyTexts.cc \ dbFlatTexts.cc \ dbTextsUtils.cc \ - dbOriginalLayerTexts.cc + dbOriginalLayerTexts.cc \ + dbNetShape.cc HEADERS = \ dbArray.h \ @@ -348,7 +349,8 @@ HEADERS = \ dbEmptyTexts.h \ dbFlatTexts.h \ dbTextsUtils.h \ - dbOriginalLayerTexts.h + dbOriginalLayerTexts.h \ + dbNetShape.h !equals(HAVE_QT, "0") { diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index 65966361e..d69bf3959 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -394,7 +394,7 @@ AsIfFlatRegion::selected_interacting_generic (const Texts &other, bool inverse) scanner.reserve2 (other.size ()); std::auto_ptr output (new FlatRegion (false)); - region_to_text_interaction_filter filter (output->raw_polygons (), inverse); + region_to_text_interaction_filter filter (output->raw_polygons (), inverse); AddressablePolygonDelivery p (begin_merged (), has_valid_merged_polygons ()); @@ -527,7 +527,7 @@ AsIfFlatRegion::pull_generic (const Texts &other) const scanner.reserve2 (other.size ()); std::auto_ptr output (new FlatTexts (false)); - region_to_text_interaction_filter filter (output->raw_texts (), false); + region_to_text_interaction_filter filter (output->raw_texts (), false); AddressablePolygonDelivery p (begin (), has_valid_merged_polygons ()); diff --git a/src/db/db/dbAsIfFlatTexts.cc b/src/db/db/dbAsIfFlatTexts.cc index 4bad031a1..a3b8a1958 100644 --- a/src/db/db/dbAsIfFlatTexts.cc +++ b/src/db/db/dbAsIfFlatTexts.cc @@ -312,13 +312,13 @@ AsIfFlatTexts::selected_interacting_generic (const Region &other, bool inverse) if (! inverse) { - text_to_region_interaction_filter filter (*output); + text_to_region_interaction_filter filter (*output); scanner.process (filter, 1, db::box_convert (), db::box_convert ()); } else { std::set interacting; - text_to_region_interaction_filter > filter (interacting); + text_to_region_interaction_filter, db::Text> filter (interacting); scanner.process (filter, 1, db::box_convert (), db::box_convert ()); for (TextsIterator o (begin ()); ! o.at_end (); ++o) { @@ -356,7 +356,7 @@ AsIfFlatTexts::pull_generic (const Region &other) const std::auto_ptr output (new FlatRegion (true)); - text_to_region_interaction_filter filter (*output); + text_to_region_interaction_filter filter (*output); scanner.process (filter, 1, db::box_convert (), db::box_convert ()); return output.release (); diff --git a/src/db/db/dbDeepEdges.cc b/src/db/db/dbDeepEdges.cc index d8371e563..5ed7bfb46 100644 --- a/src/db/db/dbDeepEdges.cc +++ b/src/db/db/dbDeepEdges.cc @@ -417,7 +417,7 @@ DeepEdges::ensure_merged_edges_valid () const db::Connectivity conn; conn.connect (m_deep_layer); hc.set_base_verbosity (base_verbosity() + 10); - hc.build (layout, m_deep_layer.initial_cell (), db::ShapeIterator::Edges, conn); + hc.build (layout, m_deep_layer.initial_cell (), conn); // collect the clusters and merge them into big polygons // NOTE: using the ClusterMerger we merge bottom-up forming bigger and bigger polygons. This is @@ -1077,7 +1077,7 @@ RegionDelegate *DeepEdges::extended (coord_type ext_b, coord_type ext_e, coord_t db::Connectivity conn (db::Connectivity::EdgesConnectByPoints); conn.connect (edges); hc.set_base_verbosity (base_verbosity () + 10); - hc.build (layout, edges.initial_cell (), db::ShapeIterator::Edges, conn); + hc.build (layout, edges.initial_cell (), conn); // TODO: iterate only over the called cells? for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index 42510cb7d..dac586f86 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -455,7 +455,7 @@ DeepRegion::ensure_merged_polygons_valid () const db::Connectivity conn; conn.connect (m_deep_layer); hc.set_base_verbosity (base_verbosity () + 10); - hc.build (layout, m_deep_layer.initial_cell (), db::ShapeIterator::Polygons, conn); + hc.build (layout, m_deep_layer.initial_cell (), conn); // collect the clusters and merge them into big polygons // NOTE: using the ClusterMerger we merge bottom-up forming bigger and bigger polygons. This is @@ -1238,7 +1238,7 @@ DeepRegion::merged (bool min_coherence, unsigned int min_wc) const db::Connectivity conn; conn.connect (m_deep_layer); hc.set_base_verbosity (base_verbosity () + 10); - hc.build (layout, m_deep_layer.initial_cell (), db::ShapeIterator::Polygons, conn); + hc.build (layout, m_deep_layer.initial_cell (), conn); // collect the clusters and merge them into big polygons // NOTE: using the ClusterMerger we merge bottom-up forming bigger and bigger polygons. This is @@ -1899,25 +1899,25 @@ public: struct TextResultInserter { - typedef db::Text value_type; + typedef db::TextRef value_type; - TextResultInserter (std::unordered_set &result) + TextResultInserter (std::unordered_set &result) : mp_result (&result) { // .. nothing yet .. } - void insert (const db::Text &e) + void insert (const db::TextRef &e) { (*mp_result).insert (e); } private: - std::unordered_set *mp_result; + std::unordered_set *mp_result; }; class PullWithTextLocalOperation - : public local_operation + : public local_operation { public: PullWithTextLocalOperation () @@ -1931,15 +1931,15 @@ public: return 1; } - virtual void compute_local (db::Layout *, const shape_interactions &interactions, std::unordered_set &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const + virtual void compute_local (db::Layout *, const shape_interactions &interactions, std::unordered_set &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const { - db::box_scanner2 scanner; + db::box_scanner2 scanner; TextResultInserter inserter (result); - region_to_text_interaction_filter filter (inserter, false); + region_to_text_interaction_filter filter (inserter, false); - for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { - for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { scanner.insert2 (& interactions.intruder_shape (*j), 0); } } @@ -1954,7 +1954,7 @@ public: } - scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); } virtual on_empty_intruder_mode on_empty_intruder_hint () const @@ -1969,7 +1969,7 @@ public: }; class InteractingWithTextLocalOperation - : public local_operation + : public local_operation { public: InteractingWithTextLocalOperation (bool inverse) @@ -1984,12 +1984,12 @@ public: return 1; } - virtual void compute_local (db::Layout *layout, const shape_interactions &interactions, std::unordered_set &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const + virtual void compute_local (db::Layout *layout, const shape_interactions &interactions, std::unordered_set &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const { - db::box_scanner2 scanner; + db::box_scanner2 scanner; ResultInserter inserter (layout, result); - region_to_text_interaction_filter filter (inserter, m_inverse); + region_to_text_interaction_filter filter (inserter, m_inverse); for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { @@ -2010,7 +2010,7 @@ public: } - scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); if (m_inverse) { filter.fill_output (); } @@ -2199,7 +2199,7 @@ DeepRegion::pull_generic (const Texts &other) const db::PullWithTextLocalOperation op; - db::local_processor proc (const_cast (&polygons.layout ()), const_cast (&polygons.initial_cell ()), &other_texts.layout (), &other_texts.initial_cell (), polygons.breakout_cells (), other_texts.breakout_cells ()); + db::local_processor proc (const_cast (&polygons.layout ()), const_cast (&polygons.initial_cell ()), &other_texts.layout (), &other_texts.initial_cell (), polygons.breakout_cells (), other_texts.breakout_cells ()); proc.set_base_verbosity (base_verbosity ()); proc.set_threads (polygons.store ()->threads ()); proc.run (&op, polygons.layer (), other_texts.layer (), dl_out.layer ()); @@ -2229,7 +2229,7 @@ DeepRegion::selected_interacting_generic (const Texts &other, bool inverse) cons db::InteractingWithTextLocalOperation op (inverse); - db::local_processor proc (const_cast (&polygons.layout ()), const_cast (&polygons.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), polygons.breakout_cells (), other_deep->deep_layer ().breakout_cells ()); + db::local_processor proc (const_cast (&polygons.layout ()), const_cast (&polygons.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), polygons.breakout_cells (), other_deep->deep_layer ().breakout_cells ()); proc.set_base_verbosity (base_verbosity ()); proc.set_threads (polygons.store ()->threads ()); if (split_after) { diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index b678b302f..c8f249a76 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -474,7 +474,7 @@ DeepLayer DeepShapeStore::create_from_flat (const db::Texts &texts, const db::IC db::Shapes *shapes = &initial_cell ().shapes (layer); db::Box world = db::Box::world (); - db::TextBuildingHierarchyBuilderShapeReceiver tb; + db::TextBuildingHierarchyBuilderShapeReceiver tb (&layout ()); std::pair ii = texts.begin_iter (); db::ICplxTrans ttop = trans * ii.second; @@ -849,7 +849,10 @@ DeepLayer DeepShapeStore::create_edge_pair_layer (const db::RecursiveShapeIterat DeepLayer DeepShapeStore::create_text_layer (const db::RecursiveShapeIterator &si, const db::ICplxTrans &trans) { - db::TextBuildingHierarchyBuilderShapeReceiver refs; + unsigned int layout_index = layout_for_iter (si, trans); + db::Layout &layout = m_layouts[layout_index]->layout; + + db::TextBuildingHierarchyBuilderShapeReceiver refs (&layout); return create_custom_layer (si, &refs, trans); } diff --git a/src/db/db/dbDeepTexts.cc b/src/db/db/dbDeepTexts.cc index 73739984f..5165de7f2 100644 --- a/src/db/db/dbDeepTexts.cc +++ b/src/db/db/dbDeepTexts.cc @@ -408,7 +408,7 @@ void DeepTexts::insert_into_as_polygons (Layout *layout, db::cell_index_type int namespace { class Text2PolygonInteractingLocalOperation - : public local_operation + : public local_operation { public: Text2PolygonInteractingLocalOperation (bool inverse) @@ -423,19 +423,19 @@ public: return 1; } - virtual void compute_local (db::Layout * /*layout*/, const shape_interactions &interactions, std::unordered_set &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const + virtual void compute_local (db::Layout * /*layout*/, const shape_interactions &interactions, std::unordered_set &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const { - db::box_scanner2 scanner; + db::box_scanner2 scanner; std::set others; - for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { - for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { others.insert (interactions.intruder_shape (*j)); } } - for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { - const db::Text &subject = interactions.subject_shape (i->first); + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + const db::TextRef &subject = interactions.subject_shape (i->first); scanner.insert1 (&subject, 0); } @@ -447,12 +447,12 @@ public: if (m_inverse) { - std::unordered_set interacting; - text_to_region_interaction_filter > filter (interacting); - scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + std::unordered_set interacting; + text_to_region_interaction_filter, db::TextRef> filter (interacting); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); - for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { - const db::Text &subject = interactions.subject_shape (i->first); + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + const db::TextRef &subject = interactions.subject_shape (i->first); if (interacting.find (subject) == interacting.end ()) { result.insert (subject); } @@ -460,8 +460,8 @@ public: } else { - text_to_region_interaction_filter > filter (result); - scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + text_to_region_interaction_filter, db::TextRef> filter (result); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); } } @@ -505,7 +505,7 @@ private: }; class Text2PolygonPullLocalOperation - : public local_operation + : public local_operation { public: Text2PolygonPullLocalOperation () @@ -519,19 +519,19 @@ public: return 1; } - virtual void compute_local (db::Layout *layout, const shape_interactions &interactions, std::unordered_set &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const + virtual void compute_local (db::Layout *layout, const shape_interactions &interactions, std::unordered_set &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const { - db::box_scanner2 scanner; + db::box_scanner2 scanner; std::set others; - for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { - for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + for (shape_interactions::iterator2 j = i->second.begin (); j != i->second.end (); ++j) { others.insert (interactions.intruder_shape (*j)); } } - for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { - const db::Text &subject = interactions.subject_shape (i->first); + for (shape_interactions::iterator i = interactions.begin (); i != interactions.end (); ++i) { + const db::TextRef &subject = interactions.subject_shape (i->first); scanner.insert1 (&subject, 1); } @@ -542,8 +542,8 @@ public: } ResultInserter inserter (layout, result); - text_to_region_interaction_filter filter (inserter); - scanner.process (filter, 1, db::box_convert (), db::box_convert ()); + text_to_region_interaction_filter filter (inserter); + scanner.process (filter, 1, db::box_convert (), db::box_convert ()); } virtual on_empty_intruder_mode on_empty_intruder_hint () const @@ -576,7 +576,7 @@ DeepTexts::selected_interacting_generic (const Region &other, bool inverse) cons db::Text2PolygonInteractingLocalOperation op (inverse); - db::local_processor proc (const_cast (&texts.layout ()), const_cast (&texts.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ()); + db::local_processor proc (const_cast (&texts.layout ()), const_cast (&texts.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ()); proc.set_base_verbosity (other.base_verbosity ()); proc.set_threads (texts.store ()->threads ()); @@ -602,7 +602,7 @@ RegionDelegate *DeepTexts::pull_generic (const Region &other) const db::Text2PolygonPullLocalOperation op; - db::local_processor proc (const_cast (&texts.layout ()), const_cast (&texts.initial_cell ()), &other_polygons.layout (), &other_polygons.initial_cell ()); + db::local_processor proc (const_cast (&texts.layout ()), const_cast (&texts.initial_cell ()), &other_polygons.layout (), &other_polygons.initial_cell ()); proc.set_base_verbosity (other.base_verbosity ()); proc.set_threads (texts.store ()->threads ()); diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index 08ca4d269..babb8d5fc 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -29,6 +29,7 @@ #include "dbPolygonTools.h" #include "dbBoxScanner.h" #include "dbDeepRegion.h" +#include "dbNetShape.h" #include "tlProgress.h" #include "tlLog.h" #include "tlTimer.h" @@ -43,9 +44,9 @@ namespace db // ------------------------------------------------------------------------------ -template void insert_transformed (db::Layout &layout, Container &shapes, const Shape &s, const Trans &t); +template void insert_transformed (db::Layout &layout, db::Shapes &shapes, const Shape &s, const Trans &t); -template void insert_transformed (db::Layout &layout, Container &shapes, const db::PolygonRef &s, const Trans &t) +template void insert_transformed (db::Layout &layout, db::Shapes &shapes, const db::PolygonRef &s, const Trans &t) { db::Polygon poly = s.obj (); poly.transform (s.trans ()); @@ -55,7 +56,32 @@ template void insert_transformed (db::Layout &lay shapes.insert (db::PolygonRef (poly, layout.shape_repository ())); } -template void insert_transformed (db::Layout & /*layout*/, Container &shapes, const db::Edge &s, const Trans &t) +template void insert_transformed (db::Layout &layout, db::Shapes &shapes, const db::NetShape &s, const Trans &t) +{ + if (s.type () == db::NetShape::Polygon) { + + db::PolygonRef pr = s.polygon_ref (); + db::Polygon poly = pr.obj (); + poly.transform (pr.trans ()); + if (! t.is_unity ()) { + poly.transform (t); + } + shapes.insert (db::PolygonRef (poly, layout.shape_repository ())); + + } else if (s.type () == db::NetShape::Text) { + + db::TextRef tr = s.text_ref (); + db::Text text = tr.obj (); + text.transform (tr.trans ()); + if (! t.is_unity ()) { + text.transform (t); + } + shapes.insert (db::TextRef (text, layout.shape_repository ())); + + } +} + +template void insert_transformed (db::Layout & /*layout*/, db::Shapes &shapes, const db::Edge &s, const Trans &t) { shapes.insert (s.transformed (t)); } @@ -237,6 +263,20 @@ interaction_test (const db::PolygonRef &a, const db::PolygonRef &b, const db::un } } +template +static bool +interaction_test (const db::NetShape &a, const db::NetShape &b, const Trans &trans, db::Connectivity::edge_connectivity_type) +{ + return a.interacts_with_transformed (b, trans); +} + +template +static bool +interaction_test (const db::NetShape &a, const db::NetShape &b, const db::unit_trans &, db::Connectivity::edge_connectivity_type) +{ + return a.interacts_with (b); +} + template static bool interaction_test (const db::Edge &a, const db::Edge &b, const Trans &trans, db::Connectivity::edge_connectivity_type ec) @@ -272,6 +312,8 @@ bool Connectivity::interacts (const T &a, unsigned int la, const T &b, unsigned } // explicit instantiations +template DB_PUBLIC bool Connectivity::interacts (const db::NetShape &a, unsigned int la, const db::NetShape &b, unsigned int lb, const db::UnitTrans &trans) const; +template DB_PUBLIC bool Connectivity::interacts (const db::NetShape &a, unsigned int la, const db::NetShape &b, unsigned int lb, const db::ICplxTrans &trans) const; template DB_PUBLIC bool Connectivity::interacts (const db::PolygonRef &a, unsigned int la, const db::PolygonRef &b, unsigned int lb, const db::UnitTrans &trans) const; template DB_PUBLIC bool Connectivity::interacts (const db::PolygonRef &a, unsigned int la, const db::PolygonRef &b, unsigned int lb, const db::ICplxTrans &trans) const; template DB_PUBLIC bool Connectivity::interacts (const db::Edge &a, unsigned int la, const db::Edge &b, unsigned int lb, const db::UnitTrans &trans) const; @@ -630,8 +672,10 @@ size_t local_cluster::split (double max_area_ratio, Iter &output) const } // explicit instantiations +template class DB_PUBLIC local_cluster; template class DB_PUBLIC local_cluster; template class DB_PUBLIC local_cluster; +template DB_PUBLIC size_t local_cluster::split > > > (double, std::back_insert_iterator > > &) const; template DB_PUBLIC size_t local_cluster::split > > > (double, std::back_insert_iterator > > &) const; template DB_PUBLIC size_t local_cluster::split > > > (double, std::back_insert_iterator > > &) const; @@ -886,22 +930,112 @@ private: } }; +template +struct addressable_shape_delivery +{ + const T *operator () (const db::Shape &shape) + { + typename T::tag object_tag; + return shape.basic_ptr (object_tag); + } +}; + +template <> +struct addressable_shape_delivery +{ + const NetShape *operator () (const db::Shape &shape) + { + if (shape.type () == db::Shape::TextRef) { + m_heap.push_back (db::NetShape (shape.text_ref ())); + return &m_heap.back (); + } else if (shape.type () == db::Shape::PolygonRef) { + m_heap.push_back (db::NetShape (shape.polygon_ref ())); + return &m_heap.back (); + } else { + tl_assert (false); + } + } + +private: + std::list m_heap; +}; + +template +struct attr_accessor +{ + size_t operator() (const db::Shape &shape) const + { + return shape.prop_id (); + } +}; + +template <> +struct attr_accessor +{ + size_t operator() (const db::Shape &shape) const + { + // NOTE: the attribute is + // * odd: a StringRef pointer's value + // * even: a Property ID times 2 + if (shape.type () == db::Shape::TextRef) { + return db::text_ref_to_attr (&shape.text_ref ().obj ()); + } else { + return db::prop_id_to_attr (shape.prop_id ()); + } + } +}; + +template struct get_shape_flags { }; + +template <> +struct get_shape_flags +{ + db::ShapeIterator::flags_type operator() (bool /*with_attr*/) const + { + return db::ShapeIterator::Edges; + } +}; + +template <> +struct get_shape_flags +{ + db::ShapeIterator::flags_type operator() (bool /*with_attr*/) const + { + return db::ShapeIterator::Polygons; + } +}; + +template <> +struct get_shape_flags +{ + db::ShapeIterator::flags_type operator() (bool with_attr) const + { + if (with_attr) { + return db::ShapeIterator::flags_type (db::ShapeIterator::Polygons | db::ShapeIterator::Texts); + } else { + return db::ShapeIterator::flags_type (db::ShapeIterator::Polygons); + } + } +}; + } template void -local_clusters::build_clusters (const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const tl::equivalence_clusters *attr_equivalence, bool report_progress) +local_clusters::build_clusters (const db::Cell &cell, const db::Connectivity &conn, const tl::equivalence_clusters *attr_equivalence, bool report_progress) { static std::string desc = tl::to_string (tr ("Building local clusters")); - db::box_scanner > bs (report_progress, desc); - typename T::tag object_tag; + db::box_scanner > bs (report_progress, desc); db::box_convert bc; + addressable_shape_delivery heap; + attr_accessor attr; + db::ShapeIterator::flags_type shape_flags = get_shape_flags () (attr_equivalence != 0 /*with attributes*/); for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) { const db::Shapes &shapes = cell.shapes (*l); for (db::Shapes::shape_iterator s = shapes.begin (shape_flags); ! s.at_end (); ++s) { - bs.insert (s->basic_ptr (object_tag), std::make_pair (*l, (unsigned int) s->prop_id ())); + bs.insert (heap (*s), std::make_pair (*l, attr (*s))); } } @@ -916,9 +1050,9 @@ local_clusters::build_clusters (const db::Cell &cell, db::ShapeIterator::flag template void -local_clusters::apply_attr_equivalences (const tl::equivalence_clusters &attr_equivalence) +local_clusters::apply_attr_equivalences (const tl::equivalence_clusters &attr_equivalence) { - tl::equivalence_clusters eq; + tl::equivalence_clusters eq; // collect all local attributes (the ones which are present in attr_equivalence) into "eq" // and form equivalences for multi-attribute clusters. @@ -939,18 +1073,18 @@ local_clusters::apply_attr_equivalences (const tl::equivalence_clusters::cluster_id_type, std::set > c2c; + std::map::cluster_id_type, std::set > c2c; for (const_iterator c = begin (); c != end (); ++c) { for (typename local_cluster::attr_iterator a = c->begin_attr (); a != c->end_attr (); ++a) { - tl::equivalence_clusters::cluster_id_type cl = attr_equivalence.cluster_id (*a); + tl::equivalence_clusters::cluster_id_type cl = attr_equivalence.cluster_id (*a); if (cl > 0) { c2c [cl].insert (c->id ()); } } } - for (std::map::cluster_id_type, std::set >::const_iterator c = c2c.begin (); c != c2c.end (); ++c) { + for (std::map::cluster_id_type, std::set >::const_iterator c = c2c.begin (); c != c2c.end (); ++c) { if (c->second.size () > 1) { std::set::const_iterator cl0 = c->second.begin (); std::set::const_iterator cl = cl0; @@ -962,6 +1096,7 @@ local_clusters::apply_attr_equivalences (const tl::equivalence_clusters; template class DB_PUBLIC local_clusters; template class DB_PUBLIC local_clusters; @@ -984,6 +1119,7 @@ connected_clusters_iterator::connected_clusters_iterator (const connected_clu } // explicit instantiations +template class DB_PUBLIC connected_clusters_iterator; template class DB_PUBLIC connected_clusters_iterator; template class DB_PUBLIC connected_clusters_iterator; @@ -1053,6 +1189,7 @@ connected_clusters::find_cluster_with_connection (const ClusterInstance &inst } // explicit instantiations +template class DB_PUBLIC connected_clusters; template class DB_PUBLIC connected_clusters; template class DB_PUBLIC connected_clusters; @@ -1133,11 +1270,11 @@ void hier_clusters::clear () template void -hier_clusters::build (const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const std::map > *attr_equivalence, const std::set *breakout_cells) +hier_clusters::build (const db::Layout &layout, const db::Cell &cell, const db::Connectivity &conn, const std::map > *attr_equivalence, const std::set *breakout_cells) { clear (); cell_clusters_box_converter cbc (layout, *this); - do_build (cbc, layout, cell, shape_flags, conn, attr_equivalence, breakout_cells); + do_build (cbc, layout, cell, conn, attr_equivalence, breakout_cells); } namespace @@ -1939,7 +2076,7 @@ hier_clusters::propagate_cluster_inst (const db::Layout &layout, const db::Ce template void -hier_clusters::do_build (cell_clusters_box_converter &cbc, const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const std::map > *attr_equivalence, const std::set *breakout_cells) +hier_clusters::do_build (cell_clusters_box_converter &cbc, const db::Layout &layout, const db::Cell &cell, const db::Connectivity &conn, const std::map > *attr_equivalence, const std::set *breakout_cells) { tl::SelfTimer timer (tl::verbosity () > m_base_verbosity, tl::to_string (tr ("Computing shape clusters"))); @@ -1957,8 +2094,8 @@ hier_clusters::do_build (cell_clusters_box_converter &cbc, const db::Layou // look for the net label joining spec - for the top cell the "top_cell_index" entry is looked for. // If there is no such entry or the cell is not the top cell, look for the entry by cell index. - std::map >::const_iterator ae; - const tl::equivalence_clusters *ec = 0; + std::map >::const_iterator ae; + const tl::equivalence_clusters *ec = 0; if (attr_equivalence) { if (*c == cell.cell_index ()) { ae = attr_equivalence->find (top_cell_index); @@ -1974,7 +2111,7 @@ hier_clusters::do_build (cell_clusters_box_converter &cbc, const db::Layou } } - build_local_cluster (layout, layout.cell (*c), shape_flags, conn, ec); + build_local_cluster (layout, layout.cell (*c), conn, ec); ++progress; @@ -2021,7 +2158,7 @@ hier_clusters::do_build (cell_clusters_box_converter &cbc, const db::Layou template void -hier_clusters::build_local_cluster (const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const tl::equivalence_clusters *attr_equivalence) +hier_clusters::build_local_cluster (const db::Layout &layout, const db::Cell &cell, const db::Connectivity &conn, const tl::equivalence_clusters *attr_equivalence) { std::string msg = tl::to_string (tr ("Computing local clusters for cell: ")) + std::string (layout.cell_name (cell.cell_index ())); if (tl::verbosity () >= m_base_verbosity + 20) { @@ -2030,7 +2167,7 @@ hier_clusters::build_local_cluster (const db::Layout &layout, const db::Cell tl::SelfTimer timer (tl::verbosity () > m_base_verbosity + 20, msg); connected_clusters &local = m_per_cell_clusters [cell.cell_index ()]; - local.build_clusters (cell, shape_flags, conn, attr_equivalence, true); + local.build_clusters (cell, conn, attr_equivalence, true); } template @@ -2336,6 +2473,7 @@ hier_clusters::return_to_hierarchy (db::Layout &layout, const std::map; template class DB_PUBLIC hier_clusters; template class DB_PUBLIC hier_clusters; @@ -2460,6 +2598,7 @@ void recursive_cluster_shape_iterator::down (db::cell_index_type ci, typename } // explicit instantiations +template class DB_PUBLIC recursive_cluster_shape_iterator; template class DB_PUBLIC recursive_cluster_shape_iterator; template class DB_PUBLIC recursive_cluster_shape_iterator; @@ -2533,6 +2672,7 @@ void recursive_cluster_iterator::down (db::cell_index_type ci, typename db::l } // explicit instantiations +template class DB_PUBLIC recursive_cluster_iterator; template class DB_PUBLIC recursive_cluster_iterator; template class DB_PUBLIC recursive_cluster_iterator; @@ -2614,6 +2754,7 @@ incoming_cluster_connections::ensure_computed_parent (db::cell_index_type ci) } // explicit instantiations +template class DB_PUBLIC incoming_cluster_connections; template class DB_PUBLIC incoming_cluster_connections; template class DB_PUBLIC incoming_cluster_connections; diff --git a/src/db/db/dbHierNetworkProcessor.h b/src/db/db/dbHierNetworkProcessor.h index 197ae8a0e..577eef944 100644 --- a/src/db/db/dbHierNetworkProcessor.h +++ b/src/db/db/dbHierNetworkProcessor.h @@ -505,7 +505,7 @@ public: * cluster joining may happen in this case, because multi-attribute * assignment might create connections too. */ - void build_clusters (const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const tl::equivalence_clusters *attr_equivalence = 0, bool report_progress = false); + void build_clusters (const db::Cell &cell, const db::Connectivity &conn, const tl::equivalence_clusters *attr_equivalence = 0, bool report_progress = false); /** * @brief Creates and inserts a new clusters @@ -540,7 +540,7 @@ private: tree_type m_clusters; size_t m_next_dummy_id; - void apply_attr_equivalences (const tl::equivalence_clusters &attr_equivalence); + void apply_attr_equivalences (const tl::equivalence_clusters &attr_equivalence); }; /** @@ -998,7 +998,7 @@ public: /** * @brief Builds a hierarchy of clusters from a cell hierarchy and given connectivity */ - void build (const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const std::map > *attr_equivalence = 0, const std::set *breakout_cells = 0); + void build (const db::Layout &layout, const db::Cell &cell, const db::Connectivity &conn, const std::map > *attr_equivalence = 0, const std::set *breakout_cells = 0); /** * @brief Gets the connected clusters for a given cell @@ -1036,10 +1036,10 @@ public: size_t propagate_cluster_inst (const db::Layout &layout, const Cell &cell, const ClusterInstance &ci, db::cell_index_type parent_ci, bool with_self); private: - void build_local_cluster (const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const tl::equivalence_clusters *attr_equivalence); + void build_local_cluster (const db::Layout &layout, const db::Cell &cell, const db::Connectivity &conn, const tl::equivalence_clusters *attr_equivalence); void build_hier_connections (cell_clusters_box_converter &cbc, const db::Layout &layout, const db::Cell &cell, const db::Connectivity &conn, const std::set *breakout_cells, instance_interaction_cache_type &instance_interaction_cache); void build_hier_connections_for_cells (cell_clusters_box_converter &cbc, const db::Layout &layout, const std::vector &cells, const db::Connectivity &conn, const std::set *breakout_cells, tl::RelativeProgress &progress, instance_interaction_cache_type &instance_interaction_cache); - void do_build (cell_clusters_box_converter &cbc, const db::Layout &layout, const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn, const std::map > *attr_equivalence, const std::set *breakout_cells); + void do_build (cell_clusters_box_converter &cbc, const db::Layout &layout, const db::Cell &cell, const db::Connectivity &conn, const std::map > *attr_equivalence, const std::set *breakout_cells); std::map > m_per_cell_clusters; int m_base_verbosity; @@ -1335,6 +1335,39 @@ private: void ensure_computed_parent (db::cell_index_type ci) const; }; +/** + * @brief A helper function generating an attribute ID from a property ID + * This function is used to provide a generic attribute wrapping a property ID and a text ID. + */ +inline size_t prop_id_to_attr (db::properties_id_type id) +{ + return size_t (id) * 2; +} + +/** + * @brief Gets a value indicating whether the attribute is a property ID + */ +inline bool is_prop_id_attr (size_t attr) +{ + return (attr & 1) == 0; +} + +/** + * @brief Gets the property ID from an attribute + */ +inline db::properties_id_type prop_id_from_attr (size_t attr) +{ + return attr / 2; +} + +/** + * @brief A helper function generating an attribute from a StringRef + */ +inline size_t text_ref_to_attr (const db::Text *tr) +{ + return size_t (tr) * 2 + 1; +} + } #endif diff --git a/src/db/db/dbHierProcessor.cc b/src/db/db/dbHierProcessor.cc index 2db262ac4..674f81430 100644 --- a/src/db/db/dbHierProcessor.cc +++ b/src/db/db/dbHierProcessor.cc @@ -157,29 +157,6 @@ public: } }; -template <> -class shape_reference_translator -{ -public: - typedef db::Text shape_type; - - shape_reference_translator (db::Layout * /*target_layout*/) - { - // .. nothing yet .. - } - - const shape_type &operator() (const shape_type &s) const - { - return s; - } - - template - shape_type operator() (const shape_type &s, const Trans &tr) const - { - return s.transformed (tr); - } -}; - template class shape_reference_translator_with_trans_from_shape_ref { @@ -656,11 +633,11 @@ shape_interactions::intruder_shape (unsigned int id) const template class DB_PUBLIC shape_interactions; template class DB_PUBLIC shape_interactions; -template class DB_PUBLIC shape_interactions; +template class DB_PUBLIC shape_interactions; template class DB_PUBLIC shape_interactions; template class DB_PUBLIC shape_interactions; -template class DB_PUBLIC shape_interactions; -template class DB_PUBLIC shape_interactions; +template class DB_PUBLIC shape_interactions; +template class DB_PUBLIC shape_interactions; // --------------------------------------------------------------------------------------------- // Helper classes for the LocalProcessor @@ -683,7 +660,7 @@ inline unsigned int shape_flags () } template <> -inline unsigned int shape_flags () +inline unsigned int shape_flags () { return db::ShapeIterator::Texts; } @@ -1780,15 +1757,15 @@ local_processor::compute_local_cell (const db::local_processor_conte template class DB_PUBLIC local_processor; template class DB_PUBLIC local_processor; template class DB_PUBLIC local_processor; -template class DB_PUBLIC local_processor; -template class DB_PUBLIC local_processor; +template class DB_PUBLIC local_processor; +template class DB_PUBLIC local_processor; template class DB_PUBLIC local_processor; template class DB_PUBLIC local_processor; template class DB_PUBLIC local_processor; template class DB_PUBLIC local_processor; template class DB_PUBLIC local_processor; -template class DB_PUBLIC local_processor; -template class DB_PUBLIC local_processor; +template class DB_PUBLIC local_processor; +template class DB_PUBLIC local_processor; } diff --git a/src/db/db/dbHierarchyBuilder.cc b/src/db/db/dbHierarchyBuilder.cc index 5ea489b02..35424cabc 100644 --- a/src/db/db/dbHierarchyBuilder.cc +++ b/src/db/db/dbHierarchyBuilder.cc @@ -706,7 +706,8 @@ void EdgePairBuildingHierarchyBuilderShapeReceiver::push (const db::Shape &shape // --------------------------------------------------------------------------------------------- -TextBuildingHierarchyBuilderShapeReceiver::TextBuildingHierarchyBuilderShapeReceiver () +TextBuildingHierarchyBuilderShapeReceiver::TextBuildingHierarchyBuilderShapeReceiver (db::Layout *layout) + : mp_layout (layout) { // .. nothing yet .. } @@ -714,10 +715,10 @@ TextBuildingHierarchyBuilderShapeReceiver::TextBuildingHierarchyBuilderShapeRece void TextBuildingHierarchyBuilderShapeReceiver::push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box & /*region*/, const db::RecursiveShapeReceiver::box_tree_type * /*complex_region*/, db::Shapes *target) { if (shape.is_text ()) { - db::Text t; - shape.text (t); - t.transform (trans); - target->insert (t); + // NOTE: we intentionally skip all the text attributes (font etc.) here because in the context + // of a text collections we're only interested in the locations. + db::Text t (shape.text_string (), shape.text_trans ()); + target->insert (db::TextRef (t.transformed (trans), mp_layout->shape_repository ())); } } diff --git a/src/db/db/dbHierarchyBuilder.h b/src/db/db/dbHierarchyBuilder.h index 9b115bb05..2ddd6fe22 100644 --- a/src/db/db/dbHierarchyBuilder.h +++ b/src/db/db/dbHierarchyBuilder.h @@ -196,11 +196,14 @@ class DB_PUBLIC TextBuildingHierarchyBuilderShapeReceiver : public HierarchyBuilderShapeReceiver { public: - TextBuildingHierarchyBuilderShapeReceiver (); + TextBuildingHierarchyBuilderShapeReceiver (db::Layout *layout); virtual void push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *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: + db::Layout *mp_layout; }; /** diff --git a/src/db/db/dbLayout.h b/src/db/db/dbLayout.h index dd39be48e..96aaf475e 100644 --- a/src/db/db/dbLayout.h +++ b/src/db/db/dbLayout.h @@ -558,6 +558,14 @@ public: return m_string_repository; } + /** + * @brief Accessor to the string repository (const version) + */ + const StringRepository &string_repository () const + { + return m_string_repository; + } + /** * @brief Accessor to the shape repository */ @@ -566,6 +574,14 @@ public: return m_shape_repository; } + /** + * @brief Accessor to the shape repository (const version) + */ + const GenericRepository &shape_repository () const + { + return m_shape_repository; + } + /** * @brief Accessor to the properties repository */ diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index d362aa4c5..479e67ed0 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -206,7 +206,7 @@ void LayoutToNetlist::link_nets (const db::Net *net, const db::Net *with) return; } - connected_clusters &clusters = m_net_clusters.clusters_per_cell (net->circuit ()->cell_index ()); + connected_clusters &clusters = m_net_clusters.clusters_per_cell (net->circuit ()->cell_index ()); clusters.join_cluster_with (net->cluster_id (), with->cluster_id ()); } @@ -221,7 +221,7 @@ size_t LayoutToNetlist::link_net_to_parent_circuit (const Net *subcircuit_net, C db::CplxTrans dbu_trans (internal_layout ()->dbu ()); db::ICplxTrans trans = dbu_trans.inverted () * dtrans * dbu_trans; - connected_clusters &parent_net_clusters = m_net_clusters.clusters_per_cell (parent_circuit->cell_index ()); + connected_clusters &parent_net_clusters = m_net_clusters.clusters_per_cell (parent_circuit->cell_index ()); size_t id = parent_net_clusters.insert_dummy (); @@ -613,49 +613,84 @@ namespace } template -static bool deliver_shape (const db::PolygonRef &, StopOnFirst, const Tr &, db::properties_id_type) +static bool deliver_shape (const db::NetShape &, StopOnFirst, const Tr &, db::properties_id_type) { return false; } template -static bool deliver_shape (const db::PolygonRef &pr, db::Region ®ion, const Tr &tr, db::properties_id_type /*propid*/) +static bool deliver_shape (const db::NetShape &s, db::Region ®ion, const Tr &tr, db::properties_id_type /*propid*/) { - if (pr.obj ().is_box ()) { - region.insert (pr.obj ().box ().transformed (pr.trans ()).transformed (tr)); - } else { - region.insert (pr.obj ().transformed (pr.trans ()).transformed (tr)); + if (s.type () == db::NetShape::Polygon) { + + db::PolygonRef pr = s.polygon_ref (); + + if (pr.obj ().is_box ()) { + region.insert (pr.obj ().box ().transformed (pr.trans ()).transformed (tr)); + } else { + region.insert (pr.obj ().transformed (pr.trans ()).transformed (tr)); + } + } + return true; } template -static bool deliver_shape (const db::PolygonRef &pr, db::Shapes &shapes, const Tr &tr, db::properties_id_type propid) +static bool deliver_shape (const db::NetShape &s, db::Shapes &shapes, const Tr &tr, db::properties_id_type propid) { - if (pr.obj ().is_box ()) { - if (propid) { - shapes.insert (db::BoxWithProperties (pr.obj ().box ().transformed (pr.trans ()).transformed (tr), propid)); + if (s.type () == db::NetShape::Polygon) { + + db::PolygonRef pr = s.polygon_ref (); + + if (pr.obj ().is_box ()) { + if (propid) { + shapes.insert (db::BoxWithProperties (pr.obj ().box ().transformed (pr.trans ()).transformed (tr), propid)); + } else { + shapes.insert (pr.obj ().box ().transformed (pr.trans ()).transformed (tr)); + } } else { - shapes.insert (pr.obj ().box ().transformed (pr.trans ()).transformed (tr)); + db::Layout *layout = shapes.layout (); + if (layout) { + db::PolygonRef polygon_ref (pr.obj ().transformed (pr.trans ()).transformed (tr), layout->shape_repository ()); + if (propid) { + shapes.insert (db::PolygonRefWithProperties (polygon_ref, propid)); + } else { + shapes.insert (polygon_ref); + } + } else { + db::Polygon polygon (pr.obj ().transformed (pr.trans ()).transformed (tr)); + if (propid) { + shapes.insert (db::PolygonWithProperties (polygon, propid)); + } else { + shapes.insert (polygon); + } + } } - } else { + + } else if (s.type () == db::NetShape::Text) { + + db::TextRef pr = s.text_ref (); + db::Layout *layout = shapes.layout (); if (layout) { - db::PolygonRef polygon_ref (pr.obj ().transformed (pr.trans ()).transformed (tr), layout->shape_repository ()); + db::TextRef text_ref (pr.obj ().transformed (pr.trans ()).transformed (tr), layout->shape_repository ()); if (propid) { - shapes.insert (db::PolygonRefWithProperties (polygon_ref, propid)); + shapes.insert (db::TextRefWithProperties (text_ref, propid)); } else { - shapes.insert (polygon_ref); + shapes.insert (text_ref); } } else { - db::Polygon polygon (pr.obj ().transformed (pr.trans ()).transformed (tr)); + db::Text text (pr.obj ().transformed (pr.trans ()).transformed (tr)); if (propid) { - shapes.insert (db::PolygonWithProperties (polygon, propid)); + shapes.insert (db::TextWithProperties (text, propid)); } else { - shapes.insert (polygon); + shapes.insert (text); } } + } + return true; } @@ -759,7 +794,7 @@ LayoutToNetlist::build_net_rec (db::cell_index_type ci, size_t cid, db::Layout & if (net_cell_name_prefix) { - const db::connected_clusters &ccl = m_net_clusters.clusters_per_cell (ci); + const db::connected_clusters &ccl = m_net_clusters.clusters_per_cell (ci); bool any_connections = circuit_cell_name_prefix && ! ccl.connections_for_cluster (cid).empty (); if (! any_connections) { @@ -805,8 +840,8 @@ LayoutToNetlist::build_net_rec (db::cell_index_type ci, size_t cid, db::Layout & db::ICplxTrans tr_wo_mag = tr * db::ICplxTrans (1.0 / tr.mag ()); db::ICplxTrans tr_mag (tr.mag ()); - const db::connected_clusters &clusters = m_net_clusters.clusters_per_cell (ci); - typedef db::connected_clusters::connections_type connections_type; + const db::connected_clusters &clusters = m_net_clusters.clusters_per_cell (ci); + typedef db::connected_clusters::connections_type connections_type; const connections_type &connections = clusters.connections_for_cluster (cid); for (connections_type::const_iterator c = connections.begin (); c != connections.end (); ++c) { @@ -1007,13 +1042,13 @@ db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::DPoi return probe_net (of_region, db::CplxTrans (internal_layout ()->dbu ()).inverted () * point); } -size_t LayoutToNetlist::search_net (const db::ICplxTrans &trans, const db::Cell *cell, const db::local_cluster &test_cluster, std::vector &rev_inst_path) +size_t LayoutToNetlist::search_net (const db::ICplxTrans &trans, const db::Cell *cell, const db::local_cluster &test_cluster, std::vector &rev_inst_path) { db::Box local_box = trans * test_cluster.bbox (); - const db::local_clusters &lcc = net_clusters ().clusters_per_cell (cell->cell_index ()); - for (db::local_clusters::touching_iterator i = lcc.begin_touching (local_box); ! i.at_end (); ++i) { - const db::local_cluster &lc = *i; + const db::local_clusters &lcc = net_clusters ().clusters_per_cell (cell->cell_index ()); + for (db::local_clusters::touching_iterator i = lcc.begin_touching (local_box); ! i.at_end (); ++i) { + const db::local_cluster &lc = *i; if (lc.interacts (test_cluster, trans, m_conn)) { return lc.id (); } @@ -1053,7 +1088,7 @@ db::Net *LayoutToNetlist::probe_net (const db::Region &of_region, const db::Poin // Prepare a test cluster db::Box box (point - db::Vector (1, 1), point + db::Vector (1, 1)); db::GenericRepository sr; - db::local_cluster test_cluster; + db::local_cluster test_cluster; test_cluster.add (db::PolygonRef (db::Polygon (box), sr), layer); std::vector inst_path; @@ -1155,12 +1190,12 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, const db::Reg for (db::Layout::bottom_up_const_iterator cid = ly.begin_bottom_up (); cid != ly.end_bottom_up (); ++cid) { - const connected_clusters &clusters = m_net_clusters.clusters_per_cell (*cid); + const connected_clusters &clusters = m_net_clusters.clusters_per_cell (*cid); if (clusters.empty ()) { continue; } - for (connected_clusters::all_iterator c = clusters.begin_all (); ! c.at_end (); ++c) { + for (connected_clusters::all_iterator c = clusters.begin_all (); ! c.at_end (); ++c) { if (! clusters.is_root (*c)) { continue; diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index 6f8771644..f92632bd8 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -522,7 +522,7 @@ public: * NOTE: the layer and cell indexes used inside this structure refer to the * internal layout. */ - const db::hier_clusters &net_clusters () const + const db::hier_clusters &net_clusters () const { return m_net_clusters; } @@ -530,7 +530,7 @@ public: /** * @brief Gets the hierarchical shape clusters derived in the net extraction (non-conver version) */ - db::hier_clusters &net_clusters () + db::hier_clusters &net_clusters () { return m_net_clusters; } @@ -744,7 +744,7 @@ private: tl::weak_ptr mp_dss; unsigned int m_layout_index; db::Connectivity m_conn; - db::hier_clusters m_net_clusters; + db::hier_clusters m_net_clusters; std::auto_ptr mp_netlist; std::set m_dlrefs; std::map m_named_regions; @@ -786,7 +786,7 @@ private: void init (); void ensure_netlist (); - size_t search_net (const db::ICplxTrans &trans, const db::Cell *cell, const db::local_cluster &test_cluster, std::vector &rev_inst_path); + size_t search_net (const db::ICplxTrans &trans, const db::Cell *cell, const db::local_cluster &test_cluster, std::vector &rev_inst_path); void build_net_rec (const db::Net &net, db::Layout &target, cell_index_type circuit_cell, const db::CellMapping &cmap, const std::map &lmap, const char *net_cell_name_prefix, db::properties_id_type netname_propid, BuildNetHierarchyMode hier_mode, const char *cell_name_prefix, const char *device_cell_name_prefix, cell_reuse_table_type &reuse_table, const ICplxTrans &tr) const; void build_net_rec (const db::Net &net, db::Layout &target, db::Cell &target_cell, const std::map &lmap, const char *net_cell_name_prefix, db::properties_id_type netname_propid, BuildNetHierarchyMode hier_mode, const char *cell_name_prefix, const char *device_cell_name_prefix, cell_reuse_table_type &reuse_table, const ICplxTrans &tr) const; void build_net_rec (db::cell_index_type ci, size_t cid, db::Layout &target, db::Cell &target_cell, const std::map &lmap, const Net *net, const char *net_cell_name_prefix, db::properties_id_type netname_propid, BuildNetHierarchyMode hier_mode, const char *cell_name_prefix, const char *device_cell_name_prefix, cell_reuse_table_type &reuse_table, const ICplxTrans &tr) const; diff --git a/src/db/db/dbLayoutToNetlistReader.cc b/src/db/db/dbLayoutToNetlistReader.cc index 599b08aa1..877f9842d 100644 --- a/src/db/db/dbLayoutToNetlistReader.cc +++ b/src/db/db/dbLayoutToNetlistReader.cc @@ -524,7 +524,7 @@ LayoutToNetlistStandardReader::read_polygon () } void -LayoutToNetlistStandardReader::read_geometries (db::NetlistObject *obj, Brace &br, db::LayoutToNetlist *l2n, db::local_cluster &lc, db::Cell &cell) +LayoutToNetlistStandardReader::read_geometries (db::NetlistObject *obj, Brace &br, db::LayoutToNetlist *l2n, db::local_cluster &lc, db::Cell &cell) { m_ref = db::Point (); @@ -561,8 +561,8 @@ LayoutToNetlistStandardReader::read_net (db::Netlist * /*netlist*/, db::LayoutTo if (l2n) { - db::connected_clusters &cc = l2n->net_clusters ().clusters_per_cell (circuit->cell_index ()); - db::local_cluster &lc = *cc.insert (); + db::connected_clusters &cc = l2n->net_clusters ().clusters_per_cell (circuit->cell_index ()); + db::local_cluster &lc = *cc.insert (); net->set_cluster_id (lc.id ()); db::Cell &cell = l2n->internal_layout ()->cell (circuit->cell_index ()); @@ -1025,8 +1025,8 @@ LayoutToNetlistStandardReader::read_abstract_terminal (db::LayoutToNetlist *l2n, if (l2n) { - db::connected_clusters &cc = l2n->net_clusters ().clusters_per_cell (dm->cell_index ()); - db::local_cluster &lc = *cc.insert (); + db::connected_clusters &cc = l2n->net_clusters ().clusters_per_cell (dm->cell_index ()); + db::local_cluster &lc = *cc.insert (); dm->set_cluster_id_for_terminal (tid, lc.id ()); db::Cell &cell = l2n->internal_layout ()->cell (dm->cell_index ()); diff --git a/src/db/db/dbLayoutToNetlistReader.h b/src/db/db/dbLayoutToNetlistReader.h index ebd3be9c5..860d7f714 100644 --- a/src/db/db/dbLayoutToNetlistReader.h +++ b/src/db/db/dbLayoutToNetlistReader.h @@ -143,7 +143,7 @@ protected: void read_property (db::NetlistObject *obj); db::Polygon read_polygon (); db::Box read_rect (); - void read_geometries (db::NetlistObject *obj, Brace &br, db::LayoutToNetlist *l2n, db::local_cluster &lc, db::Cell &cell); + void read_geometries (db::NetlistObject *obj, Brace &br, db::LayoutToNetlist *l2n, db::local_cluster &lc, db::Cell &cell); db::Point read_point (); private: diff --git a/src/db/db/dbLayoutToNetlistWriter.cc b/src/db/db/dbLayoutToNetlistWriter.cc index 6a211129b..ad1531e13 100644 --- a/src/db/db/dbLayoutToNetlistWriter.cc +++ b/src/db/db/dbLayoutToNetlistWriter.cc @@ -397,11 +397,16 @@ void std_writer_impl::reset_geometry_ref () } template -void std_writer_impl::write (const db::PolygonRef *s, const db::ICplxTrans &tr, const std::string &lname, bool relative) +void std_writer_impl::write (const db::NetShape *s, const db::ICplxTrans &tr, const std::string &lname, bool relative) { - db::ICplxTrans t = tr * db::ICplxTrans (s->trans ()); + if (s->type () != db::NetShape::Polygon) { + return; + } - const db::Polygon &poly = s->obj (); + db::PolygonRef pr = s->polygon_ref (); + db::ICplxTrans t = tr * db::ICplxTrans (pr.trans ()); + + const db::Polygon &poly = pr.obj (); if (poly.is_box ()) { db::Box box = t * poly.box (); @@ -435,7 +440,7 @@ bool std_writer_impl::new_cell (cell_index_type ci) const template void std_writer_impl::write (const db::Net &net, unsigned int id, const std::string &indent) { - const db::hier_clusters &clusters = mp_l2n->net_clusters (); + const db::hier_clusters &clusters = mp_l2n->net_clusters (); const db::Circuit *circuit = net.circuit (); const db::Connectivity &conn = mp_l2n->connectivity (); @@ -450,7 +455,7 @@ void std_writer_impl::write (const db::Net &net, unsigned int id, const st db::cell_index_type cci = circuit->cell_index (); db::cell_index_type prev_ci = cci; - for (db::recursive_cluster_shape_iterator si (clusters, *l, cci, net.cluster_id (), this); ! si.at_end (); ) { + for (db::recursive_cluster_shape_iterator si (clusters, *l, cci, net.cluster_id (), this); ! si.at_end (); ) { // NOTE: we don't recursive into circuits which will later be output. However, as circuits may // vanish in "purge" but the clusters will still be there we need to recursive into clusters from @@ -570,7 +575,7 @@ void std_writer_impl::write (const db::DeviceAbstract &device_abstract, co { const std::vector &td = device_abstract.device_class ()->terminal_definitions (); - const db::hier_clusters &clusters = mp_l2n->net_clusters (); + const db::hier_clusters &clusters = mp_l2n->net_clusters (); const db::Connectivity &conn = mp_l2n->connectivity (); for (std::vector::const_iterator t = td.begin (); t != td.end (); ++t) { @@ -587,8 +592,8 @@ void std_writer_impl::write (const db::DeviceAbstract &device_abstract, co continue; } - const db::local_cluster &lc = clusters.clusters_per_cell (device_abstract.cell_index ()).cluster_by_id (cid); - for (db::local_cluster::shape_iterator s = lc.begin (*l); ! s.at_end (); ++s) { + const db::local_cluster &lc = clusters.clusters_per_cell (device_abstract.cell_index ()).cluster_by_id (cid); + for (db::local_cluster::shape_iterator s = lc.begin (*l); ! s.at_end (); ++s) { *mp_stream << indent << indent2; write (s.operator-> (), db::ICplxTrans (), name_for_layer (mp_l2n, *l), true); diff --git a/src/db/db/dbLayoutToNetlistWriter.h b/src/db/db/dbLayoutToNetlistWriter.h index 08cc82196..5065c61a8 100644 --- a/src/db/db/dbLayoutToNetlistWriter.h +++ b/src/db/db/dbLayoutToNetlistWriter.h @@ -41,6 +41,7 @@ class DeviceAbstract; class Net; class Netlist; class LayoutToNetlist; +class NetShape; namespace l2n_std_format { @@ -75,7 +76,7 @@ private: void write (const db::SubCircuit &subcircuit, std::map &net2id, const std::string &indent); void write (const db::Device &device, std::map &net2id, const std::string &indent); void write (const db::DeviceAbstract &device_abstract, const std::string &indent); - void write (const db::PolygonRef *s, const db::ICplxTrans &tr, const std::string &lname, bool relative); + void write (const db::NetShape *s, const db::ICplxTrans &tr, const std::string &lname, bool relative); void write (const db::DCplxTrans &trans); void reset_geometry_ref (); diff --git a/src/db/db/dbNetShape.cc b/src/db/db/dbNetShape.cc new file mode 100644 index 000000000..ba3564754 --- /dev/null +++ b/src/db/db/dbNetShape.cc @@ -0,0 +1,218 @@ +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 "dbNetShape.h" +#include "dbShapes.h" +#include "dbPolygonTools.h" + +namespace db { + +NetShape::NetShape () + : m_ptr (0), m_dx (0), m_dy (0) +{ } + +NetShape::NetShape (const db::PolygonRef &pr) +{ + m_ptr = size_t (&pr.obj ()) + 1; + m_dx = pr.trans ().disp ().x (); + m_dy = pr.trans ().disp ().y (); +} + +NetShape::NetShape (const db::Polygon &poly, db::GenericRepository &repo) +{ + db::PolygonRef pr (poly, repo); + m_ptr = size_t (&pr.obj ()) + 1; + m_dx = pr.trans ().disp ().x (); + m_dy = pr.trans ().disp ().y (); +} + +NetShape::NetShape (const db::TextRef &tr) +{ + m_ptr = size_t (&tr.obj ()); + m_dx = tr.trans ().disp ().x (); + m_dy = tr.trans ().disp ().y (); +} + +NetShape::NetShape (const db::Text &text, db::GenericRepository &repo) +{ + db::TextRef tr (text, repo); + m_ptr = size_t (&tr.obj ()); + m_dx = tr.trans ().disp ().x (); + m_dy = tr.trans ().disp ().y (); +} + +NetShape::shape_type NetShape::type () const +{ + if (m_ptr == 0) { + return None; + } else if ((m_ptr & 1) != 0) { + return Polygon; + } else { + return Text; + } +} + +db::PolygonRef NetShape::polygon_ref () const +{ + if ((size_t (m_ptr) & 1) != 0) { + return db::PolygonRef (reinterpret_cast (m_ptr - 1), db::Disp (db::Vector (m_dx, m_dy))); + } + tl_assert (false); +} + +db::TextRef NetShape::text_ref () const +{ + if ((size_t (m_ptr) & 1) == 0) { + return db::TextRef (reinterpret_cast (m_ptr), db::Disp (db::Vector (m_dx, m_dy))); + } + tl_assert (false); +} + +void NetShape::transform (const db::Disp &tr) +{ + m_dx += tr.disp ().x (); + m_dy += tr.disp ().y (); +} + +NetShape::box_type NetShape::bbox () const +{ + if ((m_ptr & 1) != 0) { + return polygon_ref ().box (); + } else if (m_ptr != 0) { + return text_ref ().box (); + } else { + return box_type (); + } +} + +void NetShape::insert_into (db::Shapes &shapes) const +{ + if ((m_ptr & 1) != 0) { + shapes.insert (polygon_ref ()); + } else if (m_ptr != 0) { + shapes.insert (text_ref ()); + } +} + +void NetShape::insert_into (db::Shapes &shapes, db::properties_id_type pi) const +{ + if ((m_ptr & 1) != 0) { + shapes.insert (db::PolygonRefWithProperties (polygon_ref (), pi)); + } else if (m_ptr != 0) { + shapes.insert (db::TextRefWithProperties (text_ref (), pi)); + } +} + +bool NetShape::interacts_with (const db::NetShape &other) const +{ + if (m_ptr == 0 || other.m_ptr == 0 || ! bbox ().touches (other.bbox ())) { + return false; + } + + if ((m_ptr & 1) != 0) { + + if ((other.m_ptr & 1) != 0) { + + // Polygon vs. polygon + db::PolygonRef pr_other = other.polygon_ref (); + db::PolygonRef pr = polygon_ref (); + db::Polygon p = pr_other.obj ().transformed (pr.trans ().inverted () * pr_other.trans ()); + return db::interact_pp (pr.obj (), p); + + } else { + + // NOTE: we assume that the text ref's target is at 0,0 + db::PolygonRef pr = polygon_ref (); + db::Point pt = db::Point (other.m_dx, other.m_dy) - pr.trans ().disp (); + return db::inside_poly (pr.obj ().begin_edge (), pt) >= 0; + + } + + } else { + + if ((other.m_ptr & 1) == 0) { + + // Text vs. text + return m_dx == other.m_dx && m_dy == other.m_dy; + + } else { + + // NOTE: we assume that the text ref's target is at 0,0 + db::PolygonRef pr_other = other.polygon_ref (); + db::Point pt = db::Point (m_dx, m_dy) - pr_other.trans ().disp (); + return db::inside_poly (pr_other.obj ().begin_edge (), pt) >= 0; + + } + + } +} + +template +bool NetShape::interacts_with_transformed (const db::NetShape &other, const Tr &trans) const +{ + if (m_ptr == 0 || other.m_ptr == 0 || ! bbox ().touches (other.bbox ().transformed (trans))) { + return false; + } + + if ((m_ptr & 1) != 0) { + + if ((other.m_ptr & 1) != 0) { + + // Polygon vs. polygon + db::PolygonRef pr_other = other.polygon_ref (); + db::PolygonRef pr = polygon_ref (); + db::Polygon p = pr_other.obj ().transformed (Tr (pr.trans ().inverted ()) * trans * Tr (pr_other.trans ())); + return db::interact_pp (pr.obj (), p); + + } else { + + // NOTE: we assume that the text ref's target is at 0,0 + db::PolygonRef pr = polygon_ref (); + db::Point pt = trans * db::Point (other.m_dx, other.m_dy) - pr.trans ().disp (); + return db::inside_poly (pr.obj ().begin_edge (), pt) >= 0; + + } + + } else { + + if ((other.m_ptr & 1) == 0) { + + // Text vs. text + db::Point pt = trans * db::Point (other.m_dx, other.m_dy); + return db::Point (m_dx, m_dy) == pt; + + } else { + + // NOTE: we assume that the text ref's target is at 0,0 + db::PolygonRef pr_other = other.polygon_ref (); + db::Point pt = trans.inverted () * db::Point (m_dx, m_dy) - pr_other.trans ().disp (); + return db::inside_poly (pr_other.obj ().begin_edge (), pt) >= 0; + + } + + } +} + +// explicit instantiations +template bool NetShape::interacts_with_transformed (const db::NetShape &other, const db::ICplxTrans &trans) const; +template bool NetShape::interacts_with_transformed (const db::NetShape &other, const db::Trans &trans) const; + +} diff --git a/src/db/db/dbNetShape.h b/src/db/db/dbNetShape.h new file mode 100644 index 000000000..3ee5c2e4a --- /dev/null +++ b/src/db/db/dbNetShape.h @@ -0,0 +1,178 @@ +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 + +*/ + + +#ifndef HDR_dbNetShape +#define HDR_dbNetShape + +#include "dbPolygon.h" +#include "dbText.h" +#include "dbShapeRepository.h" +#include "dbBoxConvert.h" + +namespace db { + +class Shapes; + +/** + * @brief Provides a union of a PolygonRef and a TextRef + * + * This object is used in the netlist extractor and represents either a polygon or a text. + * The TextRef shall utilize a StringRef to represent the string. + */ +class DB_PUBLIC NetShape +{ +public: + enum shape_type { None, Text, Polygon }; + + typedef db::Point point_type; + typedef db::Box box_type; + typedef db::Coord coord_type; + typedef db::Disp trans_type; + + /** + * @brief Default constructor + */ + NetShape (); + + /** + * @brief A NetShape object representing a PolygonRef + */ + NetShape (const db::PolygonRef &pr); + + /** + * @brief A NetShape object representing a Polygon from the given shape repository + */ + NetShape (const db::Polygon &poly, db::GenericRepository &repo); + + /** + * @brief A NetShape object representing a TextRef + */ + NetShape (const db::TextRef &tr); + + /** + * @brief A NetShape object representing a Text from the given shape repository + */ + NetShape (const db::Text &text, db::GenericRepository &repo); + + /** + * @brief Gets a code indicating the type of object stored herein + */ + shape_type type () const; + + /** + * @brief Gets the PolygonRef object + * Asserts if the object stored is not a polygon. + */ + db::PolygonRef polygon_ref () const; + + /** + * @brief Gets the TextRef object + * Asserts if the object stored is not a text. + */ + db::TextRef text_ref () const; + + /** + * @brief In-place transformation + */ + void transform (const db::Disp &tr); + + /** + * @brief Equality + */ + bool operator== (const NetShape &net_shape) const + { + return m_ptr == net_shape.m_ptr && m_dx == net_shape.m_dx && m_dy == net_shape.m_dy; + } + + /** + * @brief Inequality + */ + bool operator!= (const NetShape &net_shape) const + { + return ! operator== (net_shape); + } + + /** + * @brief Less operator + */ + bool operator< (const NetShape &net_shape) const + { + if (m_ptr != net_shape.m_ptr) { + return m_ptr < net_shape.m_ptr; + } + if (m_dx != net_shape.m_dx) { + return m_dx < net_shape.m_dx; + } + return m_dy < net_shape.m_dy; + } + + /** + * @brief Gets the bounding box of the object + */ + box_type bbox () const; + + /** + * @brief Inserts the object into a Shapes collection + */ + void insert_into (db::Shapes &shapes) const; + + /** + * @brief Inserts the object into a Shapes collection with the given properties ID + */ + void insert_into (db::Shapes &shapes, db::properties_id_type pi) const; + + /** + * @brief Returns true if the object interacts with another NetShape object + */ + bool interacts_with (const db::NetShape &other) const; + + /** + * @brief Returns true if the object interacts with another NetShape object after transforming it + */ + template + bool interacts_with_transformed (const db::NetShape &other, const Tr &trans) const; + +public: + size_t m_ptr; + coord_type m_dx, m_dy; +}; + +/** + * @brief A box converter implementation for NetShape + */ +template <> +struct box_convert +{ + typedef db::NetShape::box_type box_type; + typedef db::NetShape::coord_type coord_type; + typedef db::complex_bbox_tag complexity; + + box_type operator() (const db::NetShape &net_shape) const + { + return net_shape.bbox (); + } +}; + +} + +#endif + diff --git a/src/db/db/dbNetlistDeviceExtractor.cc b/src/db/db/dbNetlistDeviceExtractor.cc index 0206b2725..b022e9f5e 100644 --- a/src/db/db/dbNetlistDeviceExtractor.cc +++ b/src/db/db/dbNetlistDeviceExtractor.cc @@ -119,9 +119,12 @@ void NetlistDeviceExtractor::initialize (db::Netlist *nl) setup (); } -static void insert_into_region (const db::PolygonRef &s, const db::ICplxTrans &tr, db::Region ®ion) +static void insert_into_region (const db::NetShape &s, const db::ICplxTrans &tr, db::Region ®ion) { - region.insert (s.obj ().transformed (tr * db::ICplxTrans (s.trans ()))); + if (s.type () == db::NetShape::Polygon) { + db::PolygonRef pr = s.polygon_ref (); + region.insert (pr.obj ().transformed (tr * db::ICplxTrans (pr.trans ()))); + } } void NetlistDeviceExtractor::extract (db::DeepShapeStore &dss, unsigned int layout_index, const NetlistDeviceExtractor::input_layers &layer_map, db::Netlist &nl, hier_clusters_type &clusters, double device_scaling) @@ -207,8 +210,7 @@ void NetlistDeviceExtractor::extract_without_initialize (db::Layout &layout, db: { tl_assert (layers.size () == m_layer_definitions.size ()); - typedef db::PolygonRef shape_type; - db::ShapeIterator::flags_type shape_iter_flags = db::ShapeIterator::Polygons; + typedef db::NetShape shape_type; mp_layout = &layout; m_layers = layers; @@ -247,7 +249,7 @@ void NetlistDeviceExtractor::extract_without_initialize (db::Layout &layout, db: db::Connectivity device_conn = get_connectivity (layout, layers); db::hier_clusters device_clusters; - device_clusters.build (layout, cell, shape_iter_flags, device_conn, 0, breakout_cells); + device_clusters.build (layout, cell, device_conn, 0, breakout_cells); tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Extracting devices"))); @@ -365,12 +367,12 @@ void NetlistDeviceExtractor::push_new_devices (const db::Vector &disp_cache) DeviceCellKey key; for (geometry_per_terminal_type::const_iterator t = d->second.second.begin (); t != d->second.second.end (); ++t) { - std::map > > = key.geometry [t->first]; + std::map > > = key.geometry [t->first]; for (geometry_per_layer_type::const_iterator l = t->second.begin (); l != t->second.end (); ++l) { - std::set &gl = gt [l->first]; - for (std::vector::const_iterator p = l->second.begin (); p != l->second.end (); ++p) { - db::PolygonRef pr = *p; - pr.transform (db::PolygonRef::trans_type (-disp)); + std::set &gl = gt [l->first]; + for (std::vector::const_iterator p = l->second.begin (); p != l->second.end (); ++p) { + db::NetShape pr = *p; + pr.transform (db::NetShape::trans_type (-disp)); gl.insert (pr); } } @@ -411,10 +413,10 @@ void NetlistDeviceExtractor::push_new_devices (const db::Vector &disp_cache) for (geometry_per_layer_type::const_iterator l = t->second.begin (); l != t->second.end (); ++l) { db::Shapes &shapes = device_cell.shapes (l->first); - for (std::vector::const_iterator s = l->second.begin (); s != l->second.end (); ++s) { - db::PolygonRef pr = *s; - pr.transform (db::PolygonRef::trans_type (-disp)); - shapes.insert (db::PolygonRefWithProperties (pr, pi)); + for (std::vector::const_iterator s = l->second.begin (); s != l->second.end (); ++s) { + db::NetShape pr = *s; + pr.transform (db::NetShape::trans_type (-disp)); + pr.insert_into (shapes, pi); } } @@ -542,10 +544,10 @@ void NetlistDeviceExtractor::define_terminal (Device *device, size_t terminal_id std::pair &dd = m_new_devices[device->id ()]; dd.first = device; - std::vector &geo = dd.second[terminal_id][layer_index]; + std::vector &geo = dd.second[terminal_id][layer_index]; for (db::Region::const_iterator p = region.begin_merged (); !p.at_end (); ++p) { - geo.push_back (db::PolygonRef (*p, mp_layout->shape_repository ())); + geo.push_back (db::NetShape (*p, mp_layout->shape_repository ())); } } @@ -555,7 +557,7 @@ void NetlistDeviceExtractor::define_terminal (Device *device, size_t terminal_id tl_assert (geometry_index < m_layers.size ()); unsigned int layer_index = m_layers [geometry_index]; - db::PolygonRef pr (polygon, mp_layout->shape_repository ()); + db::NetShape pr (polygon, mp_layout->shape_repository ()); std::pair &dd = m_new_devices[device->id ()]; dd.first = device; dd.second[terminal_id][layer_index].push_back (pr); diff --git a/src/db/db/dbNetlistDeviceExtractor.h b/src/db/db/dbNetlistDeviceExtractor.h index 8141093eb..2cfc3c40e 100644 --- a/src/db/db/dbNetlistDeviceExtractor.h +++ b/src/db/db/dbNetlistDeviceExtractor.h @@ -29,6 +29,7 @@ #include "dbHierNetworkProcessor.h" #include "dbDeepShapeStore.h" #include "dbRegion.h" +#include "dbNetShape.h" #include "gsiObject.h" @@ -205,7 +206,7 @@ public: typedef std::vector layer_definitions; typedef layer_definitions::const_iterator layer_definitions_iterator; typedef std::map input_layers; - typedef db::hier_clusters hier_clusters_type; + typedef db::hier_clusters hier_clusters_type; /** * @brief Constructor @@ -260,8 +261,6 @@ public: * the nets later to associate nets with device terminals. * * The definition of the input layers is device class specific. - * - * NOTE: The extractor expects "PolygonRef" type layers. */ void extract (Layout &layout, Cell &cell, const std::vector &layers, Netlist *netlist, hier_clusters_type &clusters, double device_scaling = 1.0, const std::set *breakout_cells = 0); @@ -521,11 +520,11 @@ private: return false; } - std::map > > geometry; + std::map > > geometry; std::map parameters; }; - typedef std::map > geometry_per_layer_type; + typedef std::map > geometry_per_layer_type; typedef std::map geometry_per_terminal_type; tl::weak_ptr m_netlist; diff --git a/src/db/db/dbNetlistExtractor.cc b/src/db/db/dbNetlistExtractor.cc index 539d7b7dd..bfe1fba9f 100644 --- a/src/db/db/dbNetlistExtractor.cc +++ b/src/db/db/dbNetlistExtractor.cc @@ -23,6 +23,7 @@ #include "dbNetlistExtractor.h" #include "dbDeepShapeStore.h" #include "dbNetlistDeviceExtractor.h" +#include "dbShapeRepository.h" #include "tlGlobPattern.h" namespace db @@ -50,9 +51,9 @@ void NetlistExtractor::set_include_floating_subcircuits (bool f) } static void -build_net_name_equivalence (const db::Layout *layout, db::property_names_id_type net_name_id, const std::string &joined_net_names, tl::equivalence_clusters &eq) +build_net_name_equivalence (const db::Layout *layout, db::property_names_id_type net_name_id, const std::string &joined_net_names, tl::equivalence_clusters &eq) { - std::map > prop_by_name; + std::map > prop_by_name; tl::GlobPattern jn_pattern (joined_net_names); for (db::PropertiesRepository::iterator i = layout->properties_repository ().begin (); i != layout->properties_repository ().end (); ++i) { @@ -60,15 +61,23 @@ build_net_name_equivalence (const db::Layout *layout, db::property_names_id_type if (p->first == net_name_id) { std::string nn = p->second.to_string (); if (jn_pattern.match (nn)) { - prop_by_name [nn].insert (i->first); + prop_by_name [nn].insert (db::prop_id_to_attr (i->first)); } } } } - for (std::map >::const_iterator pn = prop_by_name.begin (); pn != prop_by_name.end (); ++pn) { - std::set::const_iterator p = pn->second.begin (); - std::set::const_iterator p0 = p; + const db::repository &text_repository = layout->shape_repository ().repository (db::object_tag ()); + for (db::repository::iterator t = text_repository.begin (); t != text_repository.end (); ++t) { + std::string nn = t->string (); + if (jn_pattern.match (nn)) { + prop_by_name [nn].insert (db::text_ref_to_attr (t.operator-> ())); + } + } + + for (std::map >::const_iterator pn = prop_by_name.begin (); pn != prop_by_name.end (); ++pn) { + std::set::const_iterator p = pn->second.begin (); + std::set::const_iterator p0 = p; while (p != pn->second.end ()) { eq.same (*p0, *p); ++p; @@ -93,9 +102,9 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo m_terminal_annot_name_id = mp_layout->properties_repository ().get_id_of_name (db::NetlistDeviceExtractor::terminal_id_property_name ()); m_device_annot_name_id = mp_layout->properties_repository ().get_id_of_name (db::NetlistDeviceExtractor::device_id_property_name ()); - // the big part: actually extract the nets + // build an attribute equivalence map which lists the "attribute IDs" which are identical in terms of net names - std::map > net_name_equivalence; + std::map > net_name_equivalence; if (m_text_annot_name_id.first) { if (! m_joined_net_names.empty ()) { build_net_name_equivalence (mp_layout, m_text_annot_name_id.second, m_joined_net_names, net_name_equivalence [hier_clusters_type::top_cell_index]); @@ -107,7 +116,10 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo } } } - mp_clusters->build (*mp_layout, *mp_cell, db::ShapeIterator::Polygons, conn, &net_name_equivalence); + + // the big part: actually extract the nets + + mp_clusters->build (*mp_layout, *mp_cell, conn, &net_name_equivalence); // reverse lookup for Circuit vs. cell index std::map circuits; @@ -181,7 +193,7 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo for (connected_clusters_type::all_iterator c = clusters.begin_all (); ! c.at_end (); ++c) { - const db::local_cluster &lc = clusters.cluster_by_id (*c); + const db::local_cluster &lc = clusters.cluster_by_id (*c); if (clusters.connections_for_cluster (*c).empty () && lc.empty ()) { // this is an entirely empty cluster so we skip it. // Such clusters are left over when joining clusters. @@ -204,8 +216,8 @@ NetlistExtractor::extract_nets (const db::DeepShapeStore &dss, unsigned int layo // add the global names as second priority if (net_names.empty ()) { - const db::local_cluster::global_nets &gn = lc.get_global_nets (); - for (db::local_cluster::global_nets::const_iterator g = gn.begin (); g != gn.end (); ++g) { + const db::local_cluster::global_nets &gn = lc.get_global_nets (); + for (db::local_cluster::global_nets::const_iterator g = gn.begin (); g != gn.end (); ++g) { net_names.insert (conn.global_net_name (*g)); } } @@ -250,7 +262,13 @@ NetlistExtractor::make_device_abstract_connections (db::DeviceAbstract *dm, cons for (local_cluster_type::attr_iterator a = dc->begin_attr (); a != dc->end_attr (); ++a) { - const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (*a); + if (! db::is_prop_id_attr (*a)) { + continue; + } + + db::properties_id_type pi = db::prop_id_from_attr (*a); + + const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (pi); for (db::PropertiesRepository::properties_set::const_iterator j = ps.begin (); j != ps.end (); ++j) { if (j->first == m_terminal_annot_name_id.second) { dm->set_cluster_id_for_terminal (j->second.to (), dc->id ()); @@ -282,7 +300,13 @@ void NetlistExtractor::collect_labels (const connected_clusters_type &clusters, const local_cluster_type &lc = clusters.cluster_by_id (cid); for (local_cluster_type::attr_iterator a = lc.begin_attr (); a != lc.end_attr (); ++a) { - const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (*a); + if (! db::is_prop_id_attr (*a)) { + continue; + } + + db::properties_id_type pi = db::prop_id_from_attr (*a); + + const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (pi); for (db::PropertiesRepository::properties_set::const_iterator j = ps.begin (); j != ps.end (); ++j) { if (m_text_annot_name_id.first && j->first == m_text_annot_name_id.second) { @@ -343,13 +367,19 @@ void NetlistExtractor::connect_devices (db::Circuit *circuit, continue; } - const db::local_cluster &dc = mp_clusters->clusters_per_cell (inst_cell_index).cluster_by_id (i->id ()); + const db::local_cluster &dc = mp_clusters->clusters_per_cell (inst_cell_index).cluster_by_id (i->id ()); // connect the net to the terminal of the device: take the terminal ID from the properties on the // device cluster for (local_cluster_type::attr_iterator a = dc.begin_attr (); a != dc.end_attr (); ++a) { - const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (*a); + if (! db::is_prop_id_attr (*a)) { + continue; + } + + db::properties_id_type pi = db::prop_id_from_attr (*a); + + const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (pi); for (db::PropertiesRepository::properties_set::const_iterator j = ps.begin (); j != ps.end (); ++j) { if (m_terminal_annot_name_id.first && j->first == m_terminal_annot_name_id.second) { diff --git a/src/db/db/dbNetlistExtractor.h b/src/db/db/dbNetlistExtractor.h index f25490d93..072253dc8 100644 --- a/src/db/db/dbNetlistExtractor.h +++ b/src/db/db/dbNetlistExtractor.h @@ -25,6 +25,7 @@ #include "dbCommon.h" #include "dbHierNetworkProcessor.h" +#include "dbNetShape.h" #include #include @@ -71,9 +72,9 @@ class DeviceAbstract; class DB_PUBLIC NetlistExtractor { public: - typedef db::hier_clusters hier_clusters_type; - typedef db::connected_clusters connected_clusters_type; - typedef db::local_cluster local_cluster_type; + typedef db::hier_clusters hier_clusters_type; + typedef db::connected_clusters connected_clusters_type; + typedef db::local_cluster local_cluster_type; /** * @brief NetExtractor constructor diff --git a/src/db/db/dbRegionUtils.cc b/src/db/db/dbRegionUtils.cc index 6748fc954..f0ead2b95 100644 --- a/src/db/db/dbRegionUtils.cc +++ b/src/db/db/dbRegionUtils.cc @@ -353,23 +353,23 @@ template class region_to_edge_interaction_filter_base; // ------------------------------------------------------------------------------------- // RegionToTextInteractionFilterBase implementation -template -region_to_text_interaction_filter_base::region_to_text_interaction_filter_base (bool inverse) +template +region_to_text_interaction_filter_base::region_to_text_interaction_filter_base (bool inverse) : m_inverse (inverse) { // .. nothing yet .. } -template +template void -region_to_text_interaction_filter_base::preset (const OutputType *s) +region_to_text_interaction_filter_base::preset (const OutputType *s) { m_seen.insert (s); } -template +template void -region_to_text_interaction_filter_base::add (const db::Polygon *p, size_t, const db::Text *t, size_t) +region_to_text_interaction_filter_base::add (const db::Polygon *p, size_t, const TextType *t, size_t) { const OutputType *o = 0; tl::select (o, p, t); @@ -378,8 +378,7 @@ region_to_text_interaction_filter_base::add (const db::Polygon *p, s // A polygon and an text interact if the text is either inside completely // of at least one text of the polygon intersects with the text - db::Point pt; - pt += t->trans ().disp (); + db::Point pt = db::box_convert () (*t).p1 (); if (p->box ().contains (pt) && db::inside_poly (p->begin_edge (), pt) >= 0) { if (m_inverse) { m_seen.erase (o); @@ -392,9 +391,9 @@ region_to_text_interaction_filter_base::add (const db::Polygon *p, s } } -template +template void -region_to_text_interaction_filter_base::fill_output () +region_to_text_interaction_filter_base::fill_output () { for (typename std::set::const_iterator s = m_seen.begin (); s != m_seen.end (); ++s) { put (**s); @@ -402,8 +401,9 @@ region_to_text_interaction_filter_base::fill_output () } // explicit instantiations -template class region_to_text_interaction_filter_base; -template class region_to_text_interaction_filter_base; +template class region_to_text_interaction_filter_base; +template class region_to_text_interaction_filter_base; +template class region_to_text_interaction_filter_base; // ------------------------------------------------------------------------------------- // Polygon snapping diff --git a/src/db/db/dbRegionUtils.h b/src/db/db/dbRegionUtils.h index 4229e087b..6bddbb65e 100644 --- a/src/db/db/dbRegionUtils.h +++ b/src/db/db/dbRegionUtils.h @@ -527,15 +527,15 @@ private: /** * @brief A helper class for the region to text interaction functionality */ -template +template class DB_PUBLIC region_to_text_interaction_filter_base - : public db::box_scanner_receiver2 + : public db::box_scanner_receiver2 { public: region_to_text_interaction_filter_base (bool inverse); void preset (const OutputType *s); - void add (const db::Polygon *p, size_t, const db::Text *e, size_t); + void add (const db::Polygon *p, size_t, const TextType *e, size_t); void fill_output (); protected: @@ -549,13 +549,13 @@ private: /** * @brief A helper class for the region to text interaction functionality */ -template +template class DB_PUBLIC_TEMPLATE region_to_text_interaction_filter - : public region_to_text_interaction_filter_base + : public region_to_text_interaction_filter_base { public: region_to_text_interaction_filter (OutputContainer &output, bool inverse) - : region_to_text_interaction_filter_base (inverse), mp_output (&output) + : region_to_text_interaction_filter_base (inverse), mp_output (&output) { // .. nothing yet .. } diff --git a/src/db/db/dbShapeRepository.h b/src/db/db/dbShapeRepository.h index d95578df9..b6cd89660 100644 --- a/src/db/db/dbShapeRepository.h +++ b/src/db/db/dbShapeRepository.h @@ -176,6 +176,15 @@ public: return m_text_repository; } + /** + * @brief Return the repository by tag + */ + template + const db::repository &repository (db::object_tag tag) const + { + return const_cast *> (this)->repository (tag); + } + void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const { db::mem_stat (stat, purpose, cat, m_polygon_repository, no_self, parent); diff --git a/src/db/db/dbShapes.cc b/src/db/db/dbShapes.cc index 9f6799d08..aef79fa21 100644 --- a/src/db/db/dbShapes.cc +++ b/src/db/db/dbShapes.cc @@ -234,6 +234,20 @@ Shapes::swap (Shapes &d) m_layers.swap (d.m_layers); } +static +Shapes::shape_type safe_insert_text (Shapes &shapes, const Shapes::shape_type &shape, tl::func_delegate_base &pm) +{ + // for texts referring to a string repository we go the safe way and + // simply instantiate and re-insert the text: + Shapes::shape_type::text_type p; + shape.text (p); + if (! shape.has_prop_id ()) { + return shapes.insert (p); + } else { + return shapes.insert (db::object_with_properties (p, pm (shape.prop_id ()))); + } +} + Shapes::shape_type Shapes::do_insert (const Shapes::shape_type &shape, const Shapes::unit_trans_type & /*t*/, tl::func_delegate_base &pm) { @@ -352,19 +366,23 @@ Shapes::do_insert (const Shapes::shape_type &shape, const Shapes::unit_trans_typ case shape_type::ShortBoxArray: return (insert_by_tag (shape_type::short_box_array_type::tag (), shape, pm)); case shape_type::Text: - case shape_type::TextRef: - case shape_type::TextPtrArrayMember: { - // because texts can refer to a string repository we go the safe way and - // simply instantiate and re-insert the text: - shape_type::text_type p; - shape.text (p); - if (! shape.has_prop_id ()) { - return insert (p); + if (shape.text ().string_ref () != 0) { + return safe_insert_text (*this, shape, pm); } else { - return insert (db::object_with_properties (p, pm (shape.prop_id ()))); + return (insert_by_tag (shape_type::text_type::tag (), shape, pm)); } } + case shape_type::TextRef: + { + if (shape.text_ref ().obj ().string_ref () != 0) { + return safe_insert_text (*this, shape, pm); + } else { + return (insert_by_tag (shape_type::text_ref_type::tag (), shape, pm)); + } + } + case shape_type::TextPtrArrayMember: + return safe_insert_text (*this, shape, pm); case shape_type::TextPtrArray: tl_assert (layout () != 0); // cannot translate the array members return insert_array_by_tag (shape_type::text_ptr_array_type::tag (), shape, shape_repository (), pm); diff --git a/src/db/db/dbText.h b/src/db/db/dbText.h index cbf4b83db..828518356 100644 --- a/src/db/db/dbText.h +++ b/src/db/db/dbText.h @@ -159,6 +159,9 @@ inline void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int class DB_PUBLIC StringRepository { public: + typedef std::set string_refs_type; + typedef string_refs_type::const_iterator iterator; + /** * @brief Constructor */ @@ -216,6 +219,22 @@ public: return m_string_refs.size (); } + /** + * @brief Iterates over the string refs (begin) + */ + iterator begin () const + { + return m_string_refs.begin (); + } + + /** + * @brief Iterates over the string refs (end) + */ + iterator end () const + { + return m_string_refs.end (); + } + void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self = false, void *parent = 0) const { if (! no_self) { @@ -559,6 +578,21 @@ public: } } + /** + * @brief Gets the StringRef object is there is one + * + * If the string is a plain text kept internally, this method returns 0. + */ + const StringRef *string_ref () const + { + size_t p = (size_t) mp_ptr; + if (p & 1) { + return reinterpret_cast (p - 1); + } else { + return 0; + } + } + /** * @brief The transformation write accessor */ diff --git a/src/db/db/dbTextsUtils.h b/src/db/db/dbTextsUtils.h index 4f72c23c9..d1a5926f3 100644 --- a/src/db/db/dbTextsUtils.h +++ b/src/db/db/dbTextsUtils.h @@ -153,7 +153,7 @@ private: }; /** - * @brief A helper class for the text to region interaction functionality which acts as an text receiver + * @brief A helper class for the text ref to region interaction functionality which acts as an text receiver * * Note: This special scanner uses pointers to two different objects: texts and polygons. * It uses odd value pointers to indicate pointers to polygons and even value pointers to indicate @@ -161,9 +161,9 @@ private: * * There is a special box converter which is able to sort that out as well. */ -template +template class text_to_region_interaction_filter - : public db::box_scanner_receiver2 + : public db::box_scanner_receiver2 { public: text_to_region_interaction_filter (OutputContainer &output) @@ -172,6 +172,19 @@ public: // .. nothing yet .. } + void add (const db::TextRef *t, size_t, const db::Polygon *p, size_t) + { + const OutputType *tt = 0; + tl::select (tt, t, p); + + if (m_seen.find (tt) == m_seen.end ()) { + if (db::interact (*p, t->obj ().transformed (t->trans ()))) { + m_seen.insert (tt); + mp_output->insert (*tt); + } + } + } + void add (const db::Text *t, size_t, const db::Polygon *p, size_t) { const OutputType *tt = 0; diff --git a/src/db/unit_tests/dbHierNetworkProcessorTests.cc b/src/db/unit_tests/dbHierNetworkProcessorTests.cc index 7096e93e7..344101665 100644 --- a/src/db/unit_tests/dbHierNetworkProcessorTests.cc +++ b/src/db/unit_tests/dbHierNetworkProcessorTests.cc @@ -369,21 +369,21 @@ TEST(20_LocalClustersBasic) db::local_clusters clusters; EXPECT_EQ (local_clusters_to_string (clusters, conn), ""); - clusters.build_clusters (cell, db::ShapeIterator::Polygons, conn); + clusters.build_clusters (cell, conn); EXPECT_EQ (local_clusters_to_string (clusters, conn), "#1:[0](0,0;0,1000;1000,1000;1000,0)"); // one more shape cell.shapes (0).insert (db::PolygonRef (poly.transformed (db::Trans (db::Vector (10, 20))), repo)); clusters.clear (); - clusters.build_clusters (cell, db::ShapeIterator::Polygons, conn); + clusters.build_clusters (cell, conn); EXPECT_EQ (local_clusters_to_string (clusters, conn), "#1:[0](0,0;0,1000;1000,1000;1000,0);[0](10,20;10,1020;1010,1020;1010,20)"); // one more shape creating a new cluster cell.shapes (2).insert (db::PolygonRef (poly.transformed (db::Trans (db::Vector (0, 1100))), repo)); clusters.clear (); - clusters.build_clusters (cell, db::ShapeIterator::Polygons, conn); + clusters.build_clusters (cell, conn); EXPECT_EQ (local_clusters_to_string (clusters, conn), "#1:[0](0,0;0,1000;1000,1000;1000,0);[0](10,20;10,1020;1010,1020;1010,20)\n" "#2:[2](0,1100;0,2100;1000,2100;1000,1100)" @@ -393,7 +393,7 @@ TEST(20_LocalClustersBasic) cell.shapes (2).insert (db::PolygonRef (poly.transformed (db::Trans (db::Vector (0, 1000))), repo)); clusters.clear (); - clusters.build_clusters (cell, db::ShapeIterator::Polygons, conn); + clusters.build_clusters (cell, conn); EXPECT_EQ (local_clusters_to_string (clusters, conn), "#1:[0](0,0;0,1000;1000,1000;1000,0);[0](10,20;10,1020;1010,1020;1010,20);[2](0,1000;0,2000;1000,2000;1000,1000);[2](0,1100;0,2100;1000,2100;1000,1100)" ); @@ -402,7 +402,7 @@ TEST(20_LocalClustersBasic) cell.shapes (1).insert (db::PolygonRef (poly.transformed (db::Trans (db::Vector (0, 1100))), repo)); clusters.clear (); - clusters.build_clusters (cell, db::ShapeIterator::Polygons, conn); + clusters.build_clusters (cell, conn); EXPECT_EQ (local_clusters_to_string (clusters, conn), "#1:[0](0,0;0,1000;1000,1000;1000,0);[0](10,20;10,1020;1010,1020;1010,20);[2](0,1000;0,2000;1000,2000;1000,1000);[2](0,1100;0,2100;1000,2100;1000,1100)\n" "#2:[1](0,1100;0,2100;1000,2100;1000,1100)" @@ -430,21 +430,21 @@ TEST(21_LocalClustersBasicWithAttributes) db::local_clusters clusters; EXPECT_EQ (local_clusters_to_string (clusters, conn), ""); - clusters.build_clusters (cell, db::ShapeIterator::Polygons, conn); + clusters.build_clusters (cell, conn); EXPECT_EQ (local_clusters_to_string (clusters, conn), "#1:[0](0,0;0,1000;1000,1000;1000,0)"); // one more shape cell.shapes (0).insert (db::PolygonRefWithProperties (db::PolygonRef (poly.transformed (db::Trans (db::Vector (10, 20))), repo), 1)); clusters.clear (); - clusters.build_clusters (cell, db::ShapeIterator::Polygons, conn); + clusters.build_clusters (cell, conn); EXPECT_EQ (local_clusters_to_string (clusters, conn), "#1:[0](0,0;0,1000;1000,1000;1000,0);[0](10,20;10,1020;1010,1020;1010,20)%1"); // one more shape creating a new cluster cell.shapes (2).insert (db::PolygonRefWithProperties (db::PolygonRef (poly.transformed (db::Trans (db::Vector (0, 1100))), repo), 2)); clusters.clear (); - clusters.build_clusters (cell, db::ShapeIterator::Polygons, conn); + clusters.build_clusters (cell, conn); EXPECT_EQ (local_clusters_to_string (clusters, conn), "#1:[0](0,0;0,1000;1000,1000;1000,0);[0](10,20;10,1020;1010,1020;1010,20)%1\n" "#2:[2](0,1100;0,2100;1000,2100;1000,1100)%2" @@ -454,7 +454,7 @@ TEST(21_LocalClustersBasicWithAttributes) cell.shapes (2).insert (db::PolygonRefWithProperties (db::PolygonRef (poly.transformed (db::Trans (db::Vector (0, 1000))), repo), 3)); clusters.clear (); - clusters.build_clusters (cell, db::ShapeIterator::Polygons, conn); + clusters.build_clusters (cell, conn); EXPECT_EQ (local_clusters_to_string (clusters, conn), "#1:[0](0,0;0,1000;1000,1000;1000,0);[0](10,20;10,1020;1010,1020;1010,20);[2](0,1000;0,2000;1000,2000;1000,1000);[2](0,1100;0,2100;1000,2100;1000,1100)%1%2%3" ); @@ -463,7 +463,7 @@ TEST(21_LocalClustersBasicWithAttributes) cell.shapes (1).insert (db::PolygonRefWithProperties (db::PolygonRef (poly.transformed (db::Trans (db::Vector (0, 1100))), repo), 4)); clusters.clear (); - clusters.build_clusters (cell, db::ShapeIterator::Polygons, conn); + clusters.build_clusters (cell, conn); EXPECT_EQ (local_clusters_to_string (clusters, conn), "#1:[0](0,0;0,1000;1000,1000;1000,0);[0](10,20;10,1020;1010,1020;1010,20);[2](0,1000;0,2000;1000,2000;1000,1000);[2](0,1100;0,2100;1000,2100;1000,1100)%1%2%3\n" "#2:[1](0,1100;0,2100;1000,2100;1000,1100)%4" @@ -491,21 +491,21 @@ TEST(22_LocalClustersWithGlobal) db::local_clusters clusters; EXPECT_EQ (local_clusters_to_string (clusters, conn), ""); - clusters.build_clusters (cell, db::ShapeIterator::Polygons, conn); + clusters.build_clusters (cell, conn); EXPECT_EQ (local_clusters_to_string (clusters, conn), "#1:[0](0,0;0,1000;1000,1000;1000,0)"); // one more shape cell.shapes (0).insert (db::PolygonRefWithProperties (db::PolygonRef (poly.transformed (db::Trans (db::Vector (10, 20))), repo), 1)); clusters.clear (); - clusters.build_clusters (cell, db::ShapeIterator::Polygons, conn); + clusters.build_clusters (cell, conn); EXPECT_EQ (local_clusters_to_string (clusters, conn), "#1:[0](0,0;0,1000;1000,1000;1000,0);[0](10,20;10,1020;1010,1020;1010,20)%1"); // one more shape creating a new cluster cell.shapes (2).insert (db::PolygonRefWithProperties (db::PolygonRef (poly.transformed (db::Trans (db::Vector (0, 1100))), repo), 2)); clusters.clear (); - clusters.build_clusters (cell, db::ShapeIterator::Polygons, conn); + clusters.build_clusters (cell, conn); EXPECT_EQ (local_clusters_to_string (clusters, conn), "#1:[0](0,0;0,1000;1000,1000;1000,0);[0](10,20;10,1020;1010,1020;1010,20)%1\n" "#2:[2](0,1100;0,2100;1000,2100;1000,1100)%2" @@ -514,7 +514,7 @@ TEST(22_LocalClustersWithGlobal) conn.connect_global (0, "GLOBAL"); clusters.clear (); - clusters.build_clusters (cell, db::ShapeIterator::Polygons, conn); + clusters.build_clusters (cell, conn); EXPECT_EQ (local_clusters_to_string (clusters, conn), "#1:[0](0,0;0,1000;1000,1000;1000,0);[0](10,20;10,1020;1010,1020;1010,20)%1+GLOBAL\n" "#2:[2](0,1100;0,2100;1000,2100;1000,1100)%2" @@ -523,7 +523,7 @@ TEST(22_LocalClustersWithGlobal) conn.connect_global (2, "GLOBAL2"); clusters.clear (); - clusters.build_clusters (cell, db::ShapeIterator::Polygons, conn); + clusters.build_clusters (cell, conn); EXPECT_EQ (local_clusters_to_string (clusters, conn), "#1:[0](0,0;0,1000;1000,1000;1000,0);[0](10,20;10,1020;1010,1020;1010,20)%1+GLOBAL\n" "#2:[2](0,1100;0,2100;1000,2100;1000,1100)%2+GLOBAL2" @@ -533,7 +533,7 @@ TEST(22_LocalClustersWithGlobal) // now, GLOBAL2 will connect these clusters clusters.clear (); - clusters.build_clusters (cell, db::ShapeIterator::Polygons, conn); + clusters.build_clusters (cell, conn); EXPECT_EQ (local_clusters_to_string (clusters, conn), "#1:[0](0,0;0,1000;1000,1000;1000,0);[0](10,20;10,1020;1010,1020;1010,20);[2](0,1100;0,2100;1000,2100;1000,1100)%1%2+GLOBAL+GLOBAL2" ); @@ -570,7 +570,7 @@ TEST(23_LocalClustersWithEdges) conn.connect (0); db::local_clusters clusters; - clusters.build_clusters (cell, db::ShapeIterator::Edges, conn); + clusters.build_clusters (cell, conn); EXPECT_EQ (local_clusters_to_string (clusters, conn), "#1:[0](0,0;0,500);[0](0,500;0,1000)\n" "#2:[0](2000,500;1000,250);[0](1500,375;0,0)\n" @@ -585,7 +585,7 @@ TEST(23_LocalClustersWithEdges) conn.connect (0); db::local_clusters clusters; - clusters.build_clusters (cell, db::ShapeIterator::Edges, conn); + clusters.build_clusters (cell, conn); EXPECT_EQ (local_clusters_to_string (clusters, conn), "#1:[0](0,0;0,500);[0](0,500;0,1000);[0](1500,375;0,0);[0](0,1000;2000,1000);[0](2000,1000;2000,500);[0](2000,500;1000,250)"); } } @@ -700,7 +700,7 @@ TEST(40_HierClustersBasic) db::Connectivity conn; conn.connect (l1, l1); - hc.build (ly, top, db::ShapeIterator::Polygons, conn); + hc.build (ly, top, conn); int n, nc; const db::connected_clusters *cluster; @@ -815,7 +815,7 @@ TEST(41_HierClustersRecursiveClusterShapeIterator) db::Connectivity conn; conn.connect (l1, l1); - hc.build (ly, top, db::ShapeIterator::Polygons, conn); + hc.build (ly, top, conn); std::string res; int n = 0; @@ -860,7 +860,7 @@ TEST(41_HierClustersRecursiveClusterIterator) db::Connectivity conn; conn.connect (l1, l1); - hc.build (ly, top, db::ShapeIterator::Polygons, conn); + hc.build (ly, top, conn); std::string res; int n = 0; @@ -1020,7 +1020,7 @@ static void run_hc_test (tl::TestBase *_this, const std::string &file, const std conn.connect_global (l6, "BULK2"); db::hier_clusters hc; - hc.build (ly, ly.cell (*ly.begin_top_down ()), db::ShapeIterator::Polygons, conn); + hc.build (ly, ly.cell (*ly.begin_top_down ()), conn); std::vector > net_layers; @@ -1153,7 +1153,7 @@ static void run_hc_test_with_backannotation (tl::TestBase *_this, const std::str conn.connect_global (l6, "BULK2"); db::hier_clusters hc; - hc.build (ly, ly.cell (*ly.begin_top_down ()), db::ShapeIterator::Polygons, conn); + hc.build (ly, ly.cell (*ly.begin_top_down ()), conn); std::map lm; lm[l1] = ly.insert_layer (db::LayerProperties (101, 0)); diff --git a/src/db/unit_tests/dbLayoutToNetlistTests.cc b/src/db/unit_tests/dbLayoutToNetlistTests.cc index f352bdb0c..060904eef 100644 --- a/src/db/unit_tests/dbLayoutToNetlistTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistTests.cc @@ -91,7 +91,7 @@ static void dump_recursive_nets_to_layout (const db::LayoutToNetlist &l2n, db::L bool any = false; for (std::map::const_iterator m = lmap.begin (); m != lmap.end () && !any; ++m) { - any = !db::recursive_cluster_shape_iterator (l2n.net_clusters (), l2n.layer_of (*m->first), c->cell_index (), n->cluster_id ()).at_end (); + any = !db::recursive_cluster_shape_iterator (l2n.net_clusters (), l2n.layer_of (*m->first), c->cell_index (), n->cluster_id ()).at_end (); } if (!any) { diff --git a/src/db/unit_tests/dbNetShapeTests.cc b/src/db/unit_tests/dbNetShapeTests.cc new file mode 100644 index 000000000..06e3a5432 --- /dev/null +++ b/src/db/unit_tests/dbNetShapeTests.cc @@ -0,0 +1,187 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 "dbNetShape.h" +#include "dbShapes.h" +#include "tlUnitTest.h" + + +TEST(1) +{ + db::GenericRepository repo; + + db::NetShape s; + EXPECT_EQ (s.type () == db::NetShape::None, true); + EXPECT_EQ (s.bbox ().to_string (), "()"); + + db::Polygon p (db::Box (0, 0, 100, 200)); + s = db::NetShape (p, repo); + EXPECT_EQ (s.type () == db::NetShape::Polygon, true); + EXPECT_EQ (s.bbox ().to_string (), "(0,0;100,200)"); + EXPECT_EQ (s.polygon_ref ().obj ().to_string (), "(0,0;0,200;100,200;100,0)"); + EXPECT_EQ (db::NetShape (s.polygon_ref ()).type () == db::NetShape::Polygon, true); + EXPECT_EQ (db::NetShape (s.polygon_ref ()).polygon_ref ().obj ().to_string (), "(0,0;0,200;100,200;100,0)"); + + db::Text t ("abc", db::Trans (db::Vector (100, 200))); + s = db::NetShape (t, repo); + EXPECT_EQ (s.type () == db::NetShape::Text, true); + EXPECT_EQ (s.bbox ().to_string (), "(100,200;100,200)"); + EXPECT_EQ (s.text_ref ().obj ().to_string (), "('abc',r0 0,0)"); + EXPECT_EQ (db::NetShape (s.text_ref ()).type () == db::NetShape::Text, true); + EXPECT_EQ (db::NetShape (s.text_ref ()).text_ref ().obj ().to_string (), "('abc',r0 0,0)"); +} + +TEST(2) +{ + db::GenericRepository repo; + + db::NetShape s; + EXPECT_EQ (s.type () == db::NetShape::None, true); + EXPECT_EQ (s.bbox ().to_string (), "()"); + + db::Polygon p (db::Box (0, 0, 100, 200)); + s = db::NetShape (p, repo); + EXPECT_EQ (s.polygon_ref ().obj ().to_string (), "(0,0;0,200;100,200;100,0)"); + + s.transform (db::Disp (db::Vector (10, 20))); + EXPECT_EQ (s.bbox ().to_string (), "(10,20;110,220)"); + + db::Text t ("abc", db::Trans (db::Vector (100, 200))); + s = db::NetShape (t, repo); + EXPECT_EQ (s.text_ref ().obj ().to_string (), "('abc',r0 0,0)"); + + s.transform (db::Disp (db::Vector (10, 20))); + EXPECT_EQ (s.text_ref ().obj ().transformed (s.text_ref ().trans ()).to_string (), "('abc',r0 110,220)"); +} + +TEST(3) +{ + db::GenericRepository repo; + + db::NetShape s, s2; + EXPECT_EQ (s == db::NetShape (), true); + EXPECT_EQ (s != db::NetShape (), false); + EXPECT_EQ (s < db::NetShape (), false); + + db::Polygon p (db::Box (0, 0, 100, 200)); + s = db::NetShape (p, repo); + s2 = s; + EXPECT_EQ (s == db::NetShape (), false); + EXPECT_EQ (s != db::NetShape (), true); + EXPECT_EQ (s < db::NetShape (), false); + EXPECT_EQ (s == s2, true); + EXPECT_EQ (s != s2, false); + EXPECT_EQ (s < s2, false); + EXPECT_EQ (s2 < s, false); + s.transform (db::Disp (db::Vector (10, 20))); + EXPECT_EQ (s == s2, false); + EXPECT_EQ (s != s2, true); + EXPECT_EQ (s < s2, false); + EXPECT_EQ (s2 < s, true); + + db::Text t ("abc", db::Trans (db::Vector (100, 200))); + s = db::NetShape (t, repo); + EXPECT_EQ (s == s2, false); + EXPECT_EQ (s != s2, true); + EXPECT_EQ (s < s2, true); + EXPECT_EQ (s2 < s, false); + + s2 = s; + EXPECT_EQ (s == db::NetShape (), false); + EXPECT_EQ (s != db::NetShape (), true); + EXPECT_EQ (s < db::NetShape (), false); + EXPECT_EQ (s == s2, true); + EXPECT_EQ (s != s2, false); + EXPECT_EQ (s < s2, false); + EXPECT_EQ (s2 < s, false); + s.transform (db::Disp (db::Vector (10, 20))); + EXPECT_EQ (s == s2, false); + EXPECT_EQ (s != s2, true); + EXPECT_EQ (s < s2, false); + EXPECT_EQ (s2 < s, true); +} + +TEST(4) +{ + db::GenericRepository repo; + + db::NetShape s; + EXPECT_EQ (s.type () == db::NetShape::None, true); + EXPECT_EQ (s.bbox ().to_string (), "()"); + + db::Polygon p (db::Box (0, 0, 100, 200)); + s = db::NetShape (p, repo); + + db::Shapes shapes; + s.insert_into (shapes); + + db::Text t ("abc", db::Trans (db::Vector (100, 200))); + s = db::NetShape (t, repo); + s.insert_into (shapes); + + db::ShapeIterator si = shapes.begin (db::ShapeIterator::All); + EXPECT_EQ (si->to_string (), "polygon (0,0;0,200;100,200;100,0)"); + ++si; + EXPECT_NE (si.at_end (), true); + EXPECT_EQ (si->to_string (), "text ('abc',r0 100,200)"); + ++si; + EXPECT_EQ (si.at_end (), true); +} + +TEST(5) +{ + db::GenericRepository repo; + + db::NetShape sp1 (db::Polygon (db::Box (10, 20, 100, 200)), repo); + db::NetShape sp2 (db::Polygon (db::Box (80, 20, 180, 200)), repo); + db::NetShape sp3 (db::Polygon (db::Box (10, 320, 100, 500)), repo); + + db::NetShape st1 (db::Text ("abc", db::Trans (db::Vector (0, 0))), repo); + db::NetShape st2 (db::Text ("xyz", db::Trans (db::Vector (50, 60))), repo); + + EXPECT_EQ (sp1.interacts_with (db::NetShape ()), false); + EXPECT_EQ (sp1.interacts_with_transformed (db::NetShape (), db::Trans (db::Vector (1000, 0))), false); + EXPECT_EQ (sp1.interacts_with (sp1), true); + EXPECT_EQ (sp1.interacts_with_transformed (sp1, db::Trans (db::Vector (1000, 0))), false); + EXPECT_EQ (sp1.interacts_with (sp2), true); + EXPECT_EQ (sp2.interacts_with (sp1), true); + EXPECT_EQ (sp1.interacts_with (sp3), false); + EXPECT_EQ (sp1.interacts_with_transformed (sp3, db::Trans (db::Vector (50, -200))), true); + EXPECT_EQ (sp3.interacts_with (sp1), false); + EXPECT_EQ (sp3.interacts_with_transformed (sp1, db::Trans (db::Vector (50, 200))), true); + + EXPECT_EQ (sp1.interacts_with (st1), false); + EXPECT_EQ (sp1.interacts_with_transformed (st1, db::Trans (db::Vector (10, 20))), true); + EXPECT_EQ (sp1.interacts_with_transformed (st1, db::Trans (db::Vector (5, 20))), false); + EXPECT_EQ (sp1.interacts_with (st2), true); + + EXPECT_EQ (st1.interacts_with (sp1), false); + EXPECT_EQ (st1.interacts_with_transformed (sp1, db::Trans (db::Vector (-10, -20))), true); + EXPECT_EQ (st1.interacts_with_transformed (sp1, db::Trans (db::Vector (-5, -20))), false); + EXPECT_EQ (st2.interacts_with (sp1), true); + + EXPECT_EQ (st1.interacts_with (st1), true); + EXPECT_EQ (st1.interacts_with_transformed (st1, db::Trans (db::Vector (-5, -20))), false); + EXPECT_EQ (st2.interacts_with (st1), false); + EXPECT_EQ (st2.interacts_with_transformed (st1, db::Trans (db::Vector (50, 60))), true); +} diff --git a/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc b/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc index cf0c13caa..e26e5881d 100644 --- a/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc +++ b/src/db/unit_tests/dbNetlistDeviceExtractorTests.cc @@ -123,7 +123,7 @@ TEST(10_MOS3DeviceExtractorTest) // perform the extraction db::Netlist nl; - db::hier_clusters cl; + db::hier_clusters cl; db::NetlistDeviceExtractorMOS3Transistor ex ("MOS3"); @@ -179,7 +179,7 @@ TEST(11_MOS3DeviceExtractorTestNotRectangularGate) // perform the extraction db::Netlist nl; - db::hier_clusters cl; + db::hier_clusters cl; db::NetlistDeviceExtractorMOS3Transistor ex ("MOS3"); @@ -235,7 +235,7 @@ TEST(12_MOS3DeviceExtractorTestCircular) // perform the extraction db::Netlist nl; - db::hier_clusters cl; + db::hier_clusters cl; db::NetlistDeviceExtractorMOS3Transistor ex ("MOS3"); @@ -293,7 +293,7 @@ TEST(20_MOS4DeviceExtractorTest) // perform the extraction db::Netlist nl; - db::hier_clusters cl; + db::hier_clusters cl; db::NetlistDeviceExtractorMOS4Transistor ex ("MOS4"); @@ -354,7 +354,7 @@ TEST(21_MOS4DeviceExtractorTestNotRectangularGate) // perform the extraction db::Netlist nl; - db::hier_clusters cl; + db::hier_clusters cl; db::NetlistDeviceExtractorMOS4Transistor ex ("MOS4"); @@ -415,7 +415,7 @@ TEST(22_MOS4DeviceExtractorTestCircular) // perform the extraction db::Netlist nl; - db::hier_clusters cl; + db::hier_clusters cl; db::NetlistDeviceExtractorMOS4Transistor ex ("MOS4"); @@ -475,7 +475,7 @@ TEST(30_DMOS3DeviceExtractorTest) // perform the extraction db::Netlist nl; - db::hier_clusters cl; + db::hier_clusters cl; db::NetlistDeviceExtractorMOS3Transistor ex ("DMOS3", true); @@ -533,7 +533,7 @@ TEST(31_DMOS3DeviceExtractorTestNotRectangularGate) // perform the extraction db::Netlist nl; - db::hier_clusters cl; + db::hier_clusters cl; db::NetlistDeviceExtractorMOS3Transistor ex ("DMOS3", true); @@ -591,7 +591,7 @@ TEST(32_DMOS3DeviceExtractorTestCircular) // perform the extraction db::Netlist nl; - db::hier_clusters cl; + db::hier_clusters cl; db::NetlistDeviceExtractorMOS3Transistor ex ("DMOS3", true); @@ -651,7 +651,7 @@ TEST(40_DMOS4DeviceExtractorTest) // perform the extraction db::Netlist nl; - db::hier_clusters cl; + db::hier_clusters cl; db::NetlistDeviceExtractorMOS4Transistor ex ("DMOS4", true); @@ -714,7 +714,7 @@ TEST(41_DMOS4DeviceExtractorTestNotRectangularGate) // perform the extraction db::Netlist nl; - db::hier_clusters cl; + db::hier_clusters cl; db::NetlistDeviceExtractorMOS4Transistor ex ("DMOS4", true); @@ -777,7 +777,7 @@ TEST(42_DMOS4DeviceExtractorTestCircular) // perform the extraction db::Netlist nl; - db::hier_clusters cl; + db::hier_clusters cl; db::NetlistDeviceExtractorMOS4Transistor ex ("DMOS4", true); diff --git a/src/db/unit_tests/dbNetlistExtractorTests.cc b/src/db/unit_tests/dbNetlistExtractorTests.cc index 8cff11d1e..fecf213be 100644 --- a/src/db/unit_tests/dbNetlistExtractorTests.cc +++ b/src/db/unit_tests/dbNetlistExtractorTests.cc @@ -59,7 +59,7 @@ static unsigned int define_layer (db::Layout &ly, db::LayerMap &lmap, int gds_la return lid; } -static void dump_nets_to_layout (const db::Netlist &nl, const db::hier_clusters &clusters, db::Layout &ly, const std::map &lmap, const db::CellMapping &cmap, bool with_device_cells = false) +static void dump_nets_to_layout (const db::Netlist &nl, const db::hier_clusters &clusters, db::Layout &ly, const std::map &lmap, const db::CellMapping &cmap, bool with_device_cells = false) { std::set device_cells_seen; @@ -69,7 +69,7 @@ static void dump_nets_to_layout (const db::Netlist &nl, const db::hier_clusters< for (db::Circuit::const_net_iterator n = c->begin_nets (); n != c->end_nets (); ++n) { - const db::local_cluster &lc = clusters.clusters_per_cell (c->cell_index ()).cluster_by_id (n->cluster_id ()); + const db::local_cluster &lc = clusters.clusters_per_cell (c->cell_index ()).cluster_by_id (n->cluster_id ()); bool any_shapes = false; for (std::map::const_iterator m = lmap.begin (); m != lmap.end () && !any_shapes; ++m) { @@ -84,8 +84,8 @@ static void dump_nets_to_layout (const db::Netlist &nl, const db::hier_clusters< for (std::map::const_iterator m = lmap.begin (); m != lmap.end (); ++m) { db::Shapes &target = net_cell.shapes (m->second); - for (db::local_cluster::shape_iterator s = lc.begin (m->first); !s.at_end (); ++s) { - target.insert (*s); + for (db::local_cluster::shape_iterator s = lc.begin (m->first); !s.at_end (); ++s) { + s->insert_into (target); } } @@ -137,12 +137,12 @@ static void dump_nets_to_layout (const db::Netlist &nl, const db::hier_clusters< const std::vector &td = d->device_class ()->terminal_definitions (); for (std::vector::const_iterator t = td.begin (); t != td.end (); ++t) { - const db::local_cluster &dc = clusters.clusters_per_cell (dci).cluster_by_id (d->device_abstract ()->cluster_id_for_terminal (t->id ())); + const db::local_cluster &dc = clusters.clusters_per_cell (dci).cluster_by_id (d->device_abstract ()->cluster_id_for_terminal (t->id ())); for (std::map::const_iterator m = lmap.begin (); m != lmap.end (); ++m) { db::Shapes &target = device_cell.shapes (m->second); - for (db::local_cluster::shape_iterator s = dc.begin (m->first); !s.at_end (); ++s) { - target.insert (*s); + for (db::local_cluster::shape_iterator s = dc.begin (m->first); !s.at_end (); ++s) { + s->insert_into (target); } } @@ -233,7 +233,7 @@ TEST(1_DeviceAndNetExtraction) // perform the extraction db::Netlist nl; - db::hier_clusters cl; + db::hier_clusters cl; db::NetlistDeviceExtractorMOS3Transistor pmos_ex ("PMOS"); db::NetlistDeviceExtractorMOS3Transistor nmos_ex ("NMOS"); @@ -452,7 +452,7 @@ TEST(2_DeviceAndNetExtractionFlat) // perform the extraction db::Netlist nl; - db::hier_clusters cl; + db::hier_clusters cl; db::NetlistDeviceExtractorMOS3Transistor pmos_ex ("PMOS"); db::NetlistDeviceExtractorMOS3Transistor nmos_ex ("NMOS"); @@ -686,7 +686,7 @@ TEST(3_DeviceAndNetExtractionWithImplicitConnections) // perform the extraction db::Netlist nl; - db::hier_clusters cl; + db::hier_clusters cl; db::NetlistDeviceExtractorMOS3Transistor pmos_ex ("PMOS"); db::NetlistDeviceExtractorMOS3Transistor nmos_ex ("NMOS"); @@ -935,7 +935,7 @@ TEST(4_ResAndCapExtraction) // perform the extraction db::Netlist nl; - db::hier_clusters cl; + db::hier_clusters cl; db::NetlistDeviceExtractorMOS3Transistor pmos_ex ("PMOS"); db::NetlistDeviceExtractorMOS3Transistor nmos_ex ("NMOS"); @@ -1182,7 +1182,7 @@ TEST(5_ResAndCapWithBulkExtraction) // perform the extraction db::Netlist nl; - db::hier_clusters cl; + db::hier_clusters cl; db::NetlistDeviceExtractorMOS4Transistor pmos_ex ("PMOS"); db::NetlistDeviceExtractorMOS4Transistor nmos_ex ("NMOS"); @@ -1449,7 +1449,7 @@ TEST(6_BJT3TransistorExtraction) // perform the extraction db::Netlist nl; - db::hier_clusters cl; + db::hier_clusters cl; db::NetlistDeviceExtractorMOS4Transistor pmos_ex ("PMOS"); db::NetlistDeviceExtractorMOS4Transistor nmos_ex ("NMOS"); @@ -1656,7 +1656,7 @@ TEST(7_DiodeExtraction) // perform the extraction db::Netlist nl; - db::hier_clusters cl; + db::hier_clusters cl; db::NetlistDeviceExtractorDiode diode_ex ("DIODE"); @@ -1790,7 +1790,7 @@ TEST(8_DiodeExtractionScaled) // perform the extraction db::Netlist nl; - db::hier_clusters cl; + db::hier_clusters cl; db::NetlistDeviceExtractorDiode diode_ex ("DIODE"); @@ -1951,7 +1951,7 @@ TEST(9_StrictDeviceExtraction) // perform the extraction db::Netlist nl; - db::hier_clusters cl; + db::hier_clusters cl; db::NetlistDeviceExtractorMOS3Transistor pmos_ex ("PMOS", true /*strict*/); db::NetlistDeviceExtractorMOS3Transistor nmos_ex ("NMOS", true /*strict*/); @@ -2184,7 +2184,7 @@ TEST(10_DeviceExtractionWithBreakoutCells) // perform the extraction db::Netlist nl; - db::hier_clusters cl; + db::hier_clusters cl; db::NetlistDeviceExtractorMOS3Transistor pmos_ex ("PMOS"); db::NetlistDeviceExtractorMOS3Transistor nmos_ex ("NMOS"); @@ -2352,7 +2352,7 @@ TEST(11_DeviceExtractionWithSameClass) // perform the extraction db::Netlist nl; - db::hier_clusters cl; + db::hier_clusters cl; db::NetlistDeviceExtractorResistor polyres_ex ("RES", 50.0); db::NetlistDeviceExtractorResistor diffres_ex ("RES", 150.0); @@ -2474,7 +2474,7 @@ TEST(12_FloatingSubcircuitExtraction) // perform the extraction db::Netlist nl; - db::hier_clusters cl; + db::hier_clusters cl; db::NetlistDeviceExtractorMOS3Transistor pmos_ex ("PMOS"); db::NetlistDeviceExtractorMOS3Transistor nmos_ex ("NMOS"); @@ -2628,7 +2628,7 @@ TEST(13_RemoveDummyPins) // perform the extraction db::Netlist nl; - db::hier_clusters cl; + db::hier_clusters cl; db::NetlistDeviceExtractorMOS3Transistor pmos_ex ("PMOS"); db::NetlistDeviceExtractorMOS3Transistor nmos_ex ("NMOS"); diff --git a/src/db/unit_tests/unit_tests.pro b/src/db/unit_tests/unit_tests.pro index 7962b945a..d2753f09a 100644 --- a/src/db/unit_tests/unit_tests.pro +++ b/src/db/unit_tests/unit_tests.pro @@ -75,7 +75,8 @@ SOURCES = \ dbBoxScannerTests.cc \ dbBoxTests.cc \ dbArrayTests.cc \ - dbDeepTextsTests.cc + dbDeepTextsTests.cc \ + dbNetShapeTests.cc INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC DEPENDPATH += $$TL_INC $$DB_INC $$GSI_INC diff --git a/src/laybasic/laybasic/layNetInfoDialog.cc b/src/laybasic/laybasic/layNetInfoDialog.cc index f9ce3a2ea..9deaa7376 100644 --- a/src/laybasic/laybasic/layNetInfoDialog.cc +++ b/src/laybasic/laybasic/layNetInfoDialog.cc @@ -87,7 +87,7 @@ size_t count_shapes (db::LayoutToNetlist *l2ndb, db::Net *net, unsigned int laye size_t cluster_id = net->cluster_id (); size_t n = 0; - for (db::recursive_cluster_shape_iterator shapes (l2ndb->net_clusters (), layer, cell_index, cluster_id); ! shapes.at_end (); ++shapes) { + for (db::recursive_cluster_shape_iterator shapes (l2ndb->net_clusters (), layer, cell_index, cluster_id); ! shapes.at_end (); ++shapes) { ++n; } return n; @@ -278,7 +278,11 @@ void NetInfoDialog::update_info_text () std::string l = layer_string (mp_l2ndb.get (), *layer); - for (db::recursive_cluster_shape_iterator si (mp_l2ndb->net_clusters (), *layer, cell_index, cluster_id); ! si.at_end (); ++si) { + for (db::recursive_cluster_shape_iterator si (mp_l2ndb->net_clusters (), *layer, cell_index, cluster_id); ! si.at_end (); ++si) { + + if (si->type () != db::NetShape::Polygon) { + continue; + } if (tot_shapes++ >= max_shapes) { incomplete = true; @@ -295,7 +299,7 @@ void NetInfoDialog::update_info_text () statinfo_area.insert (std::make_pair (*layer, db::coord_traits::area_type (0))); } - s->second.push_back (si->instantiate ()); + s->second.push_back (si->polygon_ref ().instantiate ()); std::string c (ly->cell_name (si.cell_index ())); c += " (with "; diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.cc b/src/laybasic/laybasic/layNetlistBrowserPage.cc index aee0bc4b1..3c0882ad0 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.cc +++ b/src/laybasic/laybasic/layNetlistBrowserPage.cc @@ -987,9 +987,9 @@ NetlistBrowserPage::adjust_view () for (db::Connectivity::layer_iterator layer = conn.begin_layers (); layer != conn.end_layers (); ++layer) { db::Box layer_bbox; - db::recursive_cluster_shape_iterator shapes (mp_database->net_clusters (), *layer, cell_index, cluster_id); + db::recursive_cluster_shape_iterator shapes (mp_database->net_clusters (), *layer, cell_index, cluster_id); while (! shapes.at_end ()) { - layer_bbox += shapes.trans () * shapes->box (); + layer_bbox += shapes->bbox (); ++shapes; } @@ -1187,15 +1187,19 @@ NetlistBrowserPage::produce_highlights_for_net (const db::Net *net, size_t &n_ma db::LayerProperties lp = layout->get_properties (*layer); std::map::const_iterator display = display_by_lp.find (lp); - db::recursive_cluster_shape_iterator shapes (mp_database->net_clusters (), *layer, cell_index, cluster_id); + db::recursive_cluster_shape_iterator shapes (mp_database->net_clusters (), *layer, cell_index, cluster_id); while (! shapes.at_end ()) { + if (shapes->type () != db::NetShape::Polygon) { + continue; + } + if (n_markers == m_max_shape_count) { return true; } mp_markers.push_back (new lay::Marker (mp_view, m_cv_index)); - mp_markers.back ()->set (*shapes, net_trans * shapes.trans (), tv); + mp_markers.back ()->set (shapes->polygon_ref (), net_trans * shapes.trans (), tv); if (net_color.isValid ()) { From cd0b86b1dc2df0cab993a97a8cef70b4ca79c93c Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 20 May 2020 00:31:26 +0200 Subject: [PATCH 17/35] WIP: fixed tests. --- src/db/db/dbRegionUtils.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/db/db/dbRegionUtils.cc b/src/db/db/dbRegionUtils.cc index f0ead2b95..6a4829fe0 100644 --- a/src/db/db/dbRegionUtils.cc +++ b/src/db/db/dbRegionUtils.cc @@ -402,6 +402,7 @@ region_to_text_interaction_filter_base::fill_output () // explicit instantiations template class region_to_text_interaction_filter_base; +template class region_to_text_interaction_filter_base; template class region_to_text_interaction_filter_base; template class region_to_text_interaction_filter_base; From e9af72ee28648781842223c41f993d7350e386b1 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 20 May 2020 01:05:19 +0200 Subject: [PATCH 18/35] Tests for texts as net names, fixed Shapes test (order of texts) --- src/db/db/dbDeepShapeStore.cc | 30 +++ src/db/db/dbDeepShapeStore.h | 20 ++ src/db/unit_tests/dbNetlistExtractorTests.cc | 229 ++++++++++++++++++- src/db/unit_tests/dbShapesTests.cc | 14 +- testdata/algo/device_extract_au1.gds | Bin 7918 -> 8478 bytes testdata/algo/device_extract_au1a.gds | Bin 0 -> 7914 bytes 6 files changed, 277 insertions(+), 16 deletions(-) create mode 100644 testdata/algo/device_extract_au1a.gds diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index c8f249a76..72e5528a8 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -25,7 +25,13 @@ #include "dbCellMapping.h" #include "dbLayoutUtils.h" #include "dbRegion.h" +#include "dbEdges.h" +#include "dbEdgePairs.h" +#include "dbTexts.h" #include "dbDeepRegion.h" +#include "dbDeepEdges.h" +#include "dbDeepEdgePairs.h" +#include "dbDeepTexts.h" #include "tlTimer.h" @@ -48,6 +54,30 @@ DeepLayer::DeepLayer (const Region ®ion) *this = dr->deep_layer (); } +DeepLayer::DeepLayer (const Texts &texts) + : mp_store (), m_layout (0), m_layer (0) +{ + const db::DeepTexts *dr = dynamic_cast (texts.delegate ()); + tl_assert (dr != 0); + *this = dr->deep_layer (); +} + +DeepLayer::DeepLayer (const Edges &edges) + : mp_store (), m_layout (0), m_layer (0) +{ + const db::DeepEdges *dr = dynamic_cast (edges.delegate ()); + tl_assert (dr != 0); + *this = dr->deep_layer (); +} + +DeepLayer::DeepLayer (const EdgePairs &edge_pairs) + : mp_store (), m_layout (0), m_layer (0) +{ + const db::DeepEdgePairs *dr = dynamic_cast (edge_pairs.delegate ()); + tl_assert (dr != 0); + *this = dr->deep_layer (); +} + DeepLayer::DeepLayer (const DeepLayer &x) : mp_store (x.mp_store), m_layout (x.m_layout), m_layer (x.m_layer) { diff --git a/src/db/db/dbDeepShapeStore.h b/src/db/db/dbDeepShapeStore.h index 032fb8aad..981bf5259 100644 --- a/src/db/db/dbDeepShapeStore.h +++ b/src/db/db/dbDeepShapeStore.h @@ -43,6 +43,8 @@ class DeepShapeStore; class DeepShapeStoreState; class Region; class Edges; +class EdgePairs; +class Texts; /** * @brief Represents a shape collection from the deep shape store @@ -75,6 +77,24 @@ public: */ DeepLayer (const Region ®ion); + /** + * @brief Conversion operator from texts collection to DeepLayer + * This requires the texts to be a DeepTexts. Otherwise, this constructor will assert + */ + DeepLayer (const Texts ®ion); + + /** + * @brief Conversion operator from edges collection to DeepLayer + * This requires the edges to be a DeepEdges. Otherwise, this constructor will assert + */ + DeepLayer (const Edges ®ion); + + /** + * @brief Conversion operator from edge pairs collection to DeepLayer + * This requires the edge pairs to be a DeepEdgePairs. Otherwise, this constructor will assert + */ + DeepLayer (const EdgePairs ®ion); + /** * @brief Copy constructor */ diff --git a/src/db/unit_tests/dbNetlistExtractorTests.cc b/src/db/unit_tests/dbNetlistExtractorTests.cc index fecf213be..c6864d444 100644 --- a/src/db/unit_tests/dbNetlistExtractorTests.cc +++ b/src/db/unit_tests/dbNetlistExtractorTests.cc @@ -25,10 +25,11 @@ #include "dbNetlistExtractor.h" #include "dbNetlistDeviceClasses.h" #include "dbLayout.h" -#include "dbDeepShapeStore.h" #include "dbRegion.h" +#include "dbTexts.h" #include "dbStream.h" #include "dbDeepRegion.h" +#include "dbDeepTexts.h" #include "dbDeepShapeStore.h" #include "dbReader.h" #include "dbWriter.h" @@ -52,6 +53,13 @@ static unsigned int layer_of (const db::Region ®ion) return dr->deep_layer ().layer (); } +static unsigned int layer_of (const db::Texts ®ion) +{ + const db::DeepTexts *dr = dynamic_cast (region.delegate ()); + tl_assert (dr != 0); + return dr->deep_layer ().layer (); +} + static unsigned int define_layer (db::Layout &ly, db::LayerMap &lmap, int gds_layer, int gds_datatype = 0) { unsigned int lid = ly.insert_layer (db::LayerProperties (gds_layer, gds_datatype)); @@ -291,14 +299,17 @@ TEST(1_DeviceAndNetExtraction) // 210/0 -> N source/drain // 211/0 -> P source/drain std::map dump_map; - dump_map [layer_of (rpsd) ] = ly.insert_layer (db::LayerProperties (210, 0)); - dump_map [layer_of (rnsd) ] = ly.insert_layer (db::LayerProperties (211, 0)); - dump_map [layer_of (rpoly) ] = ly.insert_layer (db::LayerProperties (203, 0)); - dump_map [layer_of (rdiff_cont)] = ly.insert_layer (db::LayerProperties (204, 0)); - dump_map [layer_of (rpoly_cont)] = ly.insert_layer (db::LayerProperties (205, 0)); - dump_map [layer_of (rmetal1) ] = ly.insert_layer (db::LayerProperties (206, 0)); - dump_map [layer_of (rvia1) ] = ly.insert_layer (db::LayerProperties (207, 0)); - dump_map [layer_of (rmetal2) ] = ly.insert_layer (db::LayerProperties (208, 0)); + dump_map [layer_of (rpsd) ] = ly.insert_layer (db::LayerProperties (210, 0)); + dump_map [layer_of (rnsd) ] = ly.insert_layer (db::LayerProperties (211, 0)); + dump_map [layer_of (rpoly) ] = ly.insert_layer (db::LayerProperties (203, 0)); + dump_map [layer_of (rpoly_lbl) ] = ly.insert_layer (db::LayerProperties (203, 1)); + dump_map [layer_of (rdiff_cont) ] = ly.insert_layer (db::LayerProperties (204, 0)); + dump_map [layer_of (rpoly_cont) ] = ly.insert_layer (db::LayerProperties (205, 0)); + dump_map [layer_of (rmetal1) ] = ly.insert_layer (db::LayerProperties (206, 0)); + dump_map [layer_of (rmetal1_lbl) ] = ly.insert_layer (db::LayerProperties (206, 1)); + dump_map [layer_of (rvia1) ] = ly.insert_layer (db::LayerProperties (207, 0)); + dump_map [layer_of (rmetal2) ] = ly.insert_layer (db::LayerProperties (208, 0)); + dump_map [layer_of (rmetal2_lbl) ] = ly.insert_layer (db::LayerProperties (208, 1)); // write nets to layout db::CellMapping cm = dss.cell_mapping_to_original (0, &ly, tc.cell_index ()); @@ -371,6 +382,206 @@ TEST(1_DeviceAndNetExtraction) " device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n" "end;\n" ); + + // compare the collected test data + + std::string au = tl::testsrc (); + au = tl::combine_path (au, "testdata"); + au = tl::combine_path (au, "algo"); + au = tl::combine_path (au, "device_extract_au1.gds"); + + db::compare_layouts (_this, ly, au); +} + +TEST(1a_DeviceAndNetExtractionWithTextsAsLabels) +{ + db::Layout ly; + db::LayerMap lmap; + + unsigned int nwell = define_layer (ly, lmap, 1); + unsigned int active = define_layer (ly, lmap, 2); + unsigned int poly = define_layer (ly, lmap, 3); + unsigned int poly_lbl = define_layer (ly, lmap, 3, 1); + unsigned int diff_cont = define_layer (ly, lmap, 4); + unsigned int poly_cont = define_layer (ly, lmap, 5); + unsigned int metal1 = define_layer (ly, lmap, 6); + unsigned int metal1_lbl = define_layer (ly, lmap, 6, 1); + unsigned int via1 = define_layer (ly, lmap, 7); + unsigned int metal2 = define_layer (ly, lmap, 8); + unsigned int metal2_lbl = define_layer (ly, lmap, 8, 1); + + { + db::LoadLayoutOptions options; + options.get_options ().layer_map = lmap; + options.get_options ().create_other_layers = false; + + std::string fn (tl::testsrc ()); + fn = tl::combine_path (fn, "testdata"); + fn = tl::combine_path (fn, "algo"); + fn = tl::combine_path (fn, "device_extract_l1.gds"); + + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly, options); + } + + db::Cell &tc = ly.cell (*ly.begin_top_down ()); + + db::DeepShapeStore dss; + dss.set_text_enlargement (1); + dss.set_text_property_name (tl::Variant ("LABEL")); + + // original layers + db::Region rnwell (db::RecursiveShapeIterator (ly, tc, nwell), dss); + db::Region ractive (db::RecursiveShapeIterator (ly, tc, active), dss); + db::Region rpoly (db::RecursiveShapeIterator (ly, tc, poly), dss); + db::Texts rpoly_lbl (db::RecursiveShapeIterator (ly, tc, poly_lbl), dss); + db::Region rdiff_cont (db::RecursiveShapeIterator (ly, tc, diff_cont), dss); + db::Region rpoly_cont (db::RecursiveShapeIterator (ly, tc, poly_cont), dss); + db::Region rmetal1 (db::RecursiveShapeIterator (ly, tc, metal1), dss); + db::Texts rmetal1_lbl (db::RecursiveShapeIterator (ly, tc, metal1_lbl), dss); + db::Region rvia1 (db::RecursiveShapeIterator (ly, tc, via1), dss); + db::Region rmetal2 (db::RecursiveShapeIterator (ly, tc, metal2), dss); + db::Texts rmetal2_lbl (db::RecursiveShapeIterator (ly, tc, metal2_lbl), dss); + + // derived regions + + db::Region rpactive = ractive & rnwell; + db::Region rpgate = rpactive & rpoly; + db::Region rpsd = rpactive - rpgate; + + db::Region rnactive = ractive - rnwell; + db::Region rngate = rnactive & rpoly; + db::Region rnsd = rnactive - rngate; + + // return the computed layers into the original layout and write it for debugging purposes + + unsigned int lgate = ly.insert_layer (db::LayerProperties (10, 0)); // 10/0 -> Gate + unsigned int lsd = ly.insert_layer (db::LayerProperties (11, 0)); // 11/0 -> Source/Drain + unsigned int lpdiff = ly.insert_layer (db::LayerProperties (12, 0)); // 12/0 -> P Diffusion + unsigned int lndiff = ly.insert_layer (db::LayerProperties (13, 0)); // 13/0 -> N Diffusion + + rpgate.insert_into (&ly, tc.cell_index (), lgate); + rngate.insert_into (&ly, tc.cell_index (), lgate); + rpsd.insert_into (&ly, tc.cell_index (), lsd); + rnsd.insert_into (&ly, tc.cell_index (), lsd); + rpsd.insert_into (&ly, tc.cell_index (), lpdiff); + rnsd.insert_into (&ly, tc.cell_index (), lndiff); + + // perform the extraction + + db::Netlist nl; + db::hier_clusters cl; + + db::NetlistDeviceExtractorMOS3Transistor pmos_ex ("PMOS"); + db::NetlistDeviceExtractorMOS3Transistor nmos_ex ("NMOS"); + + db::NetlistDeviceExtractor::input_layers dl; + + dl["SD"] = &rpsd; + dl["G"] = &rpgate; + dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes + pmos_ex.extract (dss, 0, dl, nl, cl); + + dl["SD"] = &rnsd; + dl["G"] = &rngate; + dl["P"] = &rpoly; // not needed for extraction but to return terminal shapes + nmos_ex.extract (dss, 0, dl, nl, cl); + + // perform the net extraction + + db::NetlistExtractor net_ex; + + db::Connectivity conn; + // Intra-layer + conn.connect (rpsd); + conn.connect (rnsd); + conn.connect (rpoly); + conn.connect (rdiff_cont); + conn.connect (rpoly_cont); + conn.connect (rmetal1); + conn.connect (rvia1); + conn.connect (rmetal2); + // Inter-layer + conn.connect (rpsd, rdiff_cont); + conn.connect (rnsd, rdiff_cont); + conn.connect (rpoly, rpoly_cont); + conn.connect (rpoly_cont, rmetal1); + conn.connect (rdiff_cont, rmetal1); + conn.connect (rmetal1, rvia1); + conn.connect (rvia1, rmetal2); + conn.connect (rpoly, rpoly_lbl); // attaches labels + conn.connect (rmetal1, rmetal1_lbl); // attaches labels + conn.connect (rmetal2, rmetal2_lbl); // attaches labels + + // extract the nets + + net_ex.extract_nets (dss, 0, conn, nl, cl); + + // debug layers produced for nets + // 202/0 -> Active + // 203/0 -> Poly + // 204/0 -> Diffusion contacts + // 205/0 -> Poly contacts + // 206/0 -> Metal1 + // 207/0 -> Via1 + // 208/0 -> Metal2 + // 210/0 -> N source/drain + // 211/0 -> P source/drain + std::map dump_map; + dump_map [layer_of (rpsd) ] = ly.insert_layer (db::LayerProperties (210, 0)); + dump_map [layer_of (rnsd) ] = ly.insert_layer (db::LayerProperties (211, 0)); + dump_map [layer_of (rpoly) ] = ly.insert_layer (db::LayerProperties (203, 0)); + dump_map [layer_of (rpoly_lbl) ] = ly.insert_layer (db::LayerProperties (203, 1)); + dump_map [layer_of (rdiff_cont) ] = ly.insert_layer (db::LayerProperties (204, 0)); + dump_map [layer_of (rpoly_cont) ] = ly.insert_layer (db::LayerProperties (205, 0)); + dump_map [layer_of (rmetal1) ] = ly.insert_layer (db::LayerProperties (206, 0)); + dump_map [layer_of (rmetal1_lbl) ] = ly.insert_layer (db::LayerProperties (206, 1)); + dump_map [layer_of (rvia1) ] = ly.insert_layer (db::LayerProperties (207, 0)); + dump_map [layer_of (rmetal2) ] = ly.insert_layer (db::LayerProperties (208, 0)); + dump_map [layer_of (rmetal2_lbl) ] = ly.insert_layer (db::LayerProperties (208, 1)); + + // write nets to layout + db::CellMapping cm = dss.cell_mapping_to_original (0, &ly, tc.cell_index ()); + dump_nets_to_layout (nl, cl, ly, dump_map, cm); + + // compare netlist as string + CHECKPOINT (); + db::compare_netlist (_this, nl, + "circuit RINGO ();\n" + " subcircuit INV2 $1 (IN=$I8,$2=FB,OUT=OSC,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $2 (IN=FB,$2=$I38,OUT=$I19,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $3 (IN=$I19,$2=$I39,OUT=$I1,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $4 (IN=$I1,$2=$I40,OUT=$I2,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $5 (IN=$I2,$2=$I41,OUT=$I3,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $6 (IN=$I3,$2=$I42,OUT=$I4,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $7 (IN=$I4,$2=$I43,OUT=$I5,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $8 (IN=$I5,$2=$I44,OUT=$I6,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $9 (IN=$I6,$2=$I45,OUT=$I7,$4=VSS,$5=VDD);\n" + " subcircuit INV2 $10 (IN=$I7,$2=$I46,OUT=$I8,$4=VSS,$5=VDD);\n" + "end;\n" + "circuit INV2 (IN=IN,$2=$2,OUT=OUT,$4=$4,$5=$5);\n" + " device PMOS $1 (S=$2,G=IN,D=$5) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" + " device PMOS $2 (S=$5,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n" + " device NMOS $3 (S=$2,G=IN,D=$4) (L=0.25,W=0.95,AS=0.49875,AD=0.26125,PS=2.95,PD=1.5);\n" + " device NMOS $4 (S=$4,G=$2,D=OUT) (L=0.25,W=0.95,AS=0.26125,AD=0.49875,PS=1.5,PD=2.95);\n" + " subcircuit TRANS $1 ($1=$2,$2=$4,$3=IN);\n" + " subcircuit TRANS $2 ($1=$2,$2=$5,$3=IN);\n" + " subcircuit TRANS $3 ($1=$5,$2=OUT,$3=$2);\n" + " subcircuit TRANS $4 ($1=$4,$2=OUT,$3=$2);\n" + "end;\n" + "circuit TRANS ($1=$1,$2=$2,$3=$3);\n" + "end;\n" + ); + + // compare the collected test data + + std::string au = tl::testsrc (); + au = tl::combine_path (au, "testdata"); + au = tl::combine_path (au, "algo"); + au = tl::combine_path (au, "device_extract_au1a.gds"); + + db::compare_layouts (_this, ly, au); } TEST(2_DeviceAndNetExtractionFlat) diff --git a/src/db/unit_tests/dbShapesTests.cc b/src/db/unit_tests/dbShapesTests.cc index a43778b8f..c438c2e03 100644 --- a/src/db/unit_tests/dbShapesTests.cc +++ b/src/db/unit_tests/dbShapesTests.cc @@ -1318,6 +1318,9 @@ TEST(5) "text ('A',r0 10,35) #0\n" "text ('B',r90 20,25) #0\n" "text ('C',m90 30,15) #0\n" + "text ('A',r0 10,35) #1\n" + "text ('B',r90 20,25) #2\n" + "text ('C',m90 30,15) #3\n" "text ('A',r0 0,50) #0\n" "text ('B',r90 -90,140) #0\n" "text ('C',m90 -180,230) #0\n" @@ -1333,9 +1336,6 @@ TEST(5) "text ('A',r0 33010,40) #0\n" "text ('A',r0 33010,10040) #0\n" "text ('A',r0 33010,20040) #0\n" - "text ('A',r0 10,35) #1\n" - "text ('B',r90 20,25) #2\n" - "text ('C',m90 30,15) #3\n" "text ('A',r0 0,50) #5\n" "text ('B',r90 -90,140) #6\n" "text ('C',m90 -180,230) #7\n" @@ -1357,10 +1357,13 @@ TEST(5) for (db::Shapes::shape_iterator shape = topcell.shapes (lindex).begin (db::Shapes::shape_iterator::All); ! shape.at_end (); ++shape) { sa_copy.insert (*shape); } - EXPECT_EQ (shapes_to_string (_this, sa_copy), + EXPECT_EQ (shapes_to_string (_this, sa_copy), "text ('A',r0 10,35) #0\n" "text ('B',r90 20,25) #0\n" "text ('C',m90 30,15) #0\n" + "text ('A',r0 10,35) #1\n" + "text ('B',r90 20,25) #2\n" + "text ('C',m90 30,15) #3\n" "text ('A',r0 0,50) #0\n" "text ('B',r90 -90,140) #0\n" "text ('C',m90 -180,230) #0\n" @@ -1376,9 +1379,6 @@ TEST(5) "text ('A',r0 33010,40) #0\n" "text ('A',r0 33010,10040) #0\n" "text ('A',r0 33010,20040) #0\n" - "text ('A',r0 10,35) #1\n" - "text ('B',r90 20,25) #2\n" - "text ('C',m90 30,15) #3\n" "text ('A',r0 0,50) #5\n" "text ('B',r90 -90,140) #6\n" "text ('C',m90 -180,230) #7\n" diff --git a/testdata/algo/device_extract_au1.gds b/testdata/algo/device_extract_au1.gds index 903b6bf0d9ded99ed198b20e4753b10494c08656..77699100476948d4bff799ccafa702d2780d55e5 100644 GIT binary patch delta 1131 zcmaE7JI^VKfsKKQDS|{L4=vr&auJObm<+Is(iL49xNj4D9SsniEJX0{Ji+CeF^lBFMnN0_5WH?`AEwn>bxJ zS&Cz(@o9v`|NsBF53(3aa{}pyAd8_iOq_l4G7eu{KAz0Qc@?MJH_ppAEaJ~Nz1VH*DFtsrv z(J=A%xWl_1kx0?33=YO=CCEAufLI5z5`rP35E8eQC^k-Z<(~*kNJt)IV2FPYNl0KC zn1JGeo&zN$FbzyOPY792cTUr227 Yav5G0Q1nlh;gy^$E6Th1o{Rt!0KG2WqW}N^ delta 630 zcmbQ|^v*VlfsKKQDS|{L4=vr&au7022UcQ)box diff --git a/testdata/algo/device_extract_au1a.gds b/testdata/algo/device_extract_au1a.gds new file mode 100644 index 0000000000000000000000000000000000000000..79534b993db2fa59f48764479a023843932bb74a GIT binary patch literal 7914 zcmc&&QD|I66rJ~W^LDe@)L2)crARF+D8yWw`cc0Gp-{g>L>jF@{SaEDAJRV|;FoFB=ecv|?%a91FS~D58dy%aGw0p8 zXJ+oq9g~sUpz%-08Tg~J8e^ZT9L9P51#&b zcE)TN$mfkD$<*$d`I!Sdr>5tdCQ^UX)F9^Cx=to4nDjTyWXx&rG9=(OIW*nxU} zehK*)&%Ml#E;FA|>=rd&=67zSVvWWN%}C7KG7Yl524sI`uybe;e9%Ijt8~z*F1`SaC33J#=Tx@J&;Z`->es{1Ja36 z?1aI1Gx4JR0>z8pR}`;DvERI~8XufV)+^f0dI^f%Oa}anUhu!2^@_e>y%@z#SX{3$ zub0|?X?pz{uOq_x0`~o19%+4XdobQW@9Wnv9_UT|qRY%@6gy$SSLX@M541{no~p?6 zlm{5aZc*>wfKPe3gv~=({sesFXF;(8HUCGyKH+y0_^&gT4+3#M2#Ou3`I0~Ed5E(P z{_UC9^6UMxJ>x&*k3ye0^c%%I9D#lx35uPN{r7gBa=zVyFkHS>deQulo;*)gI%kky z7{$Jt-f8;x9OXmC3Y`_NQ2t{SJMyL0OX&^Xr{JGrtQ^HUe+ztvVoy%>6mLCACYn>v z?wfA?KbC84vF6-KB3s#_<`1xL&!h- zb-4h1{w~=)zsua#B-Ylfs*xf>C}<-+DiI2b-FtGYLh)rpeuVKE7wH+x6D9Pl{$G*W zS=}GbYLKz|m{rB^5bG_TRf@GWt7@cu&8p&ei1gOYD%P*9E0C3H#*D1hmBtoRr<<7j zvumua&sYzA#@qY2wI2J7pH(%xtEHW@!XQ^bCC5+hi80FRZ8X|t)8J8aj;GO=HU_z* ztiASeug~z|pxC`$@v)nW*HIZh`KRyT*IONx==h7&6>ioPAHJ_36aA-k*nz!MPw$&= z`npry1C5z~6;uBnW95V~hhN4ytV$Z~@_{O|2&Uz7&PO}eqB)wdF zj$ZJ)hxB43on}!d2#UQ&y{btCZ(I`zioH?|_M&9$QS#r%omcTO z=f!K3fZs=rqWIVo1@7E+Y$Lqcfqz$QBG#X36zG$z!@dYq8t^J}W|xXbDj-3zXDT7Z z$0!Tj?A^I48D5>M(TnuXXwOn(zQhU4_q*W+5M% z^;*|C&A}JVTjQ**OZGiC<1&u(Q}L?18lc#FLxvB1ioG|q@#P&z-h~9ko_QZ?3vP!A?01twd-}J_>^0S z&q(hlR8I?vJ@Y=N_?%nl{Zihk$giz2hw&|Ix44RbYG?mc+me4qvA6Mubo>&h#NEUD ztK!T15Mz(;M*+W&_f5s8`LglZc_ZCu{ET8>Eq)p|wHJE7QvSg${@z&sm-;JyU-}39 zKJ*_B$1ggI?t)^ssMoLJ_oaWpFQR{!dp2rRd&kBiLj74?%eP2-LqU$EKO051t+qeE zt#LZP?e3-gw)=PFw~dE4&|sWTT+Qe0c__c_z_I+cxy7K(-DX?WNGE;5J{@ZJPA6{m zmeWH86P!eSR4|I)s!(jD(qjb^@cXD3gOjXC1=M~L7OObjjRpSwjb$F|5jQKku}nYd p)_SLYv>Ny}`P44n5qZ7P5nnqvJ>BJNs2r%@#DwdIeOfM?e*iirVr~Ec literal 0 HcmV?d00001 From 854320d52d295e3031e55e16ce2f914149eb72a7 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 20 May 2020 23:27:06 +0200 Subject: [PATCH 19/35] Debugging: proper assignment of net names through labels. --- src/db/db/dbHierNetworkProcessor.cc | 14 +++++-------- src/db/db/dbHierNetworkProcessor.h | 13 +++++++++++- src/db/db/dbNetlistExtractor.cc | 20 +++++++++++-------- src/db/unit_tests/dbNetlistExtractorTests.cc | 18 ++++++++++++++++- testdata/algo/device_extract_au1a.gds | Bin 7914 -> 8330 bytes 5 files changed, 46 insertions(+), 19 deletions(-) diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index babb8d5fc..33ae690d4 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -990,7 +990,7 @@ template struct get_shape_flags { }; template <> struct get_shape_flags { - db::ShapeIterator::flags_type operator() (bool /*with_attr*/) const + db::ShapeIterator::flags_type operator() () const { return db::ShapeIterator::Edges; } @@ -999,7 +999,7 @@ struct get_shape_flags template <> struct get_shape_flags { - db::ShapeIterator::flags_type operator() (bool /*with_attr*/) const + db::ShapeIterator::flags_type operator() () const { return db::ShapeIterator::Polygons; } @@ -1008,13 +1008,9 @@ struct get_shape_flags template <> struct get_shape_flags { - db::ShapeIterator::flags_type operator() (bool with_attr) const + db::ShapeIterator::flags_type operator() () const { - if (with_attr) { - return db::ShapeIterator::flags_type (db::ShapeIterator::Polygons | db::ShapeIterator::Texts); - } else { - return db::ShapeIterator::flags_type (db::ShapeIterator::Polygons); - } + return db::ShapeIterator::flags_type (db::ShapeIterator::Polygons | db::ShapeIterator::Texts); } }; @@ -1030,7 +1026,7 @@ local_clusters::build_clusters (const db::Cell &cell, const db::Connectivity db::box_convert bc; addressable_shape_delivery heap; attr_accessor attr; - db::ShapeIterator::flags_type shape_flags = get_shape_flags () (attr_equivalence != 0 /*with attributes*/); + db::ShapeIterator::flags_type shape_flags = get_shape_flags () (); for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) { const db::Shapes &shapes = cell.shapes (*l); diff --git a/src/db/db/dbHierNetworkProcessor.h b/src/db/db/dbHierNetworkProcessor.h index 577eef944..625a972b8 100644 --- a/src/db/db/dbHierNetworkProcessor.h +++ b/src/db/db/dbHierNetworkProcessor.h @@ -31,6 +31,7 @@ #include "dbCell.h" #include "dbInstElement.h" #include "tlEquivalenceClusters.h" +#include "tlAssert.h" #include #include @@ -1365,7 +1366,17 @@ inline db::properties_id_type prop_id_from_attr (size_t attr) */ inline size_t text_ref_to_attr (const db::Text *tr) { - return size_t (tr) * 2 + 1; + return size_t (tr) + 1; +} + +/** + * @brief Gets the text value from an attribute ID + */ +inline const char *text_from_attr (size_t attr) +{ + tl_assert ((attr & 1) != 0); + const db::Text *t = reinterpret_cast (attr - 1); + return t->string (); } } diff --git a/src/db/db/dbNetlistExtractor.cc b/src/db/db/dbNetlistExtractor.cc index bfe1fba9f..7783ffbc6 100644 --- a/src/db/db/dbNetlistExtractor.cc +++ b/src/db/db/dbNetlistExtractor.cc @@ -300,19 +300,23 @@ void NetlistExtractor::collect_labels (const connected_clusters_type &clusters, const local_cluster_type &lc = clusters.cluster_by_id (cid); for (local_cluster_type::attr_iterator a = lc.begin_attr (); a != lc.end_attr (); ++a) { - if (! db::is_prop_id_attr (*a)) { - continue; - } + if (db::is_prop_id_attr (*a)) { - db::properties_id_type pi = db::prop_id_from_attr (*a); + db::properties_id_type pi = db::prop_id_from_attr (*a); - const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (pi); - for (db::PropertiesRepository::properties_set::const_iterator j = ps.begin (); j != ps.end (); ++j) { + const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (pi); + for (db::PropertiesRepository::properties_set::const_iterator j = ps.begin (); j != ps.end (); ++j) { + + if (m_text_annot_name_id.first && j->first == m_text_annot_name_id.second) { + net_names.insert (j->second.to_string ()); + } - if (m_text_annot_name_id.first && j->first == m_text_annot_name_id.second) { - net_names.insert (j->second.to_string ()); } + } else { + + net_names.insert (db::text_from_attr (*a)); + } } diff --git a/src/db/unit_tests/dbNetlistExtractorTests.cc b/src/db/unit_tests/dbNetlistExtractorTests.cc index c6864d444..8b3600bd5 100644 --- a/src/db/unit_tests/dbNetlistExtractorTests.cc +++ b/src/db/unit_tests/dbNetlistExtractorTests.cc @@ -77,6 +77,7 @@ static void dump_nets_to_layout (const db::Netlist &nl, const db::hier_clusters< for (db::Circuit::const_net_iterator n = c->begin_nets (); n != c->end_nets (); ++n) { + std::string nn = "NET_" + c->name () + "_" + n->expanded_name (); const db::local_cluster &lc = clusters.clusters_per_cell (c->cell_index ()).cluster_by_id (n->cluster_id ()); bool any_shapes = false; @@ -86,7 +87,6 @@ static void dump_nets_to_layout (const db::Netlist &nl, const db::hier_clusters< if (any_shapes || (with_device_cells && n->terminal_count() > 0)) { - std::string nn = "NET_" + c->name () + "_" + n->expanded_name (); db::Cell &net_cell = ly.cell (ly.add_cell (nn.c_str ())); cell.insert (db::CellInstArray (db::CellInst (net_cell.cell_index ()), db::Trans ())); @@ -288,6 +288,14 @@ TEST(1_DeviceAndNetExtraction) net_ex.extract_nets (dss, 0, conn, nl, cl); + // check if net names are properly assigned + db::Circuit *top_circuit = nl.circuit_by_name ("RINGO"); + EXPECT_EQ (top_circuit != 0, true); + if (top_circuit) { + db::Net *fb_net = top_circuit->net_by_name ("FB"); + EXPECT_EQ (fb_net != 0, true); + } + // debug layers produced for nets // 202/0 -> Active // 203/0 -> Poly @@ -518,6 +526,14 @@ TEST(1a_DeviceAndNetExtractionWithTextsAsLabels) net_ex.extract_nets (dss, 0, conn, nl, cl); + // check if net names are properly assigned + db::Circuit *top_circuit = nl.circuit_by_name ("RINGO"); + EXPECT_EQ (top_circuit != 0, true); + if (top_circuit) { + db::Net *fb_net = top_circuit->net_by_name ("FB"); + EXPECT_EQ (fb_net != 0, true); + } + // debug layers produced for nets // 202/0 -> Active // 203/0 -> Poly diff --git a/testdata/algo/device_extract_au1a.gds b/testdata/algo/device_extract_au1a.gds index 79534b993db2fa59f48764479a023843932bb74a..47ac063c7e903def18bd5df9938bcdc44bff5693 100644 GIT binary patch delta 848 zcmaE5+vTXlz{bGD6u}_F$i)7Hft5joK^zEGkl7QJ)CDmGqvEj$p1O}IIC&Q%Hqli~ zDwE$a|5n5>nL&V!&CfL?-qSD4C|<>cVG@_vWChlr1Qhy*hD_eY^ofIqfq{*eiQ(Mj zIid=3>g3HFZdkm@#d#Zx z=r_)rSVSLiVN-jC8;jb_+jy#(bTM5i1PP@ePd|76_%Ih21_l2za=aJE==~5Q?MXl5HzMCesFVQVBvtp z-Z>fj$=(7x5vG;N$q|Uo$x4EAnSk+iP|%GTlo}?;$V|Q`$hKKWNR|^b3N}Ycn=mrD sIZZB*78MW@0;f2LJ3t;fC@6+17#19iMbO0sC@4HxkC%P(Ss7U-05r~>761SM delta 618 zcmeBjd}XV|z{bGD6u}_F$i)7Hft5jofq}t{!3vo@QAu48Q!pwXi{PpIn1YjcF=7*4 z#iTM>kM*7|I|G9ZD^9x^1lZX8TtnhL{lbjmRZJ!)vWZW=!1PlA!#$`9jVCW;6Q9KL z6Vo-DgV^pf64GusIgq1ya)BWG}I3`6*HPAo_^7M1}k5@68yiQPTa*jZb9&up_)n>R^PmqaG z4!@qsB|>wVR17EA3oB1H6INzYF$OU=*9psVV)}FQ8W|JD$qKx3>`*HvACwW^oF=Ej F1OOOxZx#Rm From 5795ec8b07ea94529a341aa5ef712d3bf7e12153 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 20 May 2020 23:56:35 +0200 Subject: [PATCH 20/35] Fixed DRC texts methods, added tests. --- src/drc/drc/built-in-macros/_drc_layer.rb | 18 ++++++++++++------ testdata/drc/drcSimpleTests_8.drc | 22 +++++++++++++++++++--- testdata/drc/drcSimpleTests_au8.gds | Bin 2792 -> 3976 bytes testdata/drc/texts.gds | Bin 586 -> 624 bytes 4 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/drc/drc/built-in-macros/_drc_layer.rb b/src/drc/drc/built-in-macros/_drc_layer.rb index 211fc45fa..bebaa7dae 100644 --- a/src/drc/drc/built-in-macros/_drc_layer.rb +++ b/src/drc/drc/built-in-macros/_drc_layer.rb @@ -669,20 +669,22 @@ CODE if @data.is_a?(RBA::Texts) if as_pattern - DRCLayer::new(@engine, @engine._tcmd(@data, 0, RBA::Texts, :with_match, pattern, invert)) + result = @engine._tcmd(@data, 0, RBA::Texts, :with_match, pattern, invert) else - DRCLayer::new(@engine, @engine._tcmd(@data, 0, RBA::Texts, :with_text, pattern, invert)) + result = @engine._tcmd(@data, 0, RBA::Texts, :with_text, pattern, invert) end if as_dots - DRCLayer::new(@engine, @engine._tcmd(@data, 0, RBA::Region, :edges)) + return DRCLayer::new(@engine, @engine._tcmd(result, 0, RBA::Region, :edges)) elsif as_dots == false - DRCLayer::new(@engine, @engine._tcmd(@data, 0, RBA::Region, :polygons)) + return DRCLayer::new(@engine, @engine._tcmd(result, 0, RBA::Region, :polygons)) + else + return DRCLayer::new(@engine, result) end else if as_dots - DRCLayer::new(@engine, @engine._tcmd(@data, 0, RBA::Region, :texts_dots, pattern, as_pattern)) + return DRCLayer::new(@engine, @engine._tcmd(@data, 0, RBA::Region, :texts_dots, pattern, as_pattern)) else - DRCLayer::new(@engine, @engine._tcmd(@data, 0, RBA::Region, :texts, pattern, as_pattern)) + return DRCLayer::new(@engine, @engine._tcmd(@data, 0, RBA::Region, :texts, pattern, as_pattern)) end end @@ -3080,6 +3082,10 @@ CODE @data.is_a?(RBA::Region) || @data.is_a?(RBA::Texts) || raise("#{f}: Requires a polygon or text layer") end + def requires_texts(f) + @data.is_a?(RBA::Texts) || raise("#{f}: Requires a text layer") + end + def requires_edge_pairs(f) @data.is_a?(RBA::EdgePairs) || raise("#{f}: Requires a edge pair layer") end diff --git a/testdata/drc/drcSimpleTests_8.drc b/testdata/drc/drcSimpleTests_8.drc index faab090a9..9e24350e0 100644 --- a/testdata/drc/drcSimpleTests_8.drc +++ b/testdata/drc/drcSimpleTests_8.drc @@ -1,17 +1,21 @@ -# Hierarchical antenna check +# Text handling - mixed mode and pure texts source($drc_test_source, "TOP") target($drc_test_target) # Flat mode -flat_labels = labels(1, 0) +flat_labels = input(1, 1) # mixed mode, labels only +flat_texts = labels(1, 0) # text objects flat_all = input(1, 0) flat_poly = polygons(1, 0) flat_texts_from_labels1 = flat_labels.texts(text("XYZ")) flat_texts_from_labels2 = flat_labels.texts("*") +flat_texts_from_texts1 = flat_texts.texts(text("XYZ")) +flat_texts_from_texts2 = flat_texts.texts("*") +flat_texts_from_texts3 = flat_texts.texts_not("U*") flat_texts_from_all1 = flat_all.texts(text("XYZ")) flat_texts_from_all2 = flat_all.texts("*") flat_texts_from_poly1 = flat_poly.texts(text("XYZ")) @@ -20,23 +24,31 @@ flat_texts_from_poly2 = flat_poly.texts("*") flat_labels.output(100, 0) flat_all.output(101, 0) flat_poly.output(102, 0) +flat_texts.output(103, 0) flat_texts_from_labels1.output(110, 0) flat_texts_from_labels2.output(111, 0) flat_texts_from_all1.output(112, 0) flat_texts_from_all2.output(113, 0) flat_texts_from_poly1.output(114, 0) flat_texts_from_poly2.output(115, 0) +flat_texts_from_texts1.output(116, 0) +flat_texts_from_texts2.output(117, 0) +flat_texts_from_texts3.output(118, 0) # Deep mode deep -deep_labels = labels(1, 0) +deep_labels = input(1, 1) # mixed mode, labels only +deep_texts = labels(1, 1) # text objects deep_all = input(1, 0) deep_poly = polygons(1, 0) deep_texts_from_labels1 = deep_labels.texts(text("XYZ")) deep_texts_from_labels2 = deep_labels.texts("*") +deep_texts_from_texts1 = deep_texts.texts(text("XYZ")) +deep_texts_from_texts2 = deep_texts.texts("*") +deep_texts_from_texts3 = deep_texts.texts_not("U*") deep_texts_from_all1 = deep_all.texts(text("XYZ")) deep_texts_from_all2 = deep_all.texts("*") deep_texts_from_poly1 = deep_poly.texts(text("XYZ")) @@ -45,10 +57,14 @@ deep_texts_from_poly2 = deep_poly.texts("*") deep_labels.output(200, 0) deep_all.output(201, 0) deep_poly.output(202, 0) +deep_texts.output(203, 0) deep_texts_from_labels1.output(210, 0) deep_texts_from_labels2.output(211, 0) deep_texts_from_all1.output(212, 0) deep_texts_from_all2.output(213, 0) deep_texts_from_poly1.output(214, 0) deep_texts_from_poly2.output(215, 0) +deep_texts_from_texts1.output(216, 0) +deep_texts_from_texts2.output(217, 0) +deep_texts_from_texts3.output(218, 0) diff --git a/testdata/drc/drcSimpleTests_au8.gds b/testdata/drc/drcSimpleTests_au8.gds index 86825b3c5a1030dd0e2d5e566d939dd96107e245..92a97ed8a93b95339c9a4e25665948f8c61f77ba 100644 GIT binary patch delta 371 zcmaDM+94msz{bGD6u}_F$i)7Hft5joL7YL4K^mFOz`?}kXR)Qf5P}TCT1zX*f){bw}5Opb_RT= zP7Yw22h)0b@;RmjFwRXNhmhvYJ^En!SHjhl sfMrW2gJes9vKBDSrC`maVChn@G*AQ~T?UpY151>FB-ntyVqswb0D9&}s{jB1 delta 189 zcmeB>e<2#hz{bGD6u}_F$i)7bfti7mL5M+(K>?Y~z`?}k8zWt(eQt}${L4=vr&au>S2S_78>9BgbM{sC|!oF@Ndl$mVIBn|*E2O<9e literal 586 zcmZQzV_;&6V31*CVt>rQ%)rVZ288U$Yz7V{HXlzX1_lvkRy)T|bMIrzKUli#&|fe+ zDuh9X6}LV%Ha15F1{Mwm1~y(M21W)pJ|+eR1|0$B|NnpA0pcbQ&Aeld`KHgQIvE7_zNfovXWRtL2-Fks*Tnfw3E|Ns9^F>pw-MMOpc^@8-X zGZ1nm&~GeUK$C?)?uDD|C;+qp1bAdv9l#6_TYwozPGewTlz^Cyu1|*531~4GfL-*3 z3Fs;x(tYwP3#hLSNz!NwNi9{~3Y&{xFx#R%+Ha7dy1MVb{?82tbL^#%h2 LP(3V!Sy&hVda72< From c682cc85d07b9088c411a45e592f90597babbe93 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 21 May 2020 23:59:30 +0200 Subject: [PATCH 21/35] Generalized concept of region, texts etc. into 'shape collections'. Fixed LVS and DRC tests. --- src/db/db/db.pro | 7 +- src/db/db/dbDeepEdgePairs.cc | 52 ++++--- src/db/db/dbDeepEdgePairs.h | 13 +- src/db/db/dbDeepEdges.cc | 74 +++++----- src/db/db/dbDeepEdges.h | 12 +- src/db/db/dbDeepRegion.cc | 74 +++++----- src/db/db/dbDeepRegion.h | 12 +- src/db/db/dbDeepShapeStore.cc | 5 +- src/db/db/dbDeepShapeStore.h | 5 +- src/db/db/dbDeepTexts.cc | 55 ++++--- src/db/db/dbDeepTexts.h | 13 +- src/db/db/dbEdgePairs.cc | 2 +- src/db/db/dbEdgePairs.h | 13 +- src/db/db/dbEdgePairsDelegate.cc | 2 +- src/db/db/dbEdgePairsDelegate.h | 5 +- src/db/db/dbEdges.cc | 2 +- src/db/db/dbEdges.h | 13 +- src/db/db/dbEdgesDelegate.cc | 2 +- src/db/db/dbEdgesDelegate.h | 4 +- src/db/db/dbLayoutToNetlist.cc | 138 +++++++++--------- src/db/db/dbLayoutToNetlist.h | 69 +++++++-- src/db/db/dbLayoutToNetlistReader.cc | 2 +- src/db/db/dbNetlistDeviceExtractor.cc | 4 +- src/db/db/dbNetlistDeviceExtractor.h | 2 +- src/db/db/dbRegion.cc | 2 +- src/db/db/dbRegion.h | 13 +- src/db/db/dbRegionDelegate.cc | 2 +- src/db/db/dbRegionDelegate.h | 4 +- src/db/db/dbShapeCollection.cc | 0 src/db/db/dbShapeCollection.h | 115 +++++++++++++++ src/db/db/dbTexts.cc | 2 +- src/db/db/dbTexts.h | 13 +- src/db/db/dbTextsDelegate.cc | 2 +- src/db/db/dbTextsDelegate.h | 5 +- src/db/db/gsiDeclDbEdgePairs.cc | 4 +- src/db/db/gsiDeclDbEdges.cc | 4 +- src/db/db/gsiDeclDbLayoutToNetlist.cc | 51 ++++++- src/db/db/gsiDeclDbRegion.cc | 4 +- src/db/db/gsiDeclDbShapeCollection.cc | 36 +++++ src/db/db/gsiDeclDbTexts.cc | 4 +- src/db/unit_tests/dbLayoutToNetlistTests.cc | 54 +++---- .../dbLayoutToNetlistWriterTests.cc | 12 +- src/db/unit_tests/dbLayoutVsSchematicTests.cc | 12 +- src/drc/drc/built-in-macros/_drc_netter.rb | 14 +- .../streamers/cif/db_plugin/dbCIFReader.cc | 2 +- .../streamers/dxf/db_plugin/dbDXFReader.cc | 2 +- .../db_plugin/contrib/dbGDS2TextReader.cc | 6 + .../gds2/db_plugin/contrib/dbGDS2TextReader.h | 1 + .../streamers/gds2/db_plugin/dbGDS2Reader.cc | 6 + .../streamers/gds2/db_plugin/dbGDS2Reader.h | 1 + .../gds2/db_plugin/dbGDS2ReaderBase.cc | 2 +- .../gds2/db_plugin/dbGDS2ReaderBase.h | 1 + .../streamers/magic/db_plugin/dbMAGReader.cc | 2 +- .../oasis/db_plugin/dbOASISReader.cc | 2 +- testdata/algo/l2n_writer_au.txt | 16 +- testdata/algo/l2n_writer_au_p.txt | 16 +- testdata/algo/l2n_writer_au_s.txt | 16 +- testdata/lvs/inv.lvsdb | 18 +-- testdata/lvs/inv2.lvsdb | 18 +-- testdata/lvs/nand2_split_gate.lvsdb.1 | 20 +-- testdata/lvs/nand2_split_gate.lvsdb.2 | 20 +-- testdata/lvs/ringo_simple_blackboxing.lvsdb | 9 +- 62 files changed, 681 insertions(+), 410 deletions(-) create mode 100644 src/db/db/dbShapeCollection.cc create mode 100644 src/db/db/dbShapeCollection.h create mode 100644 src/db/db/gsiDeclDbShapeCollection.cc diff --git a/src/db/db/db.pro b/src/db/db/db.pro index 0c46d7302..6ee1e93fd 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -194,7 +194,9 @@ SOURCES = \ dbFlatTexts.cc \ dbTextsUtils.cc \ dbOriginalLayerTexts.cc \ - dbNetShape.cc + dbNetShape.cc \ + dbShapeCollection.cc \ + gsiDeclDbShapeCollection.cc HEADERS = \ dbArray.h \ @@ -350,7 +352,8 @@ HEADERS = \ dbFlatTexts.h \ dbTextsUtils.h \ dbOriginalLayerTexts.h \ - dbNetShape.h + dbNetShape.h \ + dbShapeCollection.h !equals(HAVE_QT, "0") { diff --git a/src/db/db/dbDeepEdgePairs.cc b/src/db/db/dbDeepEdgePairs.cc index f0138a17c..95d105d91 100644 --- a/src/db/db/dbDeepEdgePairs.cc +++ b/src/db/db/dbDeepEdgePairs.cc @@ -86,34 +86,33 @@ private: DeepEdgePairs::DeepEdgePairs () - : AsIfFlatEdgePairs (), m_deep_layer () + : AsIfFlatEdgePairs () { // .. nothing yet .. } DeepEdgePairs::DeepEdgePairs (const RecursiveShapeIterator &si, DeepShapeStore &dss) - : AsIfFlatEdgePairs (), m_deep_layer (dss.create_edge_pair_layer (si)) + : AsIfFlatEdgePairs () { - // .. nothing yet .. + set_deep_layer (dss.create_edge_pair_layer (si)); } DeepEdgePairs::DeepEdgePairs (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans) - : AsIfFlatEdgePairs (), m_deep_layer (dss.create_edge_pair_layer (si, trans)) + : AsIfFlatEdgePairs () { - // .. nothing yet .. + set_deep_layer (dss.create_edge_pair_layer (si, trans)); } DeepEdgePairs::DeepEdgePairs (const DeepEdgePairs &other) - : AsIfFlatEdgePairs (other), - m_deep_layer (other.m_deep_layer.copy ()) + : AsIfFlatEdgePairs (other), db::DeepShapeCollectionDelegateBase (other) { // .. nothing yet .. } DeepEdgePairs::DeepEdgePairs (const DeepLayer &dl) - : AsIfFlatEdgePairs (), m_deep_layer (dl) + : AsIfFlatEdgePairs () { - // .. nothing yet .. + set_deep_layer (dl); } DeepEdgePairs::~DeepEdgePairs () @@ -133,7 +132,7 @@ EdgePairsIteratorDelegate *DeepEdgePairs::begin () const std::pair DeepEdgePairs::begin_iter () const { - const db::Layout &layout = m_deep_layer.layout (); + const db::Layout &layout = deep_layer ().layout (); if (layout.cells () == 0) { return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ()); @@ -141,7 +140,7 @@ std::pair DeepEdgePairs::begin_iter } else { const db::Cell &top_cell = layout.cell (*layout.begin_top_down ()); - db::RecursiveShapeIterator iter (m_deep_layer.layout (), top_cell, m_deep_layer.layer ()); + db::RecursiveShapeIterator iter (deep_layer ().layout (), top_cell, deep_layer ().layer ()); return std::make_pair (iter, db::ICplxTrans ()); } @@ -151,10 +150,10 @@ size_t DeepEdgePairs::size () const { size_t n = 0; - const db::Layout &layout = m_deep_layer.layout (); + const db::Layout &layout = deep_layer ().layout (); db::CellCounter cc (&layout); for (db::Layout::top_down_const_iterator c = layout.begin_top_down (); c != layout.end_top_down (); ++c) { - n += cc.weight (*c) * layout.cell (*c).shapes (m_deep_layer.layer ()).size (); + n += cc.weight (*c) * layout.cell (*c).shapes (deep_layer ().layer ()).size (); } return n; @@ -167,7 +166,7 @@ std::string DeepEdgePairs::to_string (size_t nmax) const Box DeepEdgePairs::bbox () const { - return m_deep_layer.initial_cell ().bbox (m_deep_layer.layer ()); + return deep_layer ().initial_cell ().bbox (deep_layer ().layer ()); } bool DeepEdgePairs::empty () const @@ -243,12 +242,12 @@ EdgePairsDelegate *DeepEdgePairs::filtered (const EdgePairFilterBase &filter) co RegionDelegate *DeepEdgePairs::polygons (db::Coord e) const { - db::DeepLayer new_layer = m_deep_layer.derived (); - db::Layout &layout = const_cast (m_deep_layer.layout ()); + db::DeepLayer new_layer = deep_layer ().derived (); + db::Layout &layout = const_cast (deep_layer ().layout ()); for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { db::Shapes &output = c->shapes (new_layer.layer ()); - for (db::Shapes::shape_iterator s = c->shapes (m_deep_layer.layer ()).begin (db::ShapeIterator::EdgePairs); ! s.at_end (); ++s) { + for (db::Shapes::shape_iterator s = c->shapes (deep_layer ().layer ()).begin (db::ShapeIterator::EdgePairs); ! s.at_end (); ++s) { db::Polygon poly = s->edge_pair ().normalized ().to_polygon (e); if (poly.vertices () >= 3) { output.insert (db::PolygonRef (poly, layout.shape_repository ())); @@ -261,12 +260,12 @@ RegionDelegate *DeepEdgePairs::polygons (db::Coord e) const EdgesDelegate *DeepEdgePairs::generic_edges (bool first, bool second) const { - db::DeepLayer new_layer = m_deep_layer.derived (); - db::Layout &layout = const_cast (m_deep_layer.layout ()); + db::DeepLayer new_layer = deep_layer ().derived (); + db::Layout &layout = const_cast (deep_layer ().layout ()); for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { db::Shapes &output = c->shapes (new_layer.layer ()); - for (db::Shapes::shape_iterator s = c->shapes (m_deep_layer.layer ()).begin (db::ShapeIterator::EdgePairs); ! s.at_end (); ++s) { + for (db::Shapes::shape_iterator s = c->shapes (deep_layer ().layer ()).begin (db::ShapeIterator::EdgePairs); ! s.at_end (); ++s) { db::EdgePair ep = s->edge_pair (); if (first) { output.insert (ep.first ()); @@ -304,8 +303,8 @@ EdgePairsDelegate *DeepEdgePairs::in (const EdgePairs &other, bool invert) const bool DeepEdgePairs::equals (const EdgePairs &other) const { const DeepEdgePairs *other_delegate = dynamic_cast (other.delegate ()); - if (other_delegate && &other_delegate->m_deep_layer.layout () == &m_deep_layer.layout () - && other_delegate->m_deep_layer.layer () == m_deep_layer.layer ()) { + if (other_delegate && &other_delegate->deep_layer ().layout () == &deep_layer ().layout () + && other_delegate->deep_layer ().layer () == deep_layer ().layer ()) { return true; } else { return AsIfFlatEdgePairs::equals (other); @@ -315,8 +314,8 @@ bool DeepEdgePairs::equals (const EdgePairs &other) const bool DeepEdgePairs::less (const EdgePairs &other) const { const DeepEdgePairs *other_delegate = dynamic_cast (other.delegate ()); - if (other_delegate && &other_delegate->m_deep_layer.layout () == &m_deep_layer.layout ()) { - return other_delegate->m_deep_layer.layer () < m_deep_layer.layer (); + if (other_delegate && &other_delegate->deep_layer ().layout () == &deep_layer ().layout ()) { + return other_delegate->deep_layer ().layer () < deep_layer ().layer (); } else { return AsIfFlatEdgePairs::less (other); } @@ -324,13 +323,12 @@ bool DeepEdgePairs::less (const EdgePairs &other) const void DeepEdgePairs::insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const { - m_deep_layer.insert_into (layout, into_cell, into_layer); + deep_layer ().insert_into (layout, into_cell, into_layer); } void DeepEdgePairs::insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const { - m_deep_layer.insert_into_as_polygons (layout, into_cell, into_layer, enl); + deep_layer ().insert_into_as_polygons (layout, into_cell, into_layer, enl); } - } diff --git a/src/db/db/dbDeepEdgePairs.h b/src/db/db/dbDeepEdgePairs.h index a6d0732f1..c75355a35 100644 --- a/src/db/db/dbDeepEdgePairs.h +++ b/src/db/db/dbDeepEdgePairs.h @@ -36,7 +36,7 @@ namespace db { * @brief Provides hierarchical edges implementation */ class DB_PUBLIC DeepEdgePairs - : public db::AsIfFlatEdgePairs + : public db::AsIfFlatEdgePairs, public db::DeepShapeCollectionDelegateBase { public: DeepEdgePairs (); @@ -80,21 +80,14 @@ public: virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const; virtual void insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const; - const DeepLayer &deep_layer () const + virtual DeepShapeCollectionDelegateBase *deep () { - return m_deep_layer; - } - - DeepLayer &deep_layer () - { - return m_deep_layer; + return this; } private: DeepEdgePairs &operator= (const DeepEdgePairs &other); - DeepLayer m_deep_layer; - void init (); EdgesDelegate *generic_edges (bool first, bool second) const; }; diff --git a/src/db/db/dbDeepEdges.cc b/src/db/db/dbDeepEdges.cc index 5ed7bfb46..d9c3fe21c 100644 --- a/src/db/db/dbDeepEdges.cc +++ b/src/db/db/dbDeepEdges.cc @@ -96,14 +96,16 @@ private: // DeepEdges implementation DeepEdges::DeepEdges (const RecursiveShapeIterator &si, DeepShapeStore &dss, bool as_edges) - : AsIfFlatEdges (), m_deep_layer (dss.create_edge_layer (si, as_edges)), m_merged_edges () + : AsIfFlatEdges (), m_merged_edges () { + set_deep_layer (dss.create_edge_layer (si, as_edges)); init (); } DeepEdges::DeepEdges (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans, bool as_edges, bool merged_semantics) - : AsIfFlatEdges (), m_deep_layer (dss.create_edge_layer (si, as_edges, trans)), m_merged_edges () + : AsIfFlatEdges (), m_merged_edges () { + set_deep_layer (dss.create_edge_layer (si, as_edges, trans)); init (); set_merged_semantics (merged_semantics); } @@ -111,7 +113,7 @@ DeepEdges::DeepEdges (const RecursiveShapeIterator &si, DeepShapeStore &dss, con DeepEdges::DeepEdges (const db::Edges &other, DeepShapeStore &dss) : AsIfFlatEdges (), m_merged_edges () { - m_deep_layer = dss.create_from_flat (other); + set_deep_layer (dss.create_from_flat (other)); init (); set_merged_semantics (other.merged_semantics ()); @@ -124,8 +126,9 @@ DeepEdges::DeepEdges () } DeepEdges::DeepEdges (const DeepLayer &dl) - : AsIfFlatEdges (), m_deep_layer (dl) + : AsIfFlatEdges () { + set_deep_layer (dl); init (); } @@ -135,8 +138,7 @@ DeepEdges::~DeepEdges () } DeepEdges::DeepEdges (const DeepEdges &other) - : AsIfFlatEdges (other), - m_deep_layer (other.m_deep_layer.copy ()), + : AsIfFlatEdges (other), DeepShapeCollectionDelegateBase (other), m_merged_edges_valid (other.m_merged_edges_valid), m_is_merged (other.m_is_merged) { @@ -151,8 +153,8 @@ DeepEdges::operator= (const DeepEdges &other) if (this != &other) { AsIfFlatEdges::operator= (other); + DeepShapeCollectionDelegateBase::operator= (other); - m_deep_layer = other.m_deep_layer.copy (); m_merged_edges_valid = other.m_merged_edges_valid; m_is_merged = other.m_is_merged; if (m_merged_edges_valid) { @@ -201,7 +203,7 @@ DeepEdges::begin_merged () const std::pair DeepEdges::begin_iter () const { - const db::Layout &layout = m_deep_layer.layout (); + const db::Layout &layout = deep_layer ().layout (); if (layout.cells () == 0) { return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ()); @@ -209,7 +211,7 @@ DeepEdges::begin_iter () const } else { const db::Cell &top_cell = layout.cell (*layout.begin_top_down ()); - db::RecursiveShapeIterator iter (m_deep_layer.layout (), top_cell, m_deep_layer.layer ()); + db::RecursiveShapeIterator iter (deep_layer ().layout (), top_cell, deep_layer ().layer ()); return std::make_pair (iter, db::ICplxTrans ()); } @@ -281,8 +283,8 @@ DeepEdges::iter () const bool DeepEdges::equals (const Edges &other) const { const DeepEdges *other_delegate = dynamic_cast (other.delegate ()); - if (other_delegate && &other_delegate->m_deep_layer.layout () == &m_deep_layer.layout () - && other_delegate->m_deep_layer.layer () == m_deep_layer.layer ()) { + if (other_delegate && &other_delegate->deep_layer ().layout () == &deep_layer ().layout () + && other_delegate->deep_layer ().layer () == deep_layer ().layer ()) { return true; } else { return AsIfFlatEdges::equals (other); @@ -292,8 +294,8 @@ bool DeepEdges::equals (const Edges &other) const bool DeepEdges::less (const Edges &other) const { const DeepEdges *other_delegate = dynamic_cast (other.delegate ()); - if (other_delegate && &other_delegate->m_deep_layer.layout () == &m_deep_layer.layout ()) { - return other_delegate->m_deep_layer.layer () < m_deep_layer.layer (); + if (other_delegate && &other_delegate->deep_layer ().layout () == &deep_layer ().layout ()) { + return other_delegate->deep_layer ().layer () < deep_layer ().layer (); } else { return AsIfFlatEdges::less (other); } @@ -403,27 +405,27 @@ DeepEdges::ensure_merged_edges_valid () const if (m_is_merged) { // NOTE: this will reuse the deep layer reference - m_merged_edges = m_deep_layer; + m_merged_edges = deep_layer (); } else { - m_merged_edges = m_deep_layer.derived (); + m_merged_edges = deep_layer ().derived (); tl::SelfTimer timer (tl::verbosity () > base_verbosity (), "Ensure merged polygons"); - db::Layout &layout = const_cast (m_deep_layer.layout ()); + db::Layout &layout = const_cast (deep_layer ().layout ()); db::hier_clusters hc; db::Connectivity conn; - conn.connect (m_deep_layer); + conn.connect (deep_layer ()); hc.set_base_verbosity (base_verbosity() + 10); - hc.build (layout, m_deep_layer.initial_cell (), conn); + hc.build (layout, deep_layer ().initial_cell (), conn); // collect the clusters and merge them into big polygons // NOTE: using the ClusterMerger we merge bottom-up forming bigger and bigger polygons. This is // hopefully more efficient that collecting everything and will lead to reuse of parts. - ClusterMerger cm (m_deep_layer.layer (), hc, report_progress (), progress_desc ()); + ClusterMerger cm (deep_layer ().layer (), hc, report_progress (), progress_desc ()); cm.set_base_verbosity (base_verbosity () + 10); // TODO: iterate only over the called cells? @@ -455,17 +457,17 @@ DeepEdges::set_is_merged (bool f) void DeepEdges::insert_into (db::Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const { - m_deep_layer.insert_into (layout, into_cell, into_layer); + deep_layer ().insert_into (layout, into_cell, into_layer); } size_t DeepEdges::size () const { size_t n = 0; - const db::Layout &layout = m_deep_layer.layout (); + const db::Layout &layout = deep_layer ().layout (); db::CellCounter cc (&layout); for (db::Layout::top_down_const_iterator c = layout.begin_top_down (); c != layout.end_top_down (); ++c) { - n += cc.weight (*c) * layout.cell (*c).shapes (m_deep_layer.layer ()).size (); + n += cc.weight (*c) * layout.cell (*c).shapes (deep_layer ().layer ()).size (); } return n; @@ -473,7 +475,7 @@ size_t DeepEdges::size () const Box DeepEdges::bbox () const { - return m_deep_layer.initial_cell ().bbox (m_deep_layer.layer ()); + return deep_layer ().initial_cell ().bbox (deep_layer ().layer ()); } DeepEdges::length_type DeepEdges::length (const db::Box &box) const @@ -756,7 +758,7 @@ EdgesDelegate *DeepEdges::merged_in_place () ensure_merged_edges_valid (); // NOTE: this makes both layers share the same resource - m_deep_layer = m_merged_edges; + set_deep_layer (m_merged_edges); return this; } @@ -779,17 +781,17 @@ EdgesDelegate *DeepEdges::merged () const DeepLayer DeepEdges::and_or_not_with (const DeepEdges *other, EdgeBoolOp op) const { - DeepLayer dl_out (m_deep_layer.derived ()); + DeepLayer dl_out (deep_layer ().derived ()); db::EdgeBoolAndOrNotLocalOperation local_op (op); - db::local_processor proc (const_cast (&m_deep_layer.layout ()), const_cast (&m_deep_layer.initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell ()); + db::local_processor proc (const_cast (&deep_layer ().layout ()), const_cast (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell ()); proc.set_base_verbosity (base_verbosity ()); - proc.set_threads (m_deep_layer.store ()->threads ()); - proc.set_area_ratio (m_deep_layer.store ()->max_area_ratio ()); - proc.set_max_vertex_count (m_deep_layer.store ()->max_vertex_count ()); + proc.set_threads (deep_layer ().store ()->threads ()); + proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ()); + proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ()); - proc.run (&local_op, m_deep_layer.layer (), other->deep_layer ().layer (), dl_out.layer ()); + proc.run (&local_op, deep_layer ().layer (), other->deep_layer ().layer (), dl_out.layer ()); return dl_out; } @@ -797,17 +799,17 @@ DeepEdges::and_or_not_with (const DeepEdges *other, EdgeBoolOp op) const DeepLayer DeepEdges::edge_region_op (const DeepRegion *other, bool outside, bool include_borders) const { - DeepLayer dl_out (m_deep_layer.derived ()); + DeepLayer dl_out (deep_layer ().derived ()); db::EdgeToPolygonLocalOperation op (outside, include_borders); - db::local_processor proc (const_cast (&m_deep_layer.layout ()), const_cast (&m_deep_layer.initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell ()); + db::local_processor proc (const_cast (&deep_layer ().layout ()), const_cast (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell ()); proc.set_base_verbosity (base_verbosity ()); - proc.set_threads (m_deep_layer.store ()->threads ()); - proc.set_area_ratio (m_deep_layer.store ()->max_area_ratio ()); - proc.set_max_vertex_count (m_deep_layer.store ()->max_vertex_count ()); + proc.set_threads (deep_layer ().store ()->threads ()); + proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ()); + proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ()); - proc.run (&op, m_deep_layer.layer (), other->deep_layer ().layer (), dl_out.layer ()); + proc.run (&op, deep_layer ().layer (), other->deep_layer ().layer (), dl_out.layer ()); return dl_out; } diff --git a/src/db/db/dbDeepEdges.h b/src/db/db/dbDeepEdges.h index 2cfa35e2f..8ed87c971 100644 --- a/src/db/db/dbDeepEdges.h +++ b/src/db/db/dbDeepEdges.h @@ -40,7 +40,7 @@ class DeepRegion; * @brief Provides hierarchical edges implementation */ class DB_PUBLIC DeepEdges - : public db::AsIfFlatEdges + : public db::AsIfFlatEdges, public db::DeepShapeCollectionDelegateBase { public: DeepEdges (); @@ -144,14 +144,9 @@ public: virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const; - const DeepLayer &deep_layer () const + virtual DeepShapeCollectionDelegateBase *deep () { - return m_deep_layer; - } - - DeepLayer &deep_layer () - { - return m_deep_layer; + return this; } protected: @@ -163,7 +158,6 @@ private: DeepEdges &operator= (const DeepEdges &other); - DeepLayer m_deep_layer; mutable DeepLayer m_merged_edges; mutable bool m_merged_edges_valid; bool m_is_merged; diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index dac586f86..e0ba85dc5 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -102,14 +102,16 @@ private: // DeepRegion implementation DeepRegion::DeepRegion (const RecursiveShapeIterator &si, DeepShapeStore &dss, double area_ratio, size_t max_vertex_count) - : AsIfFlatRegion (), m_deep_layer (dss.create_polygon_layer (si, area_ratio, max_vertex_count)), m_merged_polygons () + : AsIfFlatRegion (), m_merged_polygons () { + set_deep_layer (dss.create_polygon_layer (si, area_ratio, max_vertex_count)); init (); } DeepRegion::DeepRegion (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans, bool merged_semantics, double area_ratio, size_t max_vertex_count) - : AsIfFlatRegion (), m_deep_layer (dss.create_polygon_layer (si, area_ratio, max_vertex_count, trans)), m_merged_polygons () + : AsIfFlatRegion (), m_merged_polygons () { + set_deep_layer (dss.create_polygon_layer (si, area_ratio, max_vertex_count, trans)); init (); set_merged_semantics (merged_semantics); } @@ -117,7 +119,7 @@ DeepRegion::DeepRegion (const RecursiveShapeIterator &si, DeepShapeStore &dss, c DeepRegion::DeepRegion (const db::Region &other, DeepShapeStore &dss) : AsIfFlatRegion (), m_merged_polygons () { - m_deep_layer = dss.create_from_flat (other, false); + set_deep_layer (dss.create_from_flat (other, false)); init (); set_merged_semantics (other.merged_semantics ()); @@ -130,8 +132,9 @@ DeepRegion::DeepRegion () } DeepRegion::DeepRegion (const DeepLayer &dl) - : AsIfFlatRegion (), m_deep_layer (dl) + : AsIfFlatRegion () { + set_deep_layer (dl); init (); } @@ -141,8 +144,7 @@ DeepRegion::~DeepRegion () } DeepRegion::DeepRegion (const DeepRegion &other) - : AsIfFlatRegion (other), - m_deep_layer (other.m_deep_layer.copy ()), + : AsIfFlatRegion (other), DeepShapeCollectionDelegateBase (other), m_merged_polygons_valid (other.m_merged_polygons_valid), m_is_merged (other.m_is_merged) { @@ -157,8 +159,8 @@ DeepRegion::operator= (const DeepRegion &other) if (this != &other) { AsIfFlatRegion::operator= (other); + DeepShapeCollectionDelegateBase::operator= (other); - m_deep_layer = other.m_deep_layer.copy (); m_merged_polygons_valid = other.m_merged_polygons_valid; m_is_merged = other.m_is_merged; if (m_merged_polygons_valid) { @@ -212,7 +214,7 @@ DeepRegion::begin_merged () const std::pair DeepRegion::begin_iter () const { - const db::Layout &layout = m_deep_layer.layout (); + const db::Layout &layout = deep_layer ().layout (); if (layout.cells () == 0) { return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ()); @@ -220,7 +222,7 @@ DeepRegion::begin_iter () const } else { const db::Cell &top_cell = layout.cell (*layout.begin_top_down ()); - db::RecursiveShapeIterator iter (m_deep_layer.layout (), top_cell, m_deep_layer.layer ()); + db::RecursiveShapeIterator iter (deep_layer ().layout (), top_cell, deep_layer ().layer ()); return std::make_pair (iter, db::ICplxTrans ()); } @@ -293,8 +295,8 @@ bool DeepRegion::equals (const Region &other) const { const DeepRegion *other_delegate = dynamic_cast (other.delegate ()); - if (other_delegate && &other_delegate->m_deep_layer.layout () == &m_deep_layer.layout () - && other_delegate->m_deep_layer.layer () == m_deep_layer.layer ()) { + if (other_delegate && &other_delegate->deep_layer ().layout () == &deep_layer ().layout () + && other_delegate->deep_layer ().layer () == deep_layer ().layer ()) { return true; } else { return AsIfFlatRegion::equals (other); @@ -305,8 +307,8 @@ bool DeepRegion::less (const Region &other) const { const DeepRegion *other_delegate = dynamic_cast (other.delegate ()); - if (other_delegate && &other_delegate->m_deep_layer.layout () == &m_deep_layer.layout ()) { - return other_delegate->m_deep_layer.layer () < m_deep_layer.layer (); + if (other_delegate && &other_delegate->deep_layer ().layout () == &deep_layer ().layout ()) { + return other_delegate->deep_layer ().layer () < deep_layer ().layer (); } else { return AsIfFlatRegion::less (other); } @@ -441,27 +443,27 @@ DeepRegion::ensure_merged_polygons_valid () const if (m_is_merged) { // NOTE: this will reuse the deep layer reference - m_merged_polygons = m_deep_layer; + m_merged_polygons = deep_layer (); } else { - m_merged_polygons = m_deep_layer.derived (); + m_merged_polygons = deep_layer ().derived (); tl::SelfTimer timer (tl::verbosity () > base_verbosity (), "Ensure merged polygons"); - db::Layout &layout = const_cast (m_deep_layer.layout ()); + db::Layout &layout = const_cast (deep_layer ().layout ()); db::hier_clusters hc; db::Connectivity conn; - conn.connect (m_deep_layer); + conn.connect (deep_layer ()); hc.set_base_verbosity (base_verbosity () + 10); - hc.build (layout, m_deep_layer.initial_cell (), conn); + hc.build (layout, deep_layer ().initial_cell (), conn); // collect the clusters and merge them into big polygons // NOTE: using the ClusterMerger we merge bottom-up forming bigger and bigger polygons. This is // hopefully more efficient that collecting everything and will lead to reuse of parts. - ClusterMerger cm (m_deep_layer.layer (), layout, hc, min_coherence (), report_progress (), progress_desc ()); + ClusterMerger cm (deep_layer ().layer (), layout, hc, min_coherence (), report_progress (), progress_desc ()); cm.set_base_verbosity (base_verbosity () + 10); // TODO: iterate only over the called cells? @@ -493,7 +495,7 @@ DeepRegion::set_is_merged (bool f) void DeepRegion::insert_into (db::Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const { - m_deep_layer.insert_into (layout, into_cell, into_layer); + deep_layer ().insert_into (layout, into_cell, into_layer); } RegionDelegate * @@ -543,17 +545,17 @@ DeepRegion::not_with (const Region &other) const DeepLayer DeepRegion::and_or_not_with (const DeepRegion *other, bool and_op) const { - DeepLayer dl_out (m_deep_layer.derived ()); + DeepLayer dl_out (deep_layer ().derived ()); db::BoolAndOrNotLocalOperation op (and_op); - db::local_processor proc (const_cast (&m_deep_layer.layout ()), const_cast (&m_deep_layer.initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), m_deep_layer.breakout_cells (), other->deep_layer ().breakout_cells ()); + db::local_processor proc (const_cast (&deep_layer ().layout ()), const_cast (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), deep_layer ().breakout_cells (), other->deep_layer ().breakout_cells ()); proc.set_base_verbosity (base_verbosity ()); - proc.set_threads (m_deep_layer.store ()->threads ()); - proc.set_area_ratio (m_deep_layer.store ()->max_area_ratio ()); - proc.set_max_vertex_count (m_deep_layer.store ()->max_vertex_count ()); + proc.set_threads (deep_layer ().store ()->threads ()); + proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ()); + proc.set_max_vertex_count (deep_layer ().store ()->max_vertex_count ()); - proc.run (&op, m_deep_layer.layer (), other->deep_layer ().layer (), dl_out.layer ()); + proc.run (&op, deep_layer ().layer (), other->deep_layer ().layer (), dl_out.layer ()); return dl_out; } @@ -668,10 +670,10 @@ DeepRegion::size () const { size_t n = 0; - const db::Layout &layout = m_deep_layer.layout (); + const db::Layout &layout = deep_layer ().layout (); db::CellCounter cc (&layout); for (db::Layout::top_down_const_iterator c = layout.begin_top_down (); c != layout.end_top_down (); ++c) { - n += cc.weight (*c) * layout.cell (*c).shapes (m_deep_layer.layer ()).size (); + n += cc.weight (*c) * layout.cell (*c).shapes (deep_layer ().layer ()).size (); } return n; @@ -746,7 +748,7 @@ DeepRegion::perimeter (const db::Box &box) const Box DeepRegion::bbox () const { - return m_deep_layer.initial_cell ().bbox (m_deep_layer.layer ()); + return deep_layer ().initial_cell ().bbox (deep_layer ().layer ()); } std::string @@ -1197,7 +1199,7 @@ DeepRegion::merged_in_place () ensure_merged_polygons_valid (); // NOTE: this makes both layers share the same resource - m_deep_layer = m_merged_polygons; + set_deep_layer (m_merged_polygons); set_is_merged (true); return this; @@ -1232,21 +1234,21 @@ DeepRegion::merged (bool min_coherence, unsigned int min_wc) const { tl::SelfTimer timer (tl::verbosity () > base_verbosity (), "Ensure merged polygons"); - db::Layout &layout = const_cast (m_deep_layer.layout ()); + db::Layout &layout = const_cast (deep_layer ().layout ()); db::hier_clusters hc; db::Connectivity conn; - conn.connect (m_deep_layer); + conn.connect (deep_layer ()); hc.set_base_verbosity (base_verbosity () + 10); - hc.build (layout, m_deep_layer.initial_cell (), conn); + hc.build (layout, deep_layer ().initial_cell (), conn); // collect the clusters and merge them into big polygons // NOTE: using the ClusterMerger we merge bottom-up forming bigger and bigger polygons. This is // hopefully more efficient that collecting everything and will lead to reuse of parts. - DeepLayer dl_out (m_deep_layer.derived ()); + DeepLayer dl_out (deep_layer ().derived ()); - ClusterMerger cm (m_deep_layer.layer (), layout, hc, min_coherence, report_progress (), progress_desc ()); + ClusterMerger cm (deep_layer ().layer (), layout, hc, min_coherence, report_progress (), progress_desc ()); cm.set_base_verbosity (base_verbosity () + 10); for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { @@ -1529,7 +1531,7 @@ DeepRegion::run_check (db::edge_relation_type rel, bool different_polygons, cons const_cast (&polygons.initial_cell ()), other_deep ? &other_deep->deep_layer ().layout () : const_cast (&polygons.layout ()), other_deep ? &other_deep->deep_layer ().initial_cell () : const_cast (&polygons.initial_cell ()), - m_deep_layer.breakout_cells (), + deep_layer ().breakout_cells (), other_deep ? other_deep->deep_layer ().breakout_cells () : 0); proc.set_base_verbosity (base_verbosity ()); diff --git a/src/db/db/dbDeepRegion.h b/src/db/db/dbDeepRegion.h index bf794ec48..28dcdf0f8 100644 --- a/src/db/db/dbDeepRegion.h +++ b/src/db/db/dbDeepRegion.h @@ -35,7 +35,7 @@ namespace db { * @brief A deep, polygon-set delegate */ class DB_PUBLIC DeepRegion - : public AsIfFlatRegion + : public AsIfFlatRegion, public DeepShapeCollectionDelegateBase { public: typedef db::layer polygon_layer_type; @@ -159,14 +159,9 @@ public: virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const; - const DeepLayer &deep_layer () const + virtual DeepShapeCollectionDelegateBase *deep () { - return m_deep_layer; - } - - DeepLayer &deep_layer () - { - return m_deep_layer; + return this; } protected: @@ -180,7 +175,6 @@ private: DeepRegion &operator= (const DeepRegion &other); - DeepLayer m_deep_layer; mutable DeepLayer m_merged_polygons; mutable bool m_merged_polygons_valid; bool m_is_merged; diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index 72e5528a8..a2e11a840 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -32,6 +32,7 @@ #include "dbDeepEdges.h" #include "dbDeepEdgePairs.h" #include "dbDeepTexts.h" +#include "dbShapeCollection.h" #include "tlTimer.h" @@ -519,9 +520,9 @@ DeepLayer DeepShapeStore::create_from_flat (const db::Texts &texts, const db::IC return dl; } -std::pair DeepShapeStore::layer_for_flat (const db::Region ®ion) const +std::pair DeepShapeStore::layer_for_flat (const ShapeCollection &coll) const { - return layer_for_flat (tl::id_of (region.delegate ())); + return layer_for_flat (tl::id_of (coll.get_delegate ())); } std::pair DeepShapeStore::layer_for_flat (size_t region_id) const diff --git a/src/db/db/dbDeepShapeStore.h b/src/db/db/dbDeepShapeStore.h index 981bf5259..9e6d30dad 100644 --- a/src/db/db/dbDeepShapeStore.h +++ b/src/db/db/dbDeepShapeStore.h @@ -45,6 +45,7 @@ class Region; class Edges; class EdgePairs; class Texts; +class ShapeCollection; /** * @brief Represents a shape collection from the deep shape store @@ -372,12 +373,12 @@ public: DeepLayer create_from_flat (const db::Texts &texts, const db::ICplxTrans &trans = db::ICplxTrans ()); /** - * @brief Gets the layer for a given flat region. + * @brief Gets the layer for a given flat collection (Region, Edges, Texts, EdgePairs) * * If a layer has been created for a flat region with create_from_flat, it can be retrieved with this method. * The first return value is true in this case. */ - std::pair layer_for_flat (const db::Region ®ion) const; + std::pair layer_for_flat (const ShapeCollection &coll) const; /** * @brief Same as layer_for_flat, but takes a region Id diff --git a/src/db/db/dbDeepTexts.cc b/src/db/db/dbDeepTexts.cc index 5165de7f2..50f6e2623 100644 --- a/src/db/db/dbDeepTexts.cc +++ b/src/db/db/dbDeepTexts.cc @@ -91,7 +91,7 @@ private: DeepTexts::DeepTexts () - : AsIfFlatTexts (), m_deep_layer () + : AsIfFlatTexts () { // .. nothing yet .. } @@ -99,24 +99,23 @@ DeepTexts::DeepTexts () DeepTexts::DeepTexts (const db::Texts &other, DeepShapeStore &dss) : AsIfFlatTexts () { - m_deep_layer = dss.create_from_flat (other); + set_deep_layer (dss.create_from_flat (other)); } DeepTexts::DeepTexts (const RecursiveShapeIterator &si, DeepShapeStore &dss) - : AsIfFlatTexts (), m_deep_layer (dss.create_text_layer (si)) + : AsIfFlatTexts () { - // .. nothing yet .. + set_deep_layer (dss.create_text_layer (si)); } DeepTexts::DeepTexts (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans) - : AsIfFlatTexts (), m_deep_layer (dss.create_text_layer (si, trans)) + : AsIfFlatTexts () { - // .. nothing yet .. + set_deep_layer (dss.create_text_layer (si, trans)); } DeepTexts::DeepTexts (const DeepTexts &other) - : AsIfFlatTexts (other), - m_deep_layer (other.m_deep_layer.copy ()) + : AsIfFlatTexts (other), DeepShapeCollectionDelegateBase (other) { // .. nothing yet .. } @@ -126,15 +125,15 @@ DeepTexts::operator= (const DeepTexts &other) { if (this != &other) { AsIfFlatTexts::operator= (other); - m_deep_layer = other.m_deep_layer.copy (); + DeepShapeCollectionDelegateBase::operator= (other); } return *this; } DeepTexts::DeepTexts (const DeepLayer &dl) - : AsIfFlatTexts (), m_deep_layer (dl) + : AsIfFlatTexts () { - // .. nothing yet .. + set_deep_layer (dl); } DeepTexts::~DeepTexts () @@ -154,7 +153,7 @@ TextsIteratorDelegate *DeepTexts::begin () const std::pair DeepTexts::begin_iter () const { - const db::Layout &layout = m_deep_layer.layout (); + const db::Layout &layout = deep_layer ().layout (); if (layout.cells () == 0) { return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ()); @@ -162,7 +161,7 @@ std::pair DeepTexts::begin_iter () c } else { const db::Cell &top_cell = layout.cell (*layout.begin_top_down ()); - db::RecursiveShapeIterator iter (m_deep_layer.layout (), top_cell, m_deep_layer.layer ()); + db::RecursiveShapeIterator iter (deep_layer ().layout (), top_cell, deep_layer ().layer ()); return std::make_pair (iter, db::ICplxTrans ()); } @@ -172,10 +171,10 @@ size_t DeepTexts::size () const { size_t n = 0; - const db::Layout &layout = m_deep_layer.layout (); + const db::Layout &layout = deep_layer ().layout (); db::CellCounter cc (&layout); for (db::Layout::top_down_const_iterator c = layout.begin_top_down (); c != layout.end_top_down (); ++c) { - n += cc.weight (*c) * layout.cell (*c).shapes (m_deep_layer.layer ()).size (); + n += cc.weight (*c) * layout.cell (*c).shapes (deep_layer ().layer ()).size (); } return n; @@ -188,7 +187,7 @@ std::string DeepTexts::to_string (size_t nmax) const Box DeepTexts::bbox () const { - return m_deep_layer.initial_cell ().bbox (m_deep_layer.layer ()); + return deep_layer ().initial_cell ().bbox (deep_layer ().layer ()); } bool DeepTexts::empty () const @@ -336,12 +335,12 @@ DeepTexts *DeepTexts::apply_filter (const TextFilterBase &filter) const RegionDelegate *DeepTexts::polygons (db::Coord e) const { - db::DeepLayer new_layer = m_deep_layer.derived (); - db::Layout &layout = const_cast (m_deep_layer.layout ()); + db::DeepLayer new_layer = deep_layer ().derived (); + db::Layout &layout = const_cast (deep_layer ().layout ()); for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { db::Shapes &output = c->shapes (new_layer.layer ()); - for (db::Shapes::shape_iterator s = c->shapes (m_deep_layer.layer ()).begin (db::ShapeIterator::Texts); ! s.at_end (); ++s) { + for (db::Shapes::shape_iterator s = c->shapes (deep_layer ().layer ()).begin (db::ShapeIterator::Texts); ! s.at_end (); ++s) { db::Box box = s->bbox (); box.enlarge (db::Vector (e, e)); db::Polygon poly (box); @@ -354,12 +353,12 @@ RegionDelegate *DeepTexts::polygons (db::Coord e) const EdgesDelegate *DeepTexts::edges () const { - db::DeepLayer new_layer = m_deep_layer.derived (); - db::Layout &layout = const_cast (m_deep_layer.layout ()); + db::DeepLayer new_layer = deep_layer ().derived (); + db::Layout &layout = const_cast (deep_layer ().layout ()); for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { db::Shapes &output = c->shapes (new_layer.layer ()); - for (db::Shapes::shape_iterator s = c->shapes (m_deep_layer.layer ()).begin (db::ShapeIterator::Texts); ! s.at_end (); ++s) { + for (db::Shapes::shape_iterator s = c->shapes (deep_layer ().layer ()).begin (db::ShapeIterator::Texts); ! s.at_end (); ++s) { db::Box box = s->bbox (); output.insert (db::Edge (box.p1 (), box.p2 ())); } @@ -377,8 +376,8 @@ TextsDelegate *DeepTexts::in (const Texts &other, bool invert) const bool DeepTexts::equals (const Texts &other) const { const DeepTexts *other_delegate = dynamic_cast (other.delegate ()); - if (other_delegate && &other_delegate->m_deep_layer.layout () == &m_deep_layer.layout () - && other_delegate->m_deep_layer.layer () == m_deep_layer.layer ()) { + if (other_delegate && &other_delegate->deep_layer ().layout () == &deep_layer ().layout () + && other_delegate->deep_layer ().layer () == deep_layer ().layer ()) { return true; } else { return AsIfFlatTexts::equals (other); @@ -388,8 +387,8 @@ bool DeepTexts::equals (const Texts &other) const bool DeepTexts::less (const Texts &other) const { const DeepTexts *other_delegate = dynamic_cast (other.delegate ()); - if (other_delegate && &other_delegate->m_deep_layer.layout () == &m_deep_layer.layout ()) { - return other_delegate->m_deep_layer.layer () < m_deep_layer.layer (); + if (other_delegate && &other_delegate->deep_layer ().layout () == &deep_layer ().layout ()) { + return other_delegate->deep_layer ().layer () < deep_layer ().layer (); } else { return AsIfFlatTexts::less (other); } @@ -397,12 +396,12 @@ bool DeepTexts::less (const Texts &other) const void DeepTexts::insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const { - m_deep_layer.insert_into (layout, into_cell, into_layer); + deep_layer ().insert_into (layout, into_cell, into_layer); } void DeepTexts::insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const { - m_deep_layer.insert_into_as_polygons (layout, into_cell, into_layer, enl); + deep_layer ().insert_into_as_polygons (layout, into_cell, into_layer, enl); } namespace { diff --git a/src/db/db/dbDeepTexts.h b/src/db/db/dbDeepTexts.h index ef877be8d..812582b0d 100644 --- a/src/db/db/dbDeepTexts.h +++ b/src/db/db/dbDeepTexts.h @@ -36,7 +36,7 @@ namespace db { * @brief Provides hierarchical edges implementation */ class DB_PUBLIC DeepTexts - : public db::AsIfFlatTexts + : public db::AsIfFlatTexts, public db::DeepShapeCollectionDelegateBase { public: DeepTexts (); @@ -79,21 +79,14 @@ public: virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const; virtual void insert_into_as_polygons (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer, db::Coord enl) const; - const DeepLayer &deep_layer () const + virtual DeepShapeCollectionDelegateBase *deep () { - return m_deep_layer; - } - - DeepLayer &deep_layer () - { - return m_deep_layer; + return this; } private: DeepTexts &operator= (const DeepTexts &other); - DeepLayer m_deep_layer; - void init (); DeepTexts *apply_filter (const TextFilterBase &filter) const; diff --git a/src/db/db/dbEdgePairs.cc b/src/db/db/dbEdgePairs.cc index 5a6c97f4c..fbafdcdff 100644 --- a/src/db/db/dbEdgePairs.cc +++ b/src/db/db/dbEdgePairs.cc @@ -57,7 +57,7 @@ EdgePairs::EdgePairs (EdgePairsDelegate *delegate) } EdgePairs::EdgePairs (const EdgePairs &other) - : gsi::ObjectBase (), mp_delegate (other.mp_delegate->clone ()) + : db::ShapeCollection (), mp_delegate (other.mp_delegate->clone ()) { // .. nothing yet .. } diff --git a/src/db/db/dbEdgePairs.h b/src/db/db/dbEdgePairs.h index 2dac4e52c..07947deaf 100644 --- a/src/db/db/dbEdgePairs.h +++ b/src/db/db/dbEdgePairs.h @@ -27,8 +27,7 @@ #include "dbEdgePairsDelegate.h" #include "dbShape.h" #include "dbRecursiveShapeIterator.h" - -#include "gsiObject.h" +#include "dbShapeCollection.h" #include @@ -230,7 +229,7 @@ public: * can be converted to polygons or to individual edges. */ class DB_PUBLIC EdgePairs - : public gsi::ObjectBase + : public db::ShapeCollection { public: typedef db::Coord coord_type; @@ -339,6 +338,14 @@ public: */ explicit EdgePairs (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans); + /** + * @brief Implementation of the ShapeCollection interface + */ + ShapeCollectionDelegateBase *get_delegate () const + { + return mp_delegate; + } + /** * @brief Gets the underlying delegate object */ diff --git a/src/db/db/dbEdgePairsDelegate.cc b/src/db/db/dbEdgePairsDelegate.cc index d2b93d626..94e78bf38 100644 --- a/src/db/db/dbEdgePairsDelegate.cc +++ b/src/db/db/dbEdgePairsDelegate.cc @@ -34,7 +34,7 @@ EdgePairsDelegate::EdgePairsDelegate () } EdgePairsDelegate::EdgePairsDelegate (const EdgePairsDelegate &other) - : tl::UniqueId () + : ShapeCollectionDelegateBase () { operator= (other); } diff --git a/src/db/db/dbEdgePairsDelegate.h b/src/db/db/dbEdgePairsDelegate.h index 3eeb340ce..0cd9798b6 100644 --- a/src/db/db/dbEdgePairsDelegate.h +++ b/src/db/db/dbEdgePairsDelegate.h @@ -25,9 +25,8 @@ #define HDR_dbEdgePairsDelegate #include "dbCommon.h" - #include "dbEdgePair.h" -#include "tlUniqueId.h" +#include "dbShapeCollection.h" namespace db { @@ -59,7 +58,7 @@ public: * @brief The delegate for the actual edge set implementation */ class DB_PUBLIC EdgePairsDelegate - : public tl::UniqueId + : public ShapeCollectionDelegateBase { public: typedef db::Coord coord_type; diff --git a/src/db/db/dbEdges.cc b/src/db/db/dbEdges.cc index a2b0fbdde..aebcbaf0e 100644 --- a/src/db/db/dbEdges.cc +++ b/src/db/db/dbEdges.cc @@ -97,7 +97,7 @@ Edges::Edges (EdgesDelegate *delegate) } Edges::Edges (const Edges &other) - : gsi::ObjectBase (), mp_delegate (other.mp_delegate->clone ()) + : db::ShapeCollection (), mp_delegate (other.mp_delegate->clone ()) { // .. nothing yet .. } diff --git a/src/db/db/dbEdges.h b/src/db/db/dbEdges.h index c2d304ba0..aa76642db 100644 --- a/src/db/db/dbEdges.h +++ b/src/db/db/dbEdges.h @@ -27,8 +27,7 @@ #include "dbEdgesDelegate.h" #include "dbRecursiveShapeIterator.h" #include "dbCellVariants.h" - -#include "gsiObject.h" +#include "dbShapeCollection.h" #include @@ -215,7 +214,7 @@ class Edges; */ class DB_PUBLIC Edges - : public gsi::ObjectBase + : public db::ShapeCollection { public: typedef db::Coord coord_type; @@ -359,6 +358,14 @@ public: */ explicit Edges (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans, bool as_edges = true, bool merged_semantics = true); + /** + * @brief Implementation of the ShapeCollection interface + */ + ShapeCollectionDelegateBase *get_delegate () const + { + return mp_delegate; + } + /** * @brief Gets the underlying delegate object */ diff --git a/src/db/db/dbEdgesDelegate.cc b/src/db/db/dbEdgesDelegate.cc index ea9c7ff45..982d6350a 100644 --- a/src/db/db/dbEdgesDelegate.cc +++ b/src/db/db/dbEdgesDelegate.cc @@ -37,7 +37,7 @@ EdgesDelegate::EdgesDelegate () } EdgesDelegate::EdgesDelegate (const EdgesDelegate &other) - : tl::UniqueId () + : ShapeCollectionDelegateBase () { operator= (other); } diff --git a/src/db/db/dbEdgesDelegate.h b/src/db/db/dbEdgesDelegate.h index 18213bc58..7b2ff0b18 100644 --- a/src/db/db/dbEdgesDelegate.h +++ b/src/db/db/dbEdgesDelegate.h @@ -29,7 +29,7 @@ #include "dbEdge.h" #include "dbEdgePairs.h" #include "dbEdgePairRelations.h" -#include "tlUniqueId.h" +#include "dbShapeCollection.h" #include @@ -181,7 +181,7 @@ public: * @brief The delegate for the actual edge set implementation */ class DB_PUBLIC EdgesDelegate - : public tl::UniqueId + : public ShapeCollectionDelegateBase { public: typedef db::Coord coord_type; diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index 479e67ed0..0cd059357 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -24,6 +24,7 @@ #include "dbCommon.h" #include "dbLayoutToNetlist.h" #include "dbDeepRegion.h" +#include "dbDeepTexts.h" #include "dbShapeRepository.h" #include "dbCellMapping.h" #include "dbLayoutToNetlistWriter.h" @@ -172,17 +173,17 @@ db::Region *LayoutToNetlist::make_layer (unsigned int layer_index, const std::st return region.release (); } -db::Region *LayoutToNetlist::make_text_layer (unsigned int layer_index, const std::string &n) +db::Texts *LayoutToNetlist::make_text_layer (unsigned int layer_index, const std::string &n) { db::RecursiveShapeIterator si (m_iter); si.set_layer (layer_index); si.shape_flags (db::ShapeIterator::Texts); - std::auto_ptr region (new db::Region (si, dss ())); + std::auto_ptr texts (new db::Texts (si, dss ())); if (! n.empty ()) { - register_layer (*region, n); + register_layer (*texts, n); } - return region.release (); + return texts.release (); } db::Region *LayoutToNetlist::make_polygon_layer (unsigned int layer_index, const std::string &n) @@ -236,7 +237,7 @@ void LayoutToNetlist::ensure_netlist () } } -void LayoutToNetlist::extract_devices (db::NetlistDeviceExtractor &extractor, const std::map &layers) +void LayoutToNetlist::extract_devices (db::NetlistDeviceExtractor &extractor, const std::map &layers) { if (m_netlist_extracted) { throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted"))); @@ -262,7 +263,7 @@ void LayoutToNetlist::connect (const db::Region &l) m_conn.connect (dl.layer ()); } -void LayoutToNetlist::connect (const db::Region &a, const db::Region &b) +void LayoutToNetlist::connect_impl (const db::ShapeCollection &a, const db::ShapeCollection &b) { if (m_netlist_extracted) { throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted"))); @@ -283,7 +284,7 @@ void LayoutToNetlist::connect (const db::Region &a, const db::Region &b) m_conn.connect (dla.layer (), dlb.layer ()); } -size_t LayoutToNetlist::connect_global (const db::Region &l, const std::string &gn) +void LayoutToNetlist::connect_global_impl (const db::ShapeCollection &l, const std::string &gn) { if (m_netlist_extracted) { throw tl::Exception (tl::to_string (tr ("The netlist has already been extracted"))); @@ -296,7 +297,7 @@ size_t LayoutToNetlist::connect_global (const db::Region &l, const std::string & db::DeepLayer dl = deep_layer_of (l); m_dlrefs.insert (dl); - return m_conn.connect_global (dl.layer (), gn); + m_conn.connect_global (dl.layer (), gn); } const std::string &LayoutToNetlist::global_net_name (size_t id) const @@ -393,42 +394,6 @@ void LayoutToNetlist::ensure_layout () const } } -void LayoutToNetlist::register_layer (const db::Region ®ion, const std::string &n) -{ - if (m_named_regions.find (n) != m_named_regions.end ()) { - throw tl::Exception (tl::to_string (tr ("Layer name is already used: ")) + n); - } - - db::DeepLayer dl; - - if (m_is_flat) { - - dl = dss ().create_from_flat (region, true); - - } else { - - db::DeepRegion *delegate = dynamic_cast (region.delegate()); - if (! delegate) { - - dl = dss ().create_from_flat (region, true); - - } else { - - if (is_persisted (region)) { - std::string prev_name = name (region); - m_named_regions.erase (prev_name); - } - - dl = delegate->deep_layer (); - - } - - } - - m_named_regions [n] = dl; - m_name_of_layer [dl.layer ()] = n; -} - std::string LayoutToNetlist::make_new_name (const std::string &stem) { int m = std::numeric_limits::max () / 2 + 1; @@ -452,16 +417,6 @@ std::string LayoutToNetlist::make_new_name (const std::string &stem) return name; } -std::string LayoutToNetlist::name (const db::Region ®ion) const -{ - std::map::const_iterator n = m_name_of_layer.find (layer_of (region)); - if (n != m_name_of_layer.end ()) { - return n->second; - } else { - return std::string (); - } -} - std::string LayoutToNetlist::name (unsigned int l) const { std::map::const_iterator n = m_name_of_layer.find (l); @@ -472,11 +427,6 @@ std::string LayoutToNetlist::name (unsigned int l) const } } -bool LayoutToNetlist::is_persisted (const db::Region ®ion) const -{ - return m_name_of_layer.find (layer_of (region)) != m_name_of_layer.end (); -} - db::Region *LayoutToNetlist::layer_by_name (const std::string &name) { std::map::const_iterator l = m_named_regions.find (name); @@ -497,12 +447,71 @@ db::Region *LayoutToNetlist::layer_by_index (unsigned int index) } } -db::DeepLayer LayoutToNetlist::deep_layer_of (const db::Region ®ion) const +static db::DeepLayer dss_create_from_flat (db::DeepShapeStore &dss, const db::ShapeCollection &coll) { - const db::DeepRegion *dr = dynamic_cast (region.delegate ()); + const db::Region *region = dynamic_cast (&coll); + const db::Texts *texts = dynamic_cast (&coll); + if (region) { + return dss.create_from_flat (*region, true); + } else if (texts) { + return dss.create_from_flat (*texts); + } else { + tl_assert (false); + } +} + +std::string LayoutToNetlist::name (const ShapeCollection &coll) const +{ + std::map::const_iterator n = m_name_of_layer.find (layer_of (coll)); + if (n != m_name_of_layer.end ()) { + return n->second; + } else { + return std::string (); + } +} + +void LayoutToNetlist::register_layer (const ShapeCollection &collection, const std::string &n) +{ + if (m_named_regions.find (n) != m_named_regions.end ()) { + throw tl::Exception (tl::to_string (tr ("Layer name is already used: ")) + n); + } + + db::DeepLayer dl; + + if (m_is_flat) { + + dl = dss_create_from_flat (dss (), collection); + + } else { + + db::DeepShapeCollectionDelegateBase *delegate = collection.get_delegate ()->deep (); + if (! delegate) { + + dl = dss_create_from_flat (dss (), collection); + + } else { + + if (is_persisted (collection)) { + std::string prev_name = name (collection); + m_named_regions.erase (prev_name); + } + + dl = delegate->deep_layer (); + + } + + } + + m_named_regions [n] = dl; + m_name_of_layer [dl.layer ()] = n; +} + +db::DeepLayer LayoutToNetlist::deep_layer_of (const db::ShapeCollection &coll) const +{ + const db::DeepShapeCollectionDelegateBase *dr = coll.get_delegate ()->deep (); if (! dr) { - std::pair lff = dss ().layer_for_flat (region); + std::pair lff = dss ().layer_for_flat (coll); if (lff.first) { return lff.second; } else { @@ -514,11 +523,6 @@ db::DeepLayer LayoutToNetlist::deep_layer_of (const db::Region ®ion) const } } -unsigned int LayoutToNetlist::layer_of (const db::Region ®ion) const -{ - return deep_layer_of (region).layer (); -} - db::CellMapping LayoutToNetlist::make_cell_mapping_into (db::Layout &layout, db::Cell &cell, const std::vector *nets, bool with_device_cells) { std::set device_cells; diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index f92632bd8..a90a9b4e5 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -240,13 +240,13 @@ public: * derived by boolean operations for example. * Named regions are persisted inside the LayoutToNetlist object. */ - void register_layer (const db::Region ®ion, const std::string &name); + void register_layer (const ShapeCollection &collection, const std::string &name); /** - * @brief Gets the name of the given region - * Returns an empty string if the region does not have a name. + * @brief Gets the name of the given collection + * Returns an empty string if the collection does not have a name. */ - std::string name (const db::Region ®ion) const; + std::string name (const ShapeCollection &coll) const; /** * @brief Gets the name of the given layer by index @@ -272,7 +272,11 @@ public: * Persisted regions have a name and are kept inside the LayoutToNetlist * object. */ - bool is_persisted (const db::Region ®ion) const; + template + bool is_persisted (const Collection &coll) const + { + return m_name_of_layer.find (layer_of (coll)) != m_name_of_layer.end (); + } /** * @brief Gets the region (layer) with the given name @@ -329,10 +333,10 @@ public: db::Region *make_layer (unsigned int layer_index, const std::string &name = std::string ()); /** - * @brief Creates a new region representing an original layer taking texts only + * @brief Creates a new text collection representing an original layer taking texts only * See "make_layer" for details. */ - db::Region *make_text_layer (unsigned int layer_index, const std::string &name = std::string ()); + db::Texts *make_text_layer (unsigned int layer_index, const std::string &name = std::string ()); /** * @brief Creates a new region representing an original layer taking polygons and texts @@ -346,13 +350,13 @@ public: * This method will run device extraction for the given extractor. The layer map is specific * for the extractor and uses the region objects derived with "make_layer" and it's variants. * - * In addition, derived regions can be passed too. Certain limitations apply. It's safe to use + * In addition, derived regions/text collections can be passed too. Certain limitations apply. It's safe to use * boolean operations for deriving layers. Other operations are applicable as long as they are * capable of delivering hierarchical layers. * * If errors occur, the device extractor will contain theses errors. */ - void extract_devices (db::NetlistDeviceExtractor &extractor, const std::map &layers); + void extract_devices (db::NetlistDeviceExtractor &extractor, const std::map &layers); /** * @brief Defines an intra-layer connection for the given layer. @@ -367,13 +371,46 @@ public: * @brief Defines an inter-layer connection for the given layers. * The conditions mentioned with intra-layer "connect" apply for this method too. */ - void connect (const db::Region &a, const db::Region &b); + void connect (const db::Region &a, const db::Region &b) + { + connect_impl (a, b); + } + + /** + * @brief Defines an inter-layer connection for the given layers. + * As one layer is a texts layer, this connection will basically add net labels. + */ + void connect (const db::Region &a, const db::Texts &b) + { + connect_impl (a, b); + } + + /** + * @brief Defines an inter-layer connection for the given layers. + * As one layer is a texts layer, this connection will basically add net labels. + */ + void connect (const db::Texts &a, const db::Region &b) + { + connect_impl (b, a); + } /** * @brief Connects the given layer with a global net with the given name * Returns the global net ID */ - size_t connect_global (const db::Region &l, const std::string &gn); + void connect_global (const db::Region &l, const std::string &gn) + { + connect_global_impl (l, gn); + } + + /** + * @brief Connects the given text layer with a global net with the given name + * Returns the global net ID + */ + void connect_global (const db::Texts &l, const std::string &gn) + { + connect_global_impl (l, gn); + } /** * @brief Gets the global net name for a given global net ID @@ -470,7 +507,11 @@ public: * This method is required to derive the internal layer index - for example for * investigating the cluster tree. */ - unsigned int layer_of (const db::Region ®ion) const; + template + unsigned int layer_of (const Collection &coll) const + { + return deep_layer_of (coll).layer (); + } /** * @brief Creates a cell mapping for copying shapes from the internal layout to the given target layout. @@ -790,11 +831,13 @@ private: void build_net_rec (const db::Net &net, db::Layout &target, cell_index_type circuit_cell, const db::CellMapping &cmap, const std::map &lmap, const char *net_cell_name_prefix, db::properties_id_type netname_propid, BuildNetHierarchyMode hier_mode, const char *cell_name_prefix, const char *device_cell_name_prefix, cell_reuse_table_type &reuse_table, const ICplxTrans &tr) const; void build_net_rec (const db::Net &net, db::Layout &target, db::Cell &target_cell, const std::map &lmap, const char *net_cell_name_prefix, db::properties_id_type netname_propid, BuildNetHierarchyMode hier_mode, const char *cell_name_prefix, const char *device_cell_name_prefix, cell_reuse_table_type &reuse_table, const ICplxTrans &tr) const; void build_net_rec (db::cell_index_type ci, size_t cid, db::Layout &target, db::Cell &target_cell, const std::map &lmap, const Net *net, const char *net_cell_name_prefix, db::properties_id_type netname_propid, BuildNetHierarchyMode hier_mode, const char *cell_name_prefix, const char *device_cell_name_prefix, cell_reuse_table_type &reuse_table, const ICplxTrans &tr) const; - db::DeepLayer deep_layer_of (const db::Region ®ion) const; + db::DeepLayer deep_layer_of (const ShapeCollection &coll) const; void ensure_layout () const; std::string make_new_name (const std::string &stem = std::string ()); db::properties_id_type make_netname_propid (db::Layout &ly, const tl::Variant &netname_prop, const db::Net &net) const; db::CellMapping make_cell_mapping_into (db::Layout &layout, db::Cell &cell, const std::vector *nets, bool with_device_cells); + void connect_impl (const db::ShapeCollection &a, const db::ShapeCollection &b); + void connect_global_impl (const db::ShapeCollection &l, const std::string &gn); // implementation of NetlistManipulationCallbacks virtual size_t link_net_to_parent_circuit (const Net *subcircuit_net, Circuit *parent_circuit, const DCplxTrans &trans); diff --git a/src/db/db/dbLayoutToNetlistReader.cc b/src/db/db/dbLayoutToNetlistReader.cc index 877f9842d..f312eefc4 100644 --- a/src/db/db/dbLayoutToNetlistReader.cc +++ b/src/db/db/dbLayoutToNetlistReader.cc @@ -135,7 +135,7 @@ LayoutToNetlistStandardReader::skip () void LayoutToNetlistStandardReader::do_read (db::LayoutToNetlist *l2n) { - tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("File read"))); + tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("File read: ")) + m_path); try { read_netlist (0, l2n); diff --git a/src/db/db/dbNetlistDeviceExtractor.cc b/src/db/db/dbNetlistDeviceExtractor.cc index b022e9f5e..1b5f6f453 100644 --- a/src/db/db/dbNetlistDeviceExtractor.cc +++ b/src/db/db/dbNetlistDeviceExtractor.cc @@ -164,10 +164,10 @@ void NetlistDeviceExtractor::extract (db::DeepShapeStore &dss, unsigned int layo } tl_assert (l->second != 0); - db::DeepRegion *dr = dynamic_cast (l->second->delegate ()); + db::DeepShapeCollectionDelegateBase *dr = l->second->get_delegate ()->deep (); if (dr == 0) { - std::pair alias = dss.layer_for_flat (tl::id_of (l->second->delegate ())); + std::pair alias = dss.layer_for_flat (tl::id_of (l->second->get_delegate ())); if (alias.first) { // use deep layer alias for a given flat one (if found) layers.push_back (alias.second.layer ()); diff --git a/src/db/db/dbNetlistDeviceExtractor.h b/src/db/db/dbNetlistDeviceExtractor.h index 2cfc3c40e..862f355f7 100644 --- a/src/db/db/dbNetlistDeviceExtractor.h +++ b/src/db/db/dbNetlistDeviceExtractor.h @@ -205,7 +205,7 @@ public: typedef error_list::const_iterator error_iterator; typedef std::vector layer_definitions; typedef layer_definitions::const_iterator layer_definitions_iterator; - typedef std::map input_layers; + typedef std::map input_layers; typedef db::hier_clusters hier_clusters_type; /** diff --git a/src/db/db/dbRegion.cc b/src/db/db/dbRegion.cc index 2064fee71..08dfc495c 100644 --- a/src/db/db/dbRegion.cc +++ b/src/db/db/dbRegion.cc @@ -193,7 +193,7 @@ Region::Region (RegionDelegate *delegate) } Region::Region (const Region &other) - : gsi::ObjectBase (), mp_delegate (other.mp_delegate->clone ()) + : db::ShapeCollection (), mp_delegate (other.mp_delegate->clone ()) { // .. nothing yet .. } diff --git a/src/db/db/dbRegion.h b/src/db/db/dbRegion.h index f3f8bf576..0bc2b47fa 100644 --- a/src/db/db/dbRegion.h +++ b/src/db/db/dbRegion.h @@ -29,8 +29,7 @@ #include "dbRecursiveShapeIterator.h" #include "dbPolygonGenerators.h" #include "dbCellVariants.h" - -#include "gsiObject.h" +#include "dbShapeCollection.h" #include @@ -216,7 +215,7 @@ private: * Polygons inside the region may contain holes if the region is merged. */ class DB_PUBLIC Region - : public gsi::ObjectBase + : public db::ShapeCollection { public: typedef db::Coord coord_type; @@ -351,6 +350,14 @@ public: */ explicit Region (DeepShapeStore &dss); + /** + * @brief Implementation of the ShapeCollection interface + */ + ShapeCollectionDelegateBase *get_delegate () const + { + return mp_delegate; + } + /** * @brief Gets the underlying delegate object */ diff --git a/src/db/db/dbRegionDelegate.cc b/src/db/db/dbRegionDelegate.cc index b52bbc06b..1341a58e7 100644 --- a/src/db/db/dbRegionDelegate.cc +++ b/src/db/db/dbRegionDelegate.cc @@ -38,7 +38,7 @@ RegionDelegate::RegionDelegate () } RegionDelegate::RegionDelegate (const RegionDelegate &other) - : tl::UniqueId () + : ShapeCollectionDelegateBase () { operator= (other); } diff --git a/src/db/db/dbRegionDelegate.h b/src/db/db/dbRegionDelegate.h index f38e25688..562f08ca7 100644 --- a/src/db/db/dbRegionDelegate.h +++ b/src/db/db/dbRegionDelegate.h @@ -31,7 +31,7 @@ #include "dbTexts.h" #include "dbEdgePairs.h" #include "dbEdgePairRelations.h" -#include "tlUniqueId.h" +#include "dbShapeCollection.h" #include @@ -183,7 +183,7 @@ public: * @brief The delegate for the actual region implementation */ class DB_PUBLIC RegionDelegate - : public tl::UniqueId + : public db::ShapeCollectionDelegateBase { public: typedef db::Coord coord_type; diff --git a/src/db/db/dbShapeCollection.cc b/src/db/db/dbShapeCollection.cc new file mode 100644 index 000000000..e69de29bb diff --git a/src/db/db/dbShapeCollection.h b/src/db/db/dbShapeCollection.h new file mode 100644 index 000000000..4e014e1e9 --- /dev/null +++ b/src/db/db/dbShapeCollection.h @@ -0,0 +1,115 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 + +*/ + +#ifndef _HDR_dbShapeCollection +#define _HDR_dbShapeCollection + +#include "dbCommon.h" +#include "dbDeepShapeStore.h" +#include "tlUniqueId.h" +#include "gsiObject.h" + +namespace db +{ + +/** + * @brief A base class for the deep collection delegates + */ +class DB_PUBLIC DeepShapeCollectionDelegateBase +{ +public: + DeepShapeCollectionDelegateBase () { } + + DeepShapeCollectionDelegateBase (const DeepShapeCollectionDelegateBase &other) + { + m_deep_layer = other.m_deep_layer.copy (); + } + + DeepShapeCollectionDelegateBase &operator= (const DeepShapeCollectionDelegateBase &other) + { + if (this != &other) { + m_deep_layer = other.m_deep_layer.copy (); + } + return *this; + } + + const db::DeepLayer &deep_layer () const + { + return m_deep_layer; + } + + db::DeepLayer &deep_layer () + { + return m_deep_layer; + } + +protected: + virtual void set_deep_layer (const db::DeepLayer &dl) + { + m_deep_layer = dl; + } + +private: + db::DeepLayer m_deep_layer; +}; + +/** + * @brief A base class for the shape collection delegates + */ +class DB_PUBLIC ShapeCollectionDelegateBase + : public tl::UniqueId +{ +public: + ShapeCollectionDelegateBase () { } + virtual ~ShapeCollectionDelegateBase () { } + + virtual DeepShapeCollectionDelegateBase *deep () { return 0; } +}; + +/** + * @brief A base class for the shape collections such as Region, Edges, EdgePairs etc. + */ +class DB_PUBLIC ShapeCollection + : public gsi::ObjectBase +{ +public: + ShapeCollection () { } + virtual ~ShapeCollection () { } + + virtual ShapeCollectionDelegateBase *get_delegate () const = 0; +}; + +} + +namespace tl +{ + +template<> struct type_traits : public tl::type_traits +{ + // mark "NetlistDeviceExtractor" as having a default ctor and no copy ctor + typedef tl::false_tag has_copy_constructor; + typedef tl::false_tag has_default_constructor; +}; + +} + +#endif diff --git a/src/db/db/dbTexts.cc b/src/db/db/dbTexts.cc index 7683633d5..6d1fbc5fd 100644 --- a/src/db/db/dbTexts.cc +++ b/src/db/db/dbTexts.cc @@ -57,7 +57,7 @@ Texts::Texts (TextsDelegate *delegate) } Texts::Texts (const Texts &other) - : gsi::ObjectBase (), mp_delegate (other.mp_delegate->clone ()) + : db::ShapeCollection (), mp_delegate (other.mp_delegate->clone ()) { // .. nothing yet .. } diff --git a/src/db/db/dbTexts.h b/src/db/db/dbTexts.h index e087b3432..35ce50c05 100644 --- a/src/db/db/dbTexts.h +++ b/src/db/db/dbTexts.h @@ -27,8 +27,7 @@ #include "dbTextsDelegate.h" #include "dbShape.h" #include "dbRecursiveShapeIterator.h" - -#include "gsiObject.h" +#include "dbShapeCollection.h" #include @@ -228,7 +227,7 @@ public: * edges representing the point of the text. */ class DB_PUBLIC Texts - : public gsi::ObjectBase + : public db::ShapeCollection { public: typedef db::Coord coord_type; @@ -337,6 +336,14 @@ public: */ explicit Texts (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans); + /** + * @brief Implementation of the ShapeCollection interface + */ + ShapeCollectionDelegateBase *get_delegate () const + { + return mp_delegate; + } + /** * @brief Gets the underlying delegate object */ diff --git a/src/db/db/dbTextsDelegate.cc b/src/db/db/dbTextsDelegate.cc index 0691920f4..00b49181c 100644 --- a/src/db/db/dbTextsDelegate.cc +++ b/src/db/db/dbTextsDelegate.cc @@ -34,7 +34,7 @@ TextsDelegate::TextsDelegate () } TextsDelegate::TextsDelegate (const TextsDelegate &other) - : tl::UniqueId () + : db::ShapeCollectionDelegateBase () { operator= (other); } diff --git a/src/db/db/dbTextsDelegate.h b/src/db/db/dbTextsDelegate.h index 29f9a2c72..551f91389 100644 --- a/src/db/db/dbTextsDelegate.h +++ b/src/db/db/dbTextsDelegate.h @@ -25,9 +25,8 @@ #define HDR_dbTextsDelegate #include "dbCommon.h" - +#include "dbShapeCollection.h" #include "dbText.h" -#include "tlUniqueId.h" namespace db { @@ -60,7 +59,7 @@ public: * @brief The delegate for the actual edge set implementation */ class DB_PUBLIC TextsDelegate - : public tl::UniqueId + : public ShapeCollectionDelegateBase { public: typedef db::Coord coord_type; diff --git a/src/db/db/gsiDeclDbEdgePairs.cc b/src/db/db/gsiDeclDbEdgePairs.cc index 129539f21..c3d51f2a6 100644 --- a/src/db/db/gsiDeclDbEdgePairs.cc +++ b/src/db/db/gsiDeclDbEdgePairs.cc @@ -179,7 +179,9 @@ static size_t id (const db::EdgePairs *ep) return tl::id_of (ep->delegate ()); } -Class decl_EdgePairs ("db", "EdgePairs", +extern Class decl_dbShapeCollection; + +Class decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs", constructor ("new", &new_v, "@brief Default constructor\n" "\n" diff --git a/src/db/db/gsiDeclDbEdges.cc b/src/db/db/gsiDeclDbEdges.cc index 0eaf6dcff..6563e9c55 100644 --- a/src/db/db/gsiDeclDbEdges.cc +++ b/src/db/db/gsiDeclDbEdges.cc @@ -412,7 +412,9 @@ static size_t id (const db::Edges *e) return tl::id_of (e->delegate ()); } -Class dec_Edges ("db", "Edges", +extern Class decl_dbShapeCollection; + +Class dec_Edges (decl_dbShapeCollection, "db", "Edges", constructor ("new", &new_v, "@brief Default constructor\n" "\n" diff --git a/src/db/db/gsiDeclDbLayoutToNetlist.cc b/src/db/db/gsiDeclDbLayoutToNetlist.cc index 248137836..66818ebdb 100644 --- a/src/db/db/gsiDeclDbLayoutToNetlist.cc +++ b/src/db/db/gsiDeclDbLayoutToNetlist.cc @@ -237,7 +237,7 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", gsi::method ("original_file=", &db::LayoutToNetlist::set_original_file, "@brief Sets the original file name of the database\n" ) + - gsi::method ("layer_name", (std::string (db::LayoutToNetlist::*) (const db::Region ®ion) const) &db::LayoutToNetlist::name, gsi::arg ("l"), + gsi::method ("layer_name", (std::string (db::LayoutToNetlist::*) (const db::ShapeCollection ®ion) const) &db::LayoutToNetlist::name, gsi::arg ("l"), "@brief Gets the name of the given layer\n" ) + gsi::method ("layer_name", (std::string (db::LayoutToNetlist::*) (unsigned int) const) &db::LayoutToNetlist::name, gsi::arg ("l"), @@ -254,6 +254,13 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", "\n" "If required, the system will assign a name automatically." ) + + gsi::method ("register", (void (db::LayoutToNetlist::*) (const db::Texts &texts, const std::string &)) &db::LayoutToNetlist::register_layer, gsi::arg ("l"), gsi::arg ("n"), + "@brief Names the given layer\n" + "This method behaves like the one provided for Regions but accepts Texts. " + "Texts (hierarchical text collections) are useful to represent labels for naming nets.\n" + "\n" + "This variant has been introduced in version 0.27.\n" + ) + gsi::method_ext ("layer_names", &l2n_layer_names, "@brief Returns a list of names of the layer kept inside the LayoutToNetlist object." ) + @@ -266,12 +273,20 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", "Only named layers can be retrieved with this method. " "The returned object is a copy which represents the named layer." ) + - gsi::method ("is_persisted?", &db::LayoutToNetlist::is_persisted, gsi::arg ("layer"), + gsi::method ("is_persisted?", &db::LayoutToNetlist::is_persisted, gsi::arg ("layer"), "@brief Returns true, if the given layer is a persisted region.\n" "Persisted layers are kept inside the LayoutToNetlist object and are not released " "if their object is destroyed. Named layers are persisted, unnamed layers are not. " "Only persisted, named layers can be put into \\connect." ) + + gsi::method ("is_persisted?", &db::LayoutToNetlist::is_persisted, gsi::arg ("layer"), + "@brief Returns true, if the given layer is a persisted texts collection.\n" + "Persisted layers are kept inside the LayoutToNetlist object and are not released " + "if their object is destroyed. Named layers are persisted, unnamed layers are not. " + "Only persisted, named layers can be put into \\connect.\n" + "\n" + "The variant for Texts collections has been added in version 0.27." + ) + gsi::factory ("make_layer", (db::Region *(db::LayoutToNetlist::*) (const std::string &)) &db::LayoutToNetlist::make_layer, gsi::arg ("name", std::string ()), "@brief Creates a new, empty hierarchical region\n" "\n" @@ -291,6 +306,8 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", "See \\make_layer for details.\n" "\n" "The name is optional. If given, the layer will already be named accordingly (see \\register).\n" + "\n" + "Starting with version 0.27, this method returns a \\Texts object." ) + gsi::factory ("make_polygon_layer", &db::LayoutToNetlist::make_polygon_layer, gsi::arg ("layer_index"), gsi::arg ("name", std::string ()), "@brief Creates a new region representing an original layer taking polygons and texts\n" @@ -321,11 +338,32 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", "@brief Defines an inter-layer connection for the given layers.\n" "The conditions mentioned with intra-layer \\connect apply for this method too.\n" ) + + gsi::method ("connect", (void (db::LayoutToNetlist::*) (const db::Region &, const db::Texts &)) &db::LayoutToNetlist::connect, gsi::arg ("a"), gsi::arg ("b"), + "@brief Defines an inter-layer connection for the given layers.\n" + "The conditions mentioned with intra-layer \\connect apply for this method too.\n" + "As one argument is a (hierarchical) text collection, this method is used to attach net labels to polygons.\n" + "\n" + "This variant has been introduced in version 0.27.\n" + ) + + gsi::method ("connect", (void (db::LayoutToNetlist::*) (const db::Texts &, const db::Region &)) &db::LayoutToNetlist::connect, gsi::arg ("a"), gsi::arg ("b"), + "@brief Defines an inter-layer connection for the given layers.\n" + "The conditions mentioned with intra-layer \\connect apply for this method too.\n" + "As one argument is a (hierarchical) text collection, this method is used to attach net labels to polygons.\n" + "\n" + "This variant has been introduced in version 0.27.\n" + ) + gsi::method ("connect_global", (void (db::LayoutToNetlist::*) (const db::Region &, const std::string &)) &db::LayoutToNetlist::connect_global, gsi::arg ("l"), gsi::arg ("global_net_name"), "@brief Defines a connection of the given layer with a global net.\n" "This method returns the ID of the global net. Use \\global_net_name to get " "the name back from the ID." ) + + gsi::method ("connect_global", (void (db::LayoutToNetlist::*) (const db::Texts &, const std::string &)) &db::LayoutToNetlist::connect_global, gsi::arg ("l"), gsi::arg ("global_net_name"), + "@brief Defines a connection of the given text layer with a global net.\n" + "This method returns the ID of the global net. Use \\global_net_name to get " + "the name back from the ID." + "\n" + "This variant has been introduced in version 0.27.\n" + ) + gsi::method ("global_net_name", &db::LayoutToNetlist::global_net_name, gsi::arg ("global_net_id"), "@brief Gets the global net name for the given global net ID." ) + @@ -378,11 +416,18 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", "Usually it should not be required to obtain the internal cell. If you need to do so, make sure not to modify the cell as\n" "the functionality of the netlist extractor depends on it." ) + - gsi::method ("layer_of", &db::LayoutToNetlist::layer_of, gsi::arg ("l"), + gsi::method ("layer_of", &db::LayoutToNetlist::layer_of, gsi::arg ("l"), "@brief Gets the internal layer for a given extraction layer\n" "This method is required to derive the internal layer index - for example for\n" "investigating the cluster tree.\n" ) + + gsi::method ("layer_of", &db::LayoutToNetlist::layer_of, gsi::arg ("l"), + "@brief Gets the internal layer for a given text collection\n" + "This method is required to derive the internal layer index - for example for\n" + "investigating the cluster tree.\n" + "\n" + "The variant for Texts collections has been added in version 0.27.\n" + ) + gsi::method ("cell_mapping_into", (db::CellMapping (db::LayoutToNetlist::*) (db::Layout &, db::Cell &, bool)) &db::LayoutToNetlist::cell_mapping_into, gsi::arg ("layout"), gsi::arg ("cell"), gsi::arg ("with_device_cells", false), "@brief Creates a cell mapping for copying shapes from the internal layout to the given target layout.\n" "If 'with_device_cells' is true, cells will be produced for devices. These are cells not corresponding to circuits, so they are disabled normally.\n" diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index 099ee25d4..a1c87aade 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -607,7 +607,9 @@ static size_t id (const db::Region *r) int td_simple (); int po_any (); -Class decl_Region ("db", "Region", +extern Class decl_dbShapeCollection; + +Class decl_Region (decl_dbShapeCollection, "db", "Region", constructor ("new", &new_v, "@brief Default constructor\n" "\n" diff --git a/src/db/db/gsiDeclDbShapeCollection.cc b/src/db/db/gsiDeclDbShapeCollection.cc new file mode 100644 index 000000000..fcdacc811 --- /dev/null +++ b/src/db/db/gsiDeclDbShapeCollection.cc @@ -0,0 +1,36 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 "gsiDecl.h" +#include "dbShapeCollection.h" + +namespace gsi +{ + +Class decl_dbShapeCollection ("db", "ShapeCollection", + gsi::Methods (), + "@brief A base class for the shape collections (\\Region, \\Edges, \\EdgePairs and \\Texts)\n" + "\n" + "This class has been introduced in version 0.27." +); + +} diff --git a/src/db/db/gsiDeclDbTexts.cc b/src/db/db/gsiDeclDbTexts.cc index 003179a9d..f7c33c1cb 100644 --- a/src/db/db/gsiDeclDbTexts.cc +++ b/src/db/db/gsiDeclDbTexts.cc @@ -172,7 +172,9 @@ static db::Region pull_interacting (const db::Texts *r, const db::Region &other) return out; } -Class decl_Texts ("db", "Texts", +extern Class decl_dbShapeCollection; + +Class decl_Texts (decl_dbShapeCollection, "db", "Texts", constructor ("new", &new_v, "@brief Default constructor\n" "\n" diff --git a/src/db/unit_tests/dbLayoutToNetlistTests.cc b/src/db/unit_tests/dbLayoutToNetlistTests.cc index 060904eef..ae2ecaf4d 100644 --- a/src/db/unit_tests/dbLayoutToNetlistTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistTests.cc @@ -205,14 +205,14 @@ TEST(1_BasicExtraction) std::auto_ptr rnwell (l2n.make_layer (nwell, "nwell")); std::auto_ptr ractive (l2n.make_layer (active, "active")); std::auto_ptr rpoly (l2n.make_polygon_layer (poly, "poly")); - std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl")); + std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl")); std::auto_ptr rdiff_cont (l2n.make_polygon_layer (diff_cont, "diff_cont")); std::auto_ptr rpoly_cont (l2n.make_polygon_layer (poly_cont, "poly_cont")); std::auto_ptr rmetal1 (l2n.make_polygon_layer (metal1, "metal1")); - std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl")); + std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl")); std::auto_ptr rvia1 (l2n.make_polygon_layer (via1, "via1")); std::auto_ptr rmetal2 (l2n.make_polygon_layer (metal2, "metal2")); - std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl")); + std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl")); // derived regions @@ -693,14 +693,14 @@ TEST(2_Probing) std::auto_ptr rnwell (l2n.make_layer (nwell, "nwell")); std::auto_ptr ractive (l2n.make_layer (active, "active")); std::auto_ptr rpoly (l2n.make_polygon_layer (poly, "poly")); - std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl")); + std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl")); std::auto_ptr rdiff_cont (l2n.make_polygon_layer (diff_cont, "diff_cont")); std::auto_ptr rpoly_cont (l2n.make_polygon_layer (poly_cont, "poly_cont")); std::auto_ptr rmetal1 (l2n.make_polygon_layer (metal1, "metal1")); - std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl")); + std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl")); std::auto_ptr rvia1 (l2n.make_polygon_layer (via1, "via1")); std::auto_ptr rmetal2 (l2n.make_polygon_layer (metal2, "metal2")); - std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl")); + std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl")); // derived regions @@ -947,14 +947,14 @@ TEST(3_GlobalNetConnections) std::auto_ptr rpplus (l2n.make_layer (pplus, "pplus")); std::auto_ptr rnplus (l2n.make_layer (nplus, "nplus")); std::auto_ptr rpoly (l2n.make_polygon_layer (poly, "poly")); - std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl")); + std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl")); std::auto_ptr rdiff_cont (l2n.make_polygon_layer (diff_cont, "diff_cont")); std::auto_ptr rpoly_cont (l2n.make_polygon_layer (poly_cont, "poly_cont")); std::auto_ptr rmetal1 (l2n.make_polygon_layer (metal1, "metal1")); - std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl")); + std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl")); std::auto_ptr rvia1 (l2n.make_polygon_layer (via1, "via1")); std::auto_ptr rmetal2 (l2n.make_polygon_layer (metal2, "metal2")); - std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl")); + std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl")); // derived regions @@ -1228,14 +1228,14 @@ TEST(4_GlobalNetDeviceExtraction) std::auto_ptr rpplus (l2n.make_layer (pplus, "pplus")); std::auto_ptr rnplus (l2n.make_layer (nplus, "nplus")); std::auto_ptr rpoly (l2n.make_polygon_layer (poly, "poly")); - std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl")); + std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl")); std::auto_ptr rdiff_cont (l2n.make_polygon_layer (diff_cont, "diff_cont")); std::auto_ptr rpoly_cont (l2n.make_polygon_layer (poly_cont, "poly_cont")); std::auto_ptr rmetal1 (l2n.make_polygon_layer (metal1, "metal1")); - std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl")); + std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl")); std::auto_ptr rvia1 (l2n.make_polygon_layer (via1, "via1")); std::auto_ptr rmetal2 (l2n.make_polygon_layer (metal2, "metal2")); - std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl")); + std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl")); // derived regions @@ -1514,14 +1514,14 @@ TEST(5_DeviceExtractionWithDeviceCombination) std::auto_ptr rpplus (l2n.make_layer (pplus, "pplus")); std::auto_ptr rnplus (l2n.make_layer (nplus, "nplus")); std::auto_ptr rpoly (l2n.make_polygon_layer (poly, "poly")); - std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl")); + std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl")); std::auto_ptr rdiff_cont (l2n.make_polygon_layer (diff_cont, "diff_cont")); std::auto_ptr rpoly_cont (l2n.make_polygon_layer (poly_cont, "poly_cont")); std::auto_ptr rmetal1 (l2n.make_polygon_layer (metal1, "metal1")); - std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl")); + std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl")); std::auto_ptr rvia1 (l2n.make_polygon_layer (via1, "via1")); std::auto_ptr rmetal2 (l2n.make_polygon_layer (metal2, "metal2")); - std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl")); + std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl")); // derived regions @@ -1793,13 +1793,13 @@ TEST(6_MoreDeviceTypes) std::auto_ptr rpplus (l2n.make_layer (pplus, "pplus")); std::auto_ptr rnplus (l2n.make_layer (nplus, "nplus")); std::auto_ptr rpoly (l2n.make_polygon_layer (poly, "poly")); - std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl")); + std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl")); std::auto_ptr rcont (l2n.make_polygon_layer (cont, "cont")); std::auto_ptr rmetal1 (l2n.make_polygon_layer (metal1, "metal1")); - std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl")); + std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl")); std::auto_ptr rvia1 (l2n.make_polygon_layer (via1, "via1")); std::auto_ptr rmetal2 (l2n.make_polygon_layer (metal2, "metal2")); - std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl")); + std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl")); // derived regions @@ -1950,13 +1950,13 @@ TEST(7_MoreByEmptyDeviceTypes) std::auto_ptr rpplus (l2n.make_layer (pplus, "pplus")); std::auto_ptr rnplus (l2n.make_layer (nplus, "nplus")); std::auto_ptr rpoly (l2n.make_polygon_layer (poly, "poly")); - std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl")); + std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl")); std::auto_ptr rcont (l2n.make_polygon_layer (cont, "cont")); std::auto_ptr rmetal1 (l2n.make_polygon_layer (metal1, "metal1")); - std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl")); + std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl")); std::auto_ptr rvia1 (l2n.make_polygon_layer (via1, "via1")); std::auto_ptr rmetal2 (l2n.make_polygon_layer (metal2, "metal2")); - std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl")); + std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl")); // derived regions @@ -2655,14 +2655,14 @@ TEST(11_DuplicateInstances) std::auto_ptr rnwell (l2n.make_layer (nwell, "nwell")); std::auto_ptr ractive (l2n.make_layer (active, "active")); std::auto_ptr rpoly (l2n.make_polygon_layer (poly, "poly")); - std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl")); + std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl")); std::auto_ptr rdiff_cont (l2n.make_polygon_layer (diff_cont, "diff_cont")); std::auto_ptr rpoly_cont (l2n.make_polygon_layer (poly_cont, "poly_cont")); std::auto_ptr rmetal1 (l2n.make_polygon_layer (metal1, "metal1")); - std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl")); + std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl")); std::auto_ptr rvia1 (l2n.make_polygon_layer (via1, "via1")); std::auto_ptr rmetal2 (l2n.make_polygon_layer (metal2, "metal2")); - std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl")); + std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl")); // derived regions @@ -2863,14 +2863,14 @@ TEST(12_FlattenCircuitDoesFlattenLayout) std::auto_ptr rpplus (l2n.make_layer (pplus, "pplus")); std::auto_ptr rnplus (l2n.make_layer (nplus, "nplus")); std::auto_ptr rpoly (l2n.make_polygon_layer (poly, "poly")); - std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl")); + std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl")); std::auto_ptr rdiff_cont (l2n.make_polygon_layer (diff_cont, "diff_cont")); std::auto_ptr rpoly_cont (l2n.make_polygon_layer (poly_cont, "poly_cont")); std::auto_ptr rmetal1 (l2n.make_polygon_layer (metal1, "metal1")); - std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl")); + std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl")); std::auto_ptr rvia1 (l2n.make_polygon_layer (via1, "via1")); std::auto_ptr rmetal2 (l2n.make_polygon_layer (metal2, "metal2")); - std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl")); + std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl")); // derived regions diff --git a/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc b/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc index 2852c7b1f..badd4227f 100644 --- a/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistWriterTests.cc @@ -76,14 +76,14 @@ TEST(1_WriterBasic) std::auto_ptr rnwell (l2n.make_layer (nwell, "nwell")); std::auto_ptr ractive (l2n.make_layer (active, "active")); std::auto_ptr rpoly (l2n.make_polygon_layer (poly, "poly")); - std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl")); + std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl")); std::auto_ptr rdiff_cont (l2n.make_polygon_layer (diff_cont, "diff_cont")); std::auto_ptr rpoly_cont (l2n.make_polygon_layer (poly_cont, "poly_cont")); std::auto_ptr rmetal1 (l2n.make_polygon_layer (metal1, "metal1")); - std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl")); + std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl")); std::auto_ptr rvia1 (l2n.make_polygon_layer (via1, "via1")); std::auto_ptr rmetal2 (l2n.make_polygon_layer (metal2, "metal2")); - std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl")); + std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl")); // derived regions @@ -289,14 +289,14 @@ TEST(2_WriterWithGlobalNets) std::auto_ptr rpplus (l2n.make_layer (pplus, "pplus")); std::auto_ptr rnplus (l2n.make_layer (nplus, "nplus")); std::auto_ptr rpoly (l2n.make_polygon_layer (poly, "poly")); - std::auto_ptr rpoly_lbl (l2n.make_text_layer (poly_lbl, "poly_lbl")); + std::auto_ptr rpoly_lbl (l2n.make_layer (poly_lbl, "poly_lbl")); std::auto_ptr rdiff_cont (l2n.make_polygon_layer (diff_cont, "diff_cont")); std::auto_ptr rpoly_cont (l2n.make_polygon_layer (poly_cont, "poly_cont")); std::auto_ptr rmetal1 (l2n.make_polygon_layer (metal1, "metal1")); - std::auto_ptr rmetal1_lbl (l2n.make_text_layer (metal1_lbl, "metal1_lbl")); + std::auto_ptr rmetal1_lbl (l2n.make_layer (metal1_lbl, "metal1_lbl")); std::auto_ptr rvia1 (l2n.make_polygon_layer (via1, "via1")); std::auto_ptr rmetal2 (l2n.make_polygon_layer (metal2, "metal2")); - std::auto_ptr rmetal2_lbl (l2n.make_text_layer (metal2_lbl, "metal2_lbl")); + std::auto_ptr rmetal2_lbl (l2n.make_layer (metal2_lbl, "metal2_lbl")); // derived regions diff --git a/src/db/unit_tests/dbLayoutVsSchematicTests.cc b/src/db/unit_tests/dbLayoutVsSchematicTests.cc index 936212d21..f49697db4 100644 --- a/src/db/unit_tests/dbLayoutVsSchematicTests.cc +++ b/src/db/unit_tests/dbLayoutVsSchematicTests.cc @@ -95,14 +95,14 @@ TEST(1_BasicFlow) std::auto_ptr rpplus (lvs.make_layer (pplus, "pplus")); std::auto_ptr rnplus (lvs.make_layer (nplus, "nplus")); std::auto_ptr rpoly (lvs.make_polygon_layer (poly, "poly")); - std::auto_ptr rpoly_lbl (lvs.make_text_layer (poly_lbl, "poly_lbl")); + std::auto_ptr rpoly_lbl (lvs.make_layer (poly_lbl, "poly_lbl")); std::auto_ptr rdiff_cont (lvs.make_polygon_layer (diff_cont, "diff_cont")); std::auto_ptr rpoly_cont (lvs.make_polygon_layer (poly_cont, "poly_cont")); std::auto_ptr rmetal1 (lvs.make_polygon_layer (metal1, "metal1")); - std::auto_ptr rmetal1_lbl (lvs.make_text_layer (metal1_lbl, "metal1_lbl")); + std::auto_ptr rmetal1_lbl (lvs.make_layer (metal1_lbl, "metal1_lbl")); std::auto_ptr rvia1 (lvs.make_polygon_layer (via1, "via1")); std::auto_ptr rmetal2 (lvs.make_polygon_layer (metal2, "metal2")); - std::auto_ptr rmetal2_lbl (lvs.make_text_layer (metal2_lbl, "metal2_lbl")); + std::auto_ptr rmetal2_lbl (lvs.make_layer (metal2_lbl, "metal2_lbl")); // derived regions @@ -293,14 +293,14 @@ TEST(2_FlowWithErrors) std::auto_ptr rpplus (lvs.make_layer (pplus, "pplus")); std::auto_ptr rnplus (lvs.make_layer (nplus, "nplus")); std::auto_ptr rpoly (lvs.make_polygon_layer (poly, "poly")); - std::auto_ptr rpoly_lbl (lvs.make_text_layer (poly_lbl, "poly_lbl")); + std::auto_ptr rpoly_lbl (lvs.make_layer (poly_lbl, "poly_lbl")); std::auto_ptr rdiff_cont (lvs.make_polygon_layer (diff_cont, "diff_cont")); std::auto_ptr rpoly_cont (lvs.make_polygon_layer (poly_cont, "poly_cont")); std::auto_ptr rmetal1 (lvs.make_polygon_layer (metal1, "metal1")); - std::auto_ptr rmetal1_lbl (lvs.make_text_layer (metal1_lbl, "metal1_lbl")); + std::auto_ptr rmetal1_lbl (lvs.make_layer (metal1_lbl, "metal1_lbl")); std::auto_ptr rvia1 (lvs.make_polygon_layer (via1, "via1")); std::auto_ptr rmetal2 (lvs.make_polygon_layer (metal2, "metal2")); - std::auto_ptr rmetal2_lbl (lvs.make_text_layer (metal2_lbl, "metal2_lbl")); + std::auto_ptr rmetal2_lbl (lvs.make_layer (metal2_lbl, "metal2_lbl")); // derived regions diff --git a/src/drc/drc/built-in-macros/_drc_netter.rb b/src/drc/drc/built-in-macros/_drc_netter.rb index 163f094dd..e40229d4e 100644 --- a/src/drc/drc/built-in-macros/_drc_netter.rb +++ b/src/drc/drc/built-in-macros/_drc_netter.rb @@ -94,13 +94,13 @@ module DRC a.is_a?(DRC::DRCLayer) || raise("First argument of Netter#connect must be a layer") b.is_a?(DRC::DRCLayer) || raise("Second argument of Netter#connect must be a layer") - a.requires_region("Netter#connect (first argument)") - b.requires_region("Netter#connect (second argument)") + a.requires_texts_or_region("Netter#connect (first argument)") + b.requires_texts_or_region("Netter#connect (second argument)") register_layer(a.data) register_layer(b.data) - @l2n.connect(a.data) - @l2n.connect(b.data) + a.data.is_a?(RBA::Region) && @l2n.connect(a.data) + b.data.is_a?(RBA::Region) && @l2n.connect(b.data) @l2n.connect(a.data, b.data) end @@ -117,10 +117,10 @@ module DRC 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)") + l.requires_texts_or_region("Netter#connect_global (layer argument)") register_layer(l.data) - @l2n.connect(l.data) + l.data.is_a?(RBA::Region) && @l2n.connect(l.data) @l2n.connect_global(l.data, name) end @@ -189,7 +189,7 @@ module DRC ls = {} layer_selection.keys.sort.each do |n| l = layer_selection[n] - l.requires_region("Netter#extract_devices (#{n} layer)") + l.requires_texts_or_region("Netter#extract_devices (#{n} layer)") register_layer(l.data) ls[n.to_s] = l.data end diff --git a/src/plugins/streamers/cif/db_plugin/dbCIFReader.cc b/src/plugins/streamers/cif/db_plugin/dbCIFReader.cc index f63d9ffb5..6bfaf0851 100644 --- a/src/plugins/streamers/cif/db_plugin/dbCIFReader.cc +++ b/src/plugins/streamers/cif/db_plugin/dbCIFReader.cc @@ -818,7 +818,7 @@ CIFReader::read_cell (db::Layout &layout, db::Cell &cell, double sf, int level) void CIFReader::do_read (db::Layout &layout) { - tl::SelfTimer timer (tl::verbosity () >= 21, "File read"); + tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("File read: ")) + m_stream.source ()); try { diff --git a/src/plugins/streamers/dxf/db_plugin/dbDXFReader.cc b/src/plugins/streamers/dxf/db_plugin/dbDXFReader.cc index 3eebe2dd6..3874e4026 100644 --- a/src/plugins/streamers/dxf/db_plugin/dbDXFReader.cc +++ b/src/plugins/streamers/dxf/db_plugin/dbDXFReader.cc @@ -379,7 +379,7 @@ DXFReader::open_layer (db::Layout &layout, const std::string &n) void DXFReader::do_read (db::Layout &layout, db::cell_index_type top) { - tl::SelfTimer timer (tl::verbosity () >= 21, "File read"); + tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("File read: ")) + m_stream.source ()); // create the zero layer - this is not mapped to GDS but can be specified in the layer mapping as // a layer named "0". diff --git a/src/plugins/streamers/gds2/db_plugin/contrib/dbGDS2TextReader.cc b/src/plugins/streamers/gds2/db_plugin/contrib/dbGDS2TextReader.cc index 5603fd7a3..028d801a9 100644 --- a/src/plugins/streamers/gds2/db_plugin/contrib/dbGDS2TextReader.cc +++ b/src/plugins/streamers/gds2/db_plugin/contrib/dbGDS2TextReader.cc @@ -301,6 +301,12 @@ GDS2ReaderText::get_ushort () return x; } +std::string +GDS2ReaderText::path () const +{ + return sStream.source (); +} + void GDS2ReaderText::error (const std::string &msg) { diff --git a/src/plugins/streamers/gds2/db_plugin/contrib/dbGDS2TextReader.h b/src/plugins/streamers/gds2/db_plugin/contrib/dbGDS2TextReader.h index 0ae2e92e6..4b394d13b 100644 --- a/src/plugins/streamers/gds2/db_plugin/contrib/dbGDS2TextReader.h +++ b/src/plugins/streamers/gds2/db_plugin/contrib/dbGDS2TextReader.h @@ -110,6 +110,7 @@ private: tl::Extractor reader; std::vector xyData; + virtual std::string path () const; const char *get_string (); void get_string (tl::string &s) const; int get_int (); diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2Reader.cc b/src/plugins/streamers/gds2/db_plugin/dbGDS2Reader.cc index caecdbe12..f0fc9ac22 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2Reader.cc +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2Reader.cc @@ -256,6 +256,12 @@ GDS2Reader::progress_checkpoint () m_progress.set (m_stream.pos ()); } +std::string +GDS2Reader::path () const +{ + return m_stream.source (); +} + void GDS2Reader::error (const std::string &msg) { diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2Reader.h b/src/plugins/streamers/gds2/db_plugin/dbGDS2Reader.h index ed612382f..e5bbb4aa3 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2Reader.h +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2Reader.h @@ -124,6 +124,7 @@ private: virtual void error (const std::string &txt); virtual void warn (const std::string &txt); + virtual std::string path () const; virtual const char *get_string (); virtual void get_string (tl::string &s) const; virtual int get_int (); diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc b/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc index 4d6695891..e3d8d45a0 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.cc @@ -233,7 +233,7 @@ eq_y (const GDS2XY &a, const GDS2XY &b) void GDS2ReaderBase::do_read (db::Layout &layout) { - tl::SelfTimer timer (tl::verbosity () >= 21, "File read"); + tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("File read: ")) + path ()); m_cellname = ""; m_libname = ""; diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.h b/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.h index 9e5525441..829ccea71 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.h +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2ReaderBase.h @@ -128,6 +128,7 @@ private: virtual void error (const std::string &txt) = 0; virtual void warn (const std::string &txt) = 0; + virtual std::string path () const = 0; virtual const char *get_string () = 0; virtual void get_string (tl::string &s) const = 0; virtual int get_int () = 0; diff --git a/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc b/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc index f44a71330..b420321c7 100644 --- a/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc +++ b/src/plugins/streamers/magic/db_plugin/dbMAGReader.cc @@ -303,7 +303,7 @@ MAGReader::do_read (db::Layout &layout, db::cell_index_type cell_index, tl::Text void MAGReader::do_read_part (db::Layout &layout, db::cell_index_type cell_index, tl::TextInputStream &stream) { - tl::SelfTimer timer (tl::verbosity () >= 31, "File read"); + tl::SelfTimer timer (tl::verbosity () >= 31, tl::to_string (tr ("File read: ")) + m_stream.source ()); if (tl::verbosity () >= 30) { tl::log << "Reading layout file: " << stream.source (); diff --git a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc index 2d084c313..029dc7f5a 100644 --- a/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc +++ b/src/plugins/streamers/oasis/db_plugin/dbOASISReader.cc @@ -689,7 +689,7 @@ static const char magic_bytes[] = { "%SEMI-OASIS\015\012" }; void OASISReader::do_read (db::Layout &layout) { - tl::SelfTimer timer (tl::verbosity () >= 21, "File read"); + tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("File read: ")) + m_stream.source ()); unsigned char r; char *mb; diff --git a/testdata/algo/l2n_writer_au.txt b/testdata/algo/l2n_writer_au.txt index b56ff4d5f..a93964577 100644 --- a/testdata/algo/l2n_writer_au.txt +++ b/testdata/algo/l2n_writer_au.txt @@ -95,8 +95,8 @@ circuit(INV2 rect(poly (-1425 -630) (1300 360)) rect(poly (-125 -2780) (250 1600)) rect(poly (-250 1200) (250 1600)) - rect(poly_lbl (-526 -1801) (2 2)) - rect(poly_cont (-831 -111) (220 220)) + + rect(poly_cont (-1355 -1910) (220 220)) ) net(2 rect(poly (275 -250) (250 2500)) @@ -123,8 +123,8 @@ circuit(INV2 polygon(metal1 (-110 110) (0 360) (140 0) (0 1240) (-320 0) (0 800) (360 0) (0 -440) (320 0) (0 -1960)) rect(metal1 (-680 2400) (360 760)) rect(metal1 (-360 -3560) (360 760)) - rect(metal1_lbl (-181 1419) (2 2)) - rect(psd (-276 524) (525 950)) + + rect(psd (-455 1945) (525 950)) rect(nsd (-525 -3750) (525 950)) ) net(4 @@ -221,18 +221,18 @@ circuit(RINGO rect(via1 (-305 -305) (250 250)) rect(via1 (24230 -250) (250 250)) rect(metal2 (-24805 -325) (24880 400)) - rect(metal2_lbl (-23161 -201) (2 2)) + ) net(2 name(OSC) rect(via1 (24435 1675) (250 250)) rect(metal2 (-325 -325) (400 400)) - rect(metal2_lbl (-201 -201) (2 2)) + ) net(3 name(VSS) - rect(metal2_lbl (-1 -1) (2 2)) + ) net(4 name(VDD) - rect(metal2_lbl (-1 2799) (2 2)) + ) net(5) net(6) diff --git a/testdata/algo/l2n_writer_au_p.txt b/testdata/algo/l2n_writer_au_p.txt index aeefcf946..cda14e439 100644 --- a/testdata/algo/l2n_writer_au_p.txt +++ b/testdata/algo/l2n_writer_au_p.txt @@ -76,8 +76,8 @@ X(INV2 R(poly (-1425 -630) (1300 360)) R(poly (-125 -2780) (250 1600)) R(poly (-250 1200) (250 1600)) - R(poly_lbl (-526 -1801) (2 2)) - R(poly_cont (-831 -111) (220 220)) + + R(poly_cont (-1355 -1910) (220 220)) ) N(2 R(poly (275 -250) (250 2500)) @@ -104,8 +104,8 @@ X(INV2 Q(metal1 (-110 110) (0 360) (140 0) (0 1240) (-320 0) (0 800) (360 0) (0 -440) (320 0) (0 -1960)) R(metal1 (-680 2400) (360 760)) R(metal1 (-360 -3560) (360 760)) - R(metal1_lbl (-181 1419) (2 2)) - R(psd (-276 524) (525 950)) + + R(psd (-455 1945) (525 950)) R(nsd (-525 -3750) (525 950)) ) N(4 @@ -202,18 +202,18 @@ X(RINGO R(via1 (-305 -305) (250 250)) R(via1 (24230 -250) (250 250)) R(metal2 (-24805 -325) (24880 400)) - R(metal2_lbl (-23161 -201) (2 2)) + ) N(2 I(OSC) R(via1 (24435 1675) (250 250)) R(metal2 (-325 -325) (400 400)) - R(metal2_lbl (-201 -201) (2 2)) + ) N(3 I(VSS) - R(metal2_lbl (-1 -1) (2 2)) + ) N(4 I(VDD) - R(metal2_lbl (-1 2799) (2 2)) + ) N(5) N(6) diff --git a/testdata/algo/l2n_writer_au_s.txt b/testdata/algo/l2n_writer_au_s.txt index fbe139f9b..91e299a0a 100644 --- a/testdata/algo/l2n_writer_au_s.txt +++ b/testdata/algo/l2n_writer_au_s.txt @@ -76,8 +76,8 @@ X(INV2 R(poly (-1425 -630) (1300 360)) R(poly (-125 -2780) (250 1600)) R(poly (-250 1200) (250 1600)) - R(poly_lbl (-526 -1801) (2 2)) - R(poly_cont (-831 -111) (220 220)) + + R(poly_cont (-1355 -1910) (220 220)) ) N(2 R(poly (275 -250) (250 2500)) @@ -104,8 +104,8 @@ X(INV2 Q(metal1 (-110 110) (0 360) (140 0) (0 1240) (-320 0) (0 800) (360 0) (0 -440) (320 0) (0 -1960)) R(metal1 (-680 2400) (360 760)) R(metal1 (-360 -3560) (360 760)) - R(metal1_lbl (-181 1419) (2 2)) - R(psd (-276 524) (525 950)) + + R(psd (-455 1945) (525 950)) R(nsd (-525 -3750) (525 950)) ) N(4 @@ -193,18 +193,18 @@ X(RINGO R(via1 (-305 -305) (250 250)) R(via1 (24230 -250) (250 250)) R(metal2 (-24805 -325) (24880 400)) - R(metal2_lbl (-23161 -201) (2 2)) + ) N(2 I(OSC) R(via1 (24435 1675) (250 250)) R(metal2 (-325 -325) (400 400)) - R(metal2_lbl (-201 -201) (2 2)) + ) N(3 I(VSS) - R(metal2_lbl (-1 -1) (2 2)) + ) N(4 I(VDD) - R(metal2_lbl (-1 2799) (2 2)) + ) N(5) N(6) diff --git a/testdata/lvs/inv.lvsdb b/testdata/lvs/inv.lvsdb index 4b8431f79..a20e8a4e8 100644 --- a/testdata/lvs/inv.lvsdb +++ b/testdata/lvs/inv.lvsdb @@ -26,10 +26,10 @@ layout( connect(l4 l4 l8) connect(l8 l4 l8 l9 l2 l6) connect(l9 l8 l9 l10 l11) - connect(l10 l9 l10) + connect(l10 l9) connect(l11 l9 l11 l12) connect(l12 l11 l12 l13) - connect(l13 l12 l13) + connect(l13 l12) connect(l7 l7) connect(l2 l8 l2) connect(l6 l8 l6) @@ -88,7 +88,7 @@ layout( rect(l4 (-800 -3100) (550 400)) rect(l8 (-450 -300) (200 200)) rect(l9 (-300 -300) (400 400)) - rect(l10 (-201 -201) (2 2)) + ) net(2 name(VSS) rect(l8 (550 300) (200 200)) @@ -97,8 +97,8 @@ layout( rect(l11 (-250 -950) (200 200)) rect(l11 (-200 300) (200 200)) rect(l12 (-750 -850) (2000 1000)) - rect(l13 (-101 -851) (2 2)) - rect(l6 (-1451 49) (450 900)) + + rect(l6 (-1550 -800) (450 900)) ) net(3 name(VDD) rect(l8 (550 4350) (200 200)) @@ -108,8 +108,8 @@ layout( rect(l11 (-250 -800) (200 200)) rect(l11 (-200 300) (200 200)) rect(l12 (-750 -850) (2000 1000)) - rect(l13 (-151 -851) (2 2)) - rect(l2 (-1401 -851) (450 1500)) + + rect(l2 (-1550 -1700) (450 1500)) ) net(4 name(OUT) rect(l8 (1300 4350) (200 200)) @@ -121,8 +121,8 @@ layout( rect(l9 (-300 -4600) (300 3200)) rect(l9 (-300 -2900) (450 400)) rect(l9 (-450 -1550) (300 850)) - rect(l10 (-51 499) (2 2)) - rect(l2 (-351 2649) (450 1500)) + + rect(l2 (-400 3150) (450 1500)) rect(l6 (-450 -5500) (450 900)) ) net(5 name(NWELL) diff --git a/testdata/lvs/inv2.lvsdb b/testdata/lvs/inv2.lvsdb index 5f4e3fee5..c321762cf 100644 --- a/testdata/lvs/inv2.lvsdb +++ b/testdata/lvs/inv2.lvsdb @@ -19,10 +19,10 @@ J( C(l4 l4 l8) C(l8 l4 l8 l11 l2 l9 l6 l10) C(l11 l8 l11 l12 l13) - C(l12 l11 l12) + C(l12 l11) C(l13 l11 l13 l14) C(l14 l13 l14 l15) - C(l15 l14 l15) + C(l15 l14) C(l7 l7) C(l2 l8 l2) C(l9 l3 l8 l9) @@ -69,7 +69,7 @@ J( R(l4 (-800 -3100) (550 400)) R(l8 (-450 -300) (200 200)) R(l11 (-300 -300) (400 400)) - R(l12 (-201 -201) (2 2)) + ) N(2 I(VDD) R(l3 (0 2950) (3000 3200)) @@ -85,8 +85,8 @@ J( R(l13 (1400 -700) (200 200)) R(l13 (-200 300) (200 200)) R(l14 (-2350 -850) (3000 1000)) - R(l15 (-151 -851) (2 2)) - R(l2 (-2401 -851) (450 1500)) + + R(l2 (-2550 -1700) (450 1500)) R(l9 (1050 -1200) (600 1200)) ) N(3 I(OUT) @@ -99,8 +99,8 @@ J( R(l11 (-300 -4600) (300 3200)) R(l11 (-300 -2900) (450 400)) R(l11 (-450 -1550) (300 850)) - R(l12 (-51 499) (2 2)) - R(l2 (-351 2649) (450 1500)) + + R(l2 (-400 3150) (450 1500)) R(l6 (-450 -5500) (450 900)) ) N(4 I(VSS) @@ -115,8 +115,8 @@ J( R(l13 (1400 -700) (200 200)) R(l13 (-200 300) (200 200)) R(l14 (-2350 -850) (3000 1000)) - R(l15 (-151 -851) (2 2)) - R(l6 (-2401 49) (450 900)) + + R(l6 (-2550 -800) (450 900)) R(l10 (1050 -900) (600 1200)) ) D(1 D$PMOS diff --git a/testdata/lvs/nand2_split_gate.lvsdb.1 b/testdata/lvs/nand2_split_gate.lvsdb.1 index b37d55d89..6dbde1217 100644 --- a/testdata/lvs/nand2_split_gate.lvsdb.1 +++ b/testdata/lvs/nand2_split_gate.lvsdb.1 @@ -28,10 +28,10 @@ layout( connect(l4 l4 l8) connect(l8 l4 l8 l11 l2 l9 l6 l10) connect(l11 l8 l11 l12 l13) - connect(l12 l11 l12) + connect(l12 l11) connect(l13 l11 l13 l14) connect(l14 l13 l14 l15) - connect(l15 l14 l15) + connect(l15 l14) connect(l7 l7) connect(l2 l8 l2) connect(l9 l3 l8 l9) @@ -121,7 +121,7 @@ layout( rect(l4 (-250 300) (250 1050)) rect(l8 (-700 400) (200 200)) rect(l11 (-300 -300) (400 400)) - rect(l12 (-201 -201) (2 2)) + ) net(2 name(A) rect(l4 (1900 3400) (550 400)) @@ -131,7 +131,7 @@ layout( rect(l4 (-250 300) (250 1050)) rect(l8 (250 1050) (200 200)) rect(l11 (-300 -300) (400 400)) - rect(l12 (-201 -201) (2 2)) + ) net(3 rect(l8 (1300 300) (200 200)) @@ -167,8 +167,8 @@ layout( rect(l11 (-1200 -300) (1050 300)) rect(l11 (-1050 1150) (300 1400)) rect(l11 (-300 -2700) (300 1950)) - rect(l12 (699 -2001) (2 2)) - rect(l2 (-1101 1299) (500 1500)) + + rect(l2 (-400 -700) (500 1500)) rect(l6 (250 -5500) (450 900)) rect(l6 (-450 450) (450 900)) ) @@ -192,8 +192,8 @@ layout( rect(l13 (700 -700) (200 200)) rect(l13 (-200 300) (200 200)) rect(l14 (-3150 -850) (3750 1000)) - rect(l15 (-101 -851) (2 2)) - rect(l2 (-3201 -851) (450 1500)) + + rect(l2 (-3300 -1700) (450 1500)) rect(l2 (1000 -1500) (450 1500)) rect(l9 (400 -1200) (600 1200)) ) @@ -212,8 +212,8 @@ layout( rect(l13 (2200 -700) (200 200)) rect(l13 (-200 300) (200 200)) rect(l14 (-3150 -850) (3750 1000)) - rect(l15 (-101 -851) (2 2)) - rect(l6 (-3201 1399) (450 900)) + + rect(l6 (-3300 550) (450 900)) rect(l6 (-450 -2250) (450 900)) rect(l10 (1850 -900) (600 1200)) ) diff --git a/testdata/lvs/nand2_split_gate.lvsdb.2 b/testdata/lvs/nand2_split_gate.lvsdb.2 index d99519cfe..382f1cc89 100644 --- a/testdata/lvs/nand2_split_gate.lvsdb.2 +++ b/testdata/lvs/nand2_split_gate.lvsdb.2 @@ -28,10 +28,10 @@ layout( connect(l4 l4 l8) connect(l8 l4 l8 l11 l2 l9 l6 l10) connect(l11 l8 l11 l12 l13) - connect(l12 l11 l12) + connect(l12 l11) connect(l13 l11 l13 l14) connect(l14 l13 l14 l15) - connect(l15 l14 l15) + connect(l15 l14) connect(l7 l7) connect(l2 l8 l2) connect(l9 l3 l8 l9) @@ -121,7 +121,7 @@ layout( rect(l4 (-250 300) (250 1050)) rect(l8 (-700 400) (200 200)) rect(l11 (-300 -300) (400 400)) - rect(l12 (-201 -201) (2 2)) + ) net(2 name(A) rect(l4 (1900 3400) (550 400)) @@ -131,7 +131,7 @@ layout( rect(l4 (-250 300) (250 1050)) rect(l8 (250 1050) (200 200)) rect(l11 (-300 -300) (400 400)) - rect(l12 (-201 -201) (2 2)) + ) net(3 rect(l8 (1300 300) (200 200)) @@ -167,8 +167,8 @@ layout( rect(l11 (-1200 -300) (1050 300)) rect(l11 (-1050 1150) (300 1400)) rect(l11 (-300 -2700) (300 1950)) - rect(l12 (699 -2001) (2 2)) - rect(l2 (-1101 1299) (500 1500)) + + rect(l2 (-400 -700) (500 1500)) rect(l6 (250 -5500) (450 900)) rect(l6 (-450 450) (450 900)) ) @@ -192,8 +192,8 @@ layout( rect(l13 (700 -700) (200 200)) rect(l13 (-200 300) (200 200)) rect(l14 (-3150 -850) (3750 1000)) - rect(l15 (-101 -851) (2 2)) - rect(l2 (-3201 -851) (450 1500)) + + rect(l2 (-3300 -1700) (450 1500)) rect(l2 (1000 -1500) (450 1500)) rect(l9 (400 -1200) (600 1200)) ) @@ -212,8 +212,8 @@ layout( rect(l13 (2200 -700) (200 200)) rect(l13 (-200 300) (200 200)) rect(l14 (-3150 -850) (3750 1000)) - rect(l15 (-101 -851) (2 2)) - rect(l6 (-3201 1399) (450 900)) + + rect(l6 (-3300 550) (450 900)) rect(l6 (-450 -2250) (450 900)) rect(l10 (1850 -900) (600 1200)) ) diff --git a/testdata/lvs/ringo_simple_blackboxing.lvsdb b/testdata/lvs/ringo_simple_blackboxing.lvsdb index 6089203e1..31b71eaba 100644 --- a/testdata/lvs/ringo_simple_blackboxing.lvsdb +++ b/testdata/lvs/ringo_simple_blackboxing.lvsdb @@ -28,7 +28,6 @@ layout( connect(l11 l8 l11 l12) connect(l12 l11 l12 l13) connect(l13 l12 l13) - connect(l7 l7) connect(l2 l8 l2) connect(l9 l3 l8 l9) connect(l6 l8 l6) @@ -47,7 +46,7 @@ layout( circuit(ND2X1 # Circuit boundary - rect((-100 249) (2600 7751)) + rect((-100 250) (2600 7750)) # Outgoing pins and their connections to nets pin(name(VDD)) @@ -62,7 +61,7 @@ layout( circuit(INVX1 # Circuit boundary - rect((-100 249) (2000 7751)) + rect((-100 250) (2000 7750)) # Outgoing pins and their connections to nets pin(name(VDD)) @@ -76,7 +75,7 @@ layout( circuit(INVX2 # Circuit boundary - rect((-100 249) (2600 7751)) + rect((-100 250) (2600 7750)) # Outgoing pins and their connections to nets pin(name(IN)) @@ -90,7 +89,7 @@ layout( circuit(RINGO # Circuit boundary - rect((600 249) (25800 7751)) + rect((600 250) (25800 7750)) # Nets with their geometries net(1 From b84a9df2da942eca0b2f2db4440d4badb725a25d Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 22 May 2020 00:58:46 +0200 Subject: [PATCH 22/35] Persisting texts now for .l2n format --- src/db/db/dbLayoutToNetlistFormatDefs.cc | 4 +- src/db/db/dbLayoutToNetlistFormatDefs.h | 3 + src/db/db/dbLayoutToNetlistReader.cc | 23 +- src/db/db/dbLayoutToNetlistReader.h | 2 +- src/db/db/dbLayoutToNetlistWriter.cc | 56 +-- .../dbLayoutToNetlistReaderTests.cc | 14 +- src/db/unit_tests/dbNetShapeTests.cc | 9 +- testdata/algo/l2n_reader_au_p.oas | Bin 0 -> 1604 bytes testdata/algo/l2n_reader_in.txt | 334 ++++++++++++++++++ testdata/algo/l2n_reader_in_p.txt | 313 ++++++++++++++++ testdata/algo/l2n_reader_in_s.txt | 301 ++++++++++++++++ testdata/algo/l2n_writer_au.txt | 16 +- testdata/algo/l2n_writer_au_p.txt | 16 +- testdata/algo/l2n_writer_au_s.txt | 16 +- testdata/python/dbLayoutToNetlist.py | 2 +- testdata/ruby/dbLayoutToNetlist.rb | 6 +- 16 files changed, 1047 insertions(+), 68 deletions(-) create mode 100644 testdata/algo/l2n_reader_au_p.oas create mode 100644 testdata/algo/l2n_reader_in.txt create mode 100644 testdata/algo/l2n_reader_in_p.txt create mode 100644 testdata/algo/l2n_reader_in_s.txt diff --git a/src/db/db/dbLayoutToNetlistFormatDefs.cc b/src/db/db/dbLayoutToNetlistFormatDefs.cc index 9ddade687..b89794ea2 100644 --- a/src/db/db/dbLayoutToNetlistFormatDefs.cc +++ b/src/db/db/dbLayoutToNetlistFormatDefs.cc @@ -47,6 +47,7 @@ namespace l2n_std_format DB_PUBLIC std::string LongKeys::device_key ("device"); DB_PUBLIC std::string LongKeys::polygon_key ("polygon"); DB_PUBLIC std::string LongKeys::rect_key ("rect"); + DB_PUBLIC std::string LongKeys::text_key ("text"); DB_PUBLIC std::string LongKeys::terminal_key ("terminal"); DB_PUBLIC std::string LongKeys::abstract_key ("abstract"); DB_PUBLIC std::string LongKeys::param_key ("param"); @@ -56,7 +57,7 @@ namespace l2n_std_format DB_PUBLIC std::string LongKeys::scale_key ("scale"); DB_PUBLIC std::string LongKeys::pin_key ("pin"); - // A, B, C, D, E, F, G, I, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y + // A, B, C, D, E, F, G, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y DB_PUBLIC std::string ShortKeys::version_key ("V"); DB_PUBLIC std::string ShortKeys::description_key ("B"); DB_PUBLIC std::string ShortKeys::top_key ("W"); @@ -72,6 +73,7 @@ namespace l2n_std_format DB_PUBLIC std::string ShortKeys::device_key ("D"); DB_PUBLIC std::string ShortKeys::polygon_key ("Q"); DB_PUBLIC std::string ShortKeys::rect_key ("R"); + DB_PUBLIC std::string ShortKeys::text_key ("J"); DB_PUBLIC std::string ShortKeys::terminal_key ("T"); DB_PUBLIC std::string ShortKeys::abstract_key ("A"); DB_PUBLIC std::string ShortKeys::param_key ("E"); diff --git a/src/db/db/dbLayoutToNetlistFormatDefs.h b/src/db/db/dbLayoutToNetlistFormatDefs.h index a2c46a34c..f3a97a4de 100644 --- a/src/db/db/dbLayoutToNetlistFormatDefs.h +++ b/src/db/db/dbLayoutToNetlistFormatDefs.h @@ -119,6 +119,7 @@ namespace db * "*" for or means take previous * rect( [coord] [coord]) - defines a rectangle [short key: R] * coordinates are bottom/left and top/right + * text( [text] [coord]) - defines a rectangle [short key: J] * * [coord] * @@ -177,6 +178,7 @@ namespace l2n_std_format static std::string subcircuit_key; static std::string polygon_key; static std::string rect_key; + static std::string text_key; static std::string terminal_key; static std::string abstract_key; static std::string param_key; @@ -209,6 +211,7 @@ namespace l2n_std_format static std::string subcircuit_key; static std::string polygon_key; static std::string rect_key; + static std::string text_key; static std::string terminal_key; static std::string abstract_key; static std::string param_key; diff --git a/src/db/db/dbLayoutToNetlistReader.cc b/src/db/db/dbLayoutToNetlistReader.cc index f312eefc4..1fc9ed56e 100644 --- a/src/db/db/dbLayoutToNetlistReader.cc +++ b/src/db/db/dbLayoutToNetlistReader.cc @@ -445,8 +445,7 @@ LayoutToNetlistStandardReader::read_property (db::NetlistObject *obj) br.done (); } -std::pair -LayoutToNetlistStandardReader::read_geometry (db::LayoutToNetlist *l2n) +std::pair LayoutToNetlistStandardReader::read_geometry(db::LayoutToNetlist *l2n) { std::string lname; @@ -482,6 +481,22 @@ LayoutToNetlistStandardReader::read_geometry (db::LayoutToNetlist *l2n) poly.assign_hull (pt.begin (), pt.end ()); return std::make_pair (lid, db::PolygonRef (poly, l2n->internal_layout ()->shape_repository ())); + } else if (test (skeys::text_key) || test (lkeys::text_key)) { + + Brace br (this); + + read_word_or_quoted (lname); + unsigned int lid = l2n->layer_of (layer_by_name (l2n, lname)); + + std::string text; + read_word_or_quoted (text); + + db::Point pt = read_point (); + + br.done (); + + return std::make_pair (lid, db::TextRef (db::Text (text, db::Trans (pt - db::Point ())), l2n->internal_layout ()->shape_repository ())); + } else if (at_end ()) { throw tl::Exception (tl::to_string (tr ("Unexpected end of file (polygon or rect expected)"))); } else { @@ -532,9 +547,9 @@ LayoutToNetlistStandardReader::read_geometries (db::NetlistObject *obj, Brace &b if (test (skeys::property_key) || test (lkeys::property_key)) { read_property (obj); } else { - std::pair pr = read_geometry (l2n); + std::pair pr = read_geometry (l2n); lc.add (pr.second, pr.first); - cell.shapes (pr.first).insert (pr.second); + pr.second.insert_into (cell.shapes (pr.first)); } } } diff --git a/src/db/db/dbLayoutToNetlistReader.h b/src/db/db/dbLayoutToNetlistReader.h index 860d7f714..75d577f16 100644 --- a/src/db/db/dbLayoutToNetlistReader.h +++ b/src/db/db/dbLayoutToNetlistReader.h @@ -139,7 +139,7 @@ protected: void read_subcircuit (Netlist *netlist, db::LayoutToNetlist *l2n, db::Circuit *circuit, ObjectMap &map, std::map > &connections); bool read_trans_part (db::DCplxTrans &tr); void read_abstract_terminal (db::LayoutToNetlist *l2n, db::DeviceAbstract *dm, db::DeviceClass *dc); - std::pair read_geometry (db::LayoutToNetlist *l2n); + std::pair read_geometry(db::LayoutToNetlist *l2n); void read_property (db::NetlistObject *obj); db::Polygon read_polygon (); db::Box read_rect (); diff --git a/src/db/db/dbLayoutToNetlistWriter.cc b/src/db/db/dbLayoutToNetlistWriter.cc index ad1531e13..8af2f2049 100644 --- a/src/db/db/dbLayoutToNetlistWriter.cc +++ b/src/db/db/dbLayoutToNetlistWriter.cc @@ -399,33 +399,47 @@ void std_writer_impl::reset_geometry_ref () template void std_writer_impl::write (const db::NetShape *s, const db::ICplxTrans &tr, const std::string &lname, bool relative) { - if (s->type () != db::NetShape::Polygon) { - return; - } + if (s->type () == db::NetShape::Polygon) { - db::PolygonRef pr = s->polygon_ref (); - db::ICplxTrans t = tr * db::ICplxTrans (pr.trans ()); + db::PolygonRef pr = s->polygon_ref (); + db::ICplxTrans t = tr * db::ICplxTrans (pr.trans ()); - const db::Polygon &poly = pr.obj (); - if (poly.is_box ()) { + const db::Polygon &poly = pr.obj (); + if (poly.is_box ()) { - db::Box box = t * poly.box (); - *mp_stream << Keys::rect_key << "(" << lname; - *mp_stream << " "; - write_point (*mp_stream, box.p1 (), m_ref, relative); - *mp_stream << " "; - write_point (*mp_stream, box.p2 (), m_ref, relative); - *mp_stream << ")"; + db::Box box = t * poly.box (); + *mp_stream << Keys::rect_key << "(" << lname; + *mp_stream << " "; + write_point (*mp_stream, box.p1 (), m_ref, relative); + *mp_stream << " "; + write_point (*mp_stream, box.p2 (), m_ref, relative); + *mp_stream << ")"; - } else { - - *mp_stream << Keys::polygon_key << "(" << lname; - if (poly.holes () > 0) { - db::SimplePolygon sp = db::polygon_to_simple_polygon (poly); - write_points (*mp_stream, sp, t, m_ref, relative); } else { - write_points (*mp_stream, poly, t, m_ref, relative); + + *mp_stream << Keys::polygon_key << "(" << lname; + if (poly.holes () > 0) { + db::SimplePolygon sp = db::polygon_to_simple_polygon (poly); + write_points (*mp_stream, sp, t, m_ref, relative); + } else { + write_points (*mp_stream, poly, t, m_ref, relative); + } + *mp_stream << ")"; + } + + } else if (s->type () == db::NetShape::Text) { + + *mp_stream << Keys::text_key << "(" << lname; + + db::TextRef txtr = s->text_ref (); + db::ICplxTrans t = tr * db::ICplxTrans (txtr.trans ()); + + *mp_stream << " " << tl::to_word_or_quoted_string (txtr.obj ().string ()) << " "; + + db::Point pt = t * (db::Point () + txtr.obj ().trans ().disp ()); + write_point (*mp_stream, pt, m_ref, relative); + *mp_stream << ")"; } diff --git a/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc b/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc index cec0ca51b..f3002b868 100644 --- a/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc +++ b/src/db/unit_tests/dbLayoutToNetlistReaderTests.cc @@ -36,7 +36,7 @@ TEST(1_ReaderBasic) { db::LayoutToNetlist l2n; - std::string in_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au.txt"); + std::string in_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_reader_in.txt"); tl::InputStream is_in (in_path); db::LayoutToNetlistStandardReader reader (is_in); @@ -51,7 +51,7 @@ TEST(1_ReaderBasic) writer.write (&l2n); } - std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au.txt"); + std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_reader_in.txt"); compare_text_files (path, au_path); @@ -246,7 +246,7 @@ TEST(1b_ReaderBasicShort) { db::LayoutToNetlist l2n; - std::string in_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au_s.txt"); + std::string in_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_reader_in_s.txt"); tl::InputStream is_in (in_path); db::LayoutToNetlistStandardReader reader (is_in); @@ -261,7 +261,7 @@ TEST(1b_ReaderBasicShort) writer.write (&l2n); } - std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au_s.txt"); + std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_reader_in_s.txt"); compare_text_files (path, au_path); } @@ -270,7 +270,7 @@ TEST(1c_ReaderBasicShortWithProps) { db::LayoutToNetlist l2n; - std::string in_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au_p.txt"); + std::string in_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_reader_in_p.txt"); tl::InputStream is_in (in_path); db::LayoutToNetlistStandardReader reader (is_in); @@ -285,7 +285,7 @@ TEST(1c_ReaderBasicShortWithProps) writer.write (&l2n); } - std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_writer_au_p.txt"); + std::string au_path = tl::combine_path (tl::combine_path (tl::combine_path (tl::testsrc (), "testdata"), "algo"), "l2n_reader_in_p.txt"); compare_text_files (path, au_path); @@ -314,7 +314,7 @@ TEST(1c_ReaderBasicShortWithProps) std::string au = tl::testsrc (); au = tl::combine_path (au, "testdata"); au = tl::combine_path (au, "algo"); - au = tl::combine_path (au, "l2n_writer_au_p.oas"); + au = tl::combine_path (au, "l2n_reader_au_p.oas"); db::compare_layouts (_this, ly2, au, db::WriteOAS); } diff --git a/src/db/unit_tests/dbNetShapeTests.cc b/src/db/unit_tests/dbNetShapeTests.cc index 06e3a5432..8bf3a0d36 100644 --- a/src/db/unit_tests/dbNetShapeTests.cc +++ b/src/db/unit_tests/dbNetShapeTests.cc @@ -96,15 +96,13 @@ TEST(3) s.transform (db::Disp (db::Vector (10, 20))); EXPECT_EQ (s == s2, false); EXPECT_EQ (s != s2, true); - EXPECT_EQ (s < s2, false); - EXPECT_EQ (s2 < s, true); + EXPECT_EQ ((s < s2) != (s2 < s), true); db::Text t ("abc", db::Trans (db::Vector (100, 200))); s = db::NetShape (t, repo); EXPECT_EQ (s == s2, false); EXPECT_EQ (s != s2, true); - EXPECT_EQ (s < s2, true); - EXPECT_EQ (s2 < s, false); + EXPECT_EQ ((s < s2) != (s2 < s), true); s2 = s; EXPECT_EQ (s == db::NetShape (), false); @@ -117,8 +115,7 @@ TEST(3) s.transform (db::Disp (db::Vector (10, 20))); EXPECT_EQ (s == s2, false); EXPECT_EQ (s != s2, true); - EXPECT_EQ (s < s2, false); - EXPECT_EQ (s2 < s, true); + EXPECT_EQ ((s < s2) != (s2 < s), true); } TEST(4) diff --git a/testdata/algo/l2n_reader_au_p.oas b/testdata/algo/l2n_reader_au_p.oas new file mode 100644 index 0000000000000000000000000000000000000000..83a8f061a2b5a6bd09714f4b57d27748390a42d9 GIT binary patch literal 1604 zcmd^9O-oc!7{2G6`!)B&nKSp?0f)Pa(E=;dY|$=rZZ?oJ;vKD47yBd(r7}>a$e>mc z%%Y+X0^RiC%0*e5=o&(`n^hPp-9^N-2owrZi#liKjyjsZptHH>dEe)Kp65LSQ|H+2 zsU4XXC*|l0K#eXvnhuxVyDw#d*mcITz_uR$)fs-e;xEBV_pXoa- zNj>hVv;92-A=KF16oQQx5SvDPD&5_L#I&8INsykjyHl;Un@n`HXPh-K&0vX@XhPvC zR-zH%bp={l<*?BzPPsr!5_8RTWjD?@ttkccAY`I>z4Sl0yMw5E)^OQEH2a3A0r$ZE zAdb^ozH~cIa7iWwL{kbdl@?GpL$pUrPOAV9?AN0tr*Mz>3F)o!Leg;sEdh$cB&V+S zYAUGI(-^u*=SoOrb1NuBa)?_36VftMkt@vG%t5N^iIurhkFV;XDip!<(Gk&az&;)o z$tRwh1#{qgy$bUPMj^Q@7U56fD=gM293*oz)iU@{uX1@5B}4MOc}-d{XA@*dVXHpo z#}c}Z{qTs0{hC#|Z~S_>MPXI$hEOecT_QtjS&r_dU|*wh1=VjTr~9mw<)X);=3WuV z1>r6nH?9hvRuC4%Vfx)hF0s(lp+%}ZZ$^zACjw8)TQnwn%lq zq4WsS2z@&C$Wz86{s$u4J#A7esgUU+e2I!0nd4`{!3+D z2q!fcl&Va|$yFtB1U_&2KCSNe@-YVX8VZsawHY)TuF$KQZFT8IzVZpJZs1sUY6&DuJ^ mUIcqO_7v=FD9sB(csDhGQ89R8mV$NdGQwb?5G literal 0 HcmV?d00001 diff --git a/testdata/algo/l2n_reader_in.txt b/testdata/algo/l2n_reader_in.txt new file mode 100644 index 000000000..15276f97a --- /dev/null +++ b/testdata/algo/l2n_reader_in.txt @@ -0,0 +1,334 @@ +#%l2n-klayout +top(RINGO) +unit(0.001) + +# Layer section +# This section lists the mask layers (drawing or derived) and their connections. + +# Mask layers +layer(poly '3/0') +layer(poly_lbl '3/1') +layer(diff_cont '4/0') +layer(poly_cont '5/0') +layer(metal1 '6/0') +layer(metal1_lbl '6/1') +layer(via1 '7/0') +layer(metal2 '8/0') +layer(metal2_lbl '8/1') +layer(psd) +layer(nsd) + +# Mask layer connectivity +connect(poly poly poly_lbl poly_cont) +connect(poly_lbl poly) +connect(diff_cont diff_cont metal1 psd nsd) +connect(poly_cont poly poly_cont metal1) +connect(metal1 diff_cont poly_cont metal1 metal1_lbl via1) +connect(metal1_lbl metal1) +connect(via1 metal1 via1 metal2) +connect(metal2 via1 metal2 metal2_lbl) +connect(metal2_lbl metal2) +connect(psd diff_cont psd) +connect(nsd diff_cont nsd) + +# Device class section +class(PMOS MOS3) +class(NMOS MOS3) + +# Device abstracts section +# Device abstracts list the pin shapes of the devices. +device(D$PMOS PMOS + terminal(S + rect(psd (-650 -475) (525 950)) + ) + terminal(G + rect(poly (-125 -475) (250 950)) + ) + terminal(D + rect(psd (125 -475) (550 950)) + ) +) +device(D$PMOS$1 PMOS + terminal(S + rect(psd (-675 -475) (550 950)) + ) + terminal(G + rect(poly (-125 -475) (250 950)) + ) + terminal(D + rect(psd (125 -475) (525 950)) + ) +) +device(D$NMOS NMOS + terminal(S + rect(nsd (-650 -475) (525 950)) + ) + terminal(G + rect(poly (-125 -475) (250 950)) + ) + terminal(D + rect(nsd (125 -475) (550 950)) + ) +) +device(D$NMOS$1 NMOS + terminal(S + rect(nsd (-675 -475) (550 950)) + ) + terminal(G + rect(poly (-125 -475) (250 950)) + ) + terminal(D + rect(nsd (125 -475) (525 950)) + ) +) + +# Circuit section +# Circuits are the hierarchical building blocks of the netlist. +circuit(INV2 + + # Circuit boundary + rect((-1700 -800) (3100 4600)) + + # Nets with their geometries + net(1 name(IN) + rect(poly (-525 -250) (250 2500)) + rect(poly (-1425 -630) (1300 360)) + rect(poly (-125 -2780) (250 1600)) + rect(poly (-250 1200) (250 1600)) + text(poly_lbl IN (-525 -1800)) + rect(poly_cont (-830 -110) (220 220)) + ) + net(2 + rect(poly (275 -250) (250 2500)) + rect(poly (-305 -1430) (360 360)) + rect(poly (-305 820) (250 1600)) + rect(poly (-250 -4400) (250 1600)) + rect(diff_cont (-1435 1690) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -3420) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(poly_cont (980 580) (220 220)) + rect(metal1 (-1310 -290) (1380 360)) + rect(metal1 (-1560 -1600) (360 2840)) + rect(metal1 (-360 0) (360 760)) + rect(metal1 (-360 -3560) (360 760)) + rect(psd (-430 1945) (525 950)) + rect(nsd (-525 -3750) (525 950)) + ) + net(3 name(OUT) + rect(diff_cont (690 2890) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(diff_cont (-220 -2620) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + polygon(metal1 (-110 110) (0 360) (140 0) (0 1240) (-320 0) (0 800) (360 0) (0 -440) (320 0) (0 -1960)) + rect(metal1 (-680 2400) (360 760)) + rect(metal1 (-360 -3560) (360 760)) + text(metal1_lbl OUT (-180 1420)) + rect(psd (-275 525) (525 950)) + rect(nsd (-525 -3750) (525 950)) + ) + net(4 + rect(diff_cont (-110 -310) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -220) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(metal1 (-290 -290) (360 760)) + rect(metal1 (-360 -760) (360 760)) + rect(via1 (-305 -705) (250 250)) + rect(via1 (-250 150) (250 250)) + rect(metal2 (-1525 -775) (2800 900)) + rect(nsd (-1675 -925) (550 950)) + ) + net(5 + rect(diff_cont (-110 2490) (220 220)) + rect(diff_cont (-220 180) (220 220)) + rect(diff_cont (-220 -220) (220 220)) + rect(diff_cont (-220 -620) (220 220)) + rect(metal1 (-290 -290) (360 760)) + rect(metal1 (-360 -760) (360 760)) + rect(via1 (-305 -705) (250 250)) + rect(via1 (-250 150) (250 250)) + rect(metal2 (-1525 -775) (2800 900)) + rect(psd (-1675 -925) (550 950)) + ) + + # Outgoing pins and their connections to nets + pin(1 name(IN)) + pin(2) + pin(3 name(OUT)) + pin(4) + pin(5) + + # Devices and their connections + device(1 D$PMOS + location(-400 2800) + param(L 0.25) + param(W 0.95) + param(AS 0.49875) + param(AD 0.26125) + param(PS 2.95) + param(PD 1.5) + terminal(S 2) + terminal(G 1) + terminal(D 5) + ) + device(2 D$PMOS$1 + location(400 2800) + param(L 0.25) + param(W 0.95) + param(AS 0.26125) + param(AD 0.49875) + param(PS 1.5) + param(PD 2.95) + terminal(S 5) + terminal(G 2) + terminal(D 3) + ) + device(3 D$NMOS + location(-400 0) + param(L 0.25) + param(W 0.95) + param(AS 0.49875) + param(AD 0.26125) + param(PS 2.95) + param(PD 1.5) + terminal(S 2) + terminal(G 1) + terminal(D 4) + ) + device(4 D$NMOS$1 + location(400 0) + param(L 0.25) + param(W 0.95) + param(AS 0.26125) + param(AD 0.49875) + param(PS 1.5) + param(PD 2.95) + terminal(S 4) + terminal(G 2) + terminal(D 3) + ) + +) +circuit(RINGO + + # Circuit boundary + rect((-1720 -800) (26880 4600)) + + # Nets with their geometries + net(1 name(FB) + rect(metal1 (-1700 1620) (360 360)) + rect(via1 (-305 -305) (250 250)) + rect(via1 (24230 -250) (250 250)) + rect(metal2 (-24805 -325) (24880 400)) + text(metal2_lbl FB (-23160 -200)) + ) + net(2 name(OSC) + rect(via1 (24435 1675) (250 250)) + rect(metal2 (-325 -325) (400 400)) + text(metal2_lbl OSC (-200 -200)) + ) + net(3 name(VSS) + text(metal2_lbl VSS (0 0)) + ) + net(4 name(VDD) + text(metal2_lbl VDD (0 2800)) + ) + net(5) + net(6) + net(7) + net(8) + net(9) + net(10) + net(11) + net(12) + net(13) + net(14) + net(15) + net(16) + net(17) + net(18) + net(19) + net(20) + net(21) + net(22) + + # Outgoing pins and their connections to nets + pin(1 name(FB)) + pin(2 name(OSC)) + pin(3 name(VSS)) + pin(4 name(VDD)) + + # Subcircuits and their connections + circuit(1 INV2 location(23760 0) + pin(0 15) + pin(1 1) + pin(2 2) + pin(3 3) + pin(4 4) + ) + circuit(2 INV2 location(0 0) + pin(0 1) + pin(1 13) + pin(2 14) + pin(3 3) + pin(4 4) + ) + circuit(3 INV2 location(2640 0) + pin(0 14) + pin(1 12) + pin(2 22) + pin(3 3) + pin(4 4) + ) + circuit(4 INV2 location(5280 0) + pin(0 22) + pin(1 11) + pin(2 21) + pin(3 3) + pin(4 4) + ) + circuit(5 INV2 location(7920 0) + pin(0 21) + pin(1 10) + pin(2 20) + pin(3 3) + pin(4 4) + ) + circuit(6 INV2 location(10560 0) + pin(0 20) + pin(1 9) + pin(2 19) + pin(3 3) + pin(4 4) + ) + circuit(7 INV2 location(13200 0) + pin(0 19) + pin(1 8) + pin(2 18) + pin(3 3) + pin(4 4) + ) + circuit(8 INV2 location(15840 0) + pin(0 18) + pin(1 7) + pin(2 17) + pin(3 3) + pin(4 4) + ) + circuit(9 INV2 location(18480 0) + pin(0 17) + pin(1 6) + pin(2 16) + pin(3 3) + pin(4 4) + ) + circuit(10 INV2 location(21120 0) + pin(0 16) + pin(1 5) + pin(2 15) + pin(3 3) + pin(4 4) + ) + +) diff --git a/testdata/algo/l2n_reader_in_p.txt b/testdata/algo/l2n_reader_in_p.txt new file mode 100644 index 000000000..84e52624e --- /dev/null +++ b/testdata/algo/l2n_reader_in_p.txt @@ -0,0 +1,313 @@ +#%l2n-klayout +W(RINGO) +U(0.001) +L(poly '3/0') +L(poly_lbl '3/1') +L(diff_cont '4/0') +L(poly_cont '5/0') +L(metal1 '6/0') +L(metal1_lbl '6/1') +L(via1 '7/0') +L(metal2 '8/0') +L(metal2_lbl '8/1') +L(psd) +L(nsd) +C(poly poly poly_lbl poly_cont) +C(poly_lbl poly) +C(diff_cont diff_cont metal1 psd nsd) +C(poly_cont poly poly_cont metal1) +C(metal1 diff_cont poly_cont metal1 metal1_lbl via1) +C(metal1_lbl metal1) +C(via1 metal1 via1 metal2) +C(metal2 via1 metal2 metal2_lbl) +C(metal2_lbl metal2) +C(psd diff_cont psd) +C(nsd diff_cont nsd) +K(PMOS MOS3) +K(NMOS MOS3) +D(D$PMOS PMOS + T(S + R(psd (-650 -475) (525 950)) + ) + T(G + R(poly (-125 -475) (250 950)) + ) + T(D + R(psd (125 -475) (550 950)) + ) +) +D(D$PMOS$1 PMOS + T(S + R(psd (-675 -475) (550 950)) + ) + T(G + R(poly (-125 -475) (250 950)) + ) + T(D + R(psd (125 -475) (525 950)) + ) +) +D(D$NMOS NMOS + T(S + R(nsd (-650 -475) (525 950)) + ) + T(G + R(poly (-125 -475) (250 950)) + ) + T(D + R(nsd (125 -475) (550 950)) + ) +) +D(D$NMOS$1 NMOS + T(S + R(nsd (-675 -475) (550 950)) + ) + T(G + R(poly (-125 -475) (250 950)) + ) + T(D + R(nsd (125 -475) (525 950)) + ) +) +X(INV2 + R((-1700 -800) (3100 4600)) + N(1 I(IN) + R(poly (-525 -250) (250 2500)) + R(poly (-1425 -630) (1300 360)) + R(poly (-125 -2780) (250 1600)) + R(poly (-250 1200) (250 1600)) + J(poly_lbl IN (-525 -1800)) + R(poly_cont (-830 -110) (220 220)) + ) + N(2 + R(poly (275 -250) (250 2500)) + R(poly (-305 -1430) (360 360)) + R(poly (-305 820) (250 1600)) + R(poly (-250 -4400) (250 1600)) + R(diff_cont (-1435 1690) (220 220)) + R(diff_cont (-220 180) (220 220)) + R(diff_cont (-220 -3420) (220 220)) + R(diff_cont (-220 180) (220 220)) + R(poly_cont (980 580) (220 220)) + R(metal1 (-1310 -290) (1380 360)) + R(metal1 (-1560 -1600) (360 2840)) + R(metal1 (-360 0) (360 760)) + R(metal1 (-360 -3560) (360 760)) + R(psd (-430 1945) (525 950)) + R(nsd (-525 -3750) (525 950)) + ) + N(3 I(OUT) + R(diff_cont (690 2890) (220 220)) + R(diff_cont (-220 -620) (220 220)) + R(diff_cont (-220 -2620) (220 220)) + R(diff_cont (-220 -620) (220 220)) + Q(metal1 (-110 110) (0 360) (140 0) (0 1240) (-320 0) (0 800) (360 0) (0 -440) (320 0) (0 -1960)) + R(metal1 (-680 2400) (360 760)) + R(metal1 (-360 -3560) (360 760)) + J(metal1_lbl OUT (-180 1420)) + R(psd (-275 525) (525 950)) + R(nsd (-525 -3750) (525 950)) + ) + N(4 + R(diff_cont (-110 -310) (220 220)) + R(diff_cont (-220 180) (220 220)) + R(diff_cont (-220 -220) (220 220)) + R(diff_cont (-220 -620) (220 220)) + R(metal1 (-290 -290) (360 760)) + R(metal1 (-360 -760) (360 760)) + R(via1 (-305 -705) (250 250)) + R(via1 (-250 150) (250 250)) + R(metal2 (-1525 -775) (2800 900)) + R(nsd (-1675 -925) (550 950)) + ) + N(5 + R(diff_cont (-110 2490) (220 220)) + R(diff_cont (-220 180) (220 220)) + R(diff_cont (-220 -220) (220 220)) + R(diff_cont (-220 -620) (220 220)) + R(metal1 (-290 -290) (360 760)) + R(metal1 (-360 -760) (360 760)) + R(via1 (-305 -705) (250 250)) + R(via1 (-250 150) (250 250)) + R(metal2 (-1525 -775) (2800 900)) + R(psd (-1675 -925) (550 950)) + ) + P(1 I(IN)) + P(2) + P(3 I(OUT)) + P(4) + P(5) + D(1 D$PMOS + Y(-400 2800) + F(#17 #242) + F('a_"non_quoted"_string' '2s') + F('a_float' ##20.5) + E(L 0.25) + E(W 0.95) + E(AS 0.49875) + E(AD 0.26125) + E(PS 2.95) + E(PD 1.5) + T(S 2) + T(G 1) + T(D 5) + ) + D(2 D$PMOS$1 + Y(400 2800) + E(L 0.25) + E(W 0.95) + E(AS 0.26125) + E(AD 0.49875) + E(PS 1.5) + E(PD 2.95) + T(S 5) + T(G 2) + T(D 3) + ) + D(3 D$NMOS + Y(-400 0) + E(L 0.25) + E(W 0.95) + E(AS 0.49875) + E(AD 0.26125) + E(PS 2.95) + E(PD 1.5) + T(S 2) + T(G 1) + T(D 4) + ) + D(4 D$NMOS$1 + Y(400 0) + E(L 0.25) + E(W 0.95) + E(AS 0.26125) + E(AD 0.49875) + E(PS 1.5) + E(PD 2.95) + T(S 4) + T(G 2) + T(D 3) + ) +) +X(RINGO + R((-1720 -800) (26880 4600)) + F(#17 #42) + F('a_"non_quoted"_string' 's') + F('a_float' ##0.5) + N(1 I(FB) + F(#17 #142) + F('a_"non_quoted"_string' '1s') + F('a_float' ##10.5) + R(metal1 (-1700 1620) (360 360)) + R(via1 (-305 -305) (250 250)) + R(via1 (24230 -250) (250 250)) + R(metal2 (-24805 -325) (24880 400)) + J(metal2_lbl FB (-23160 -200)) + ) + N(2 I(OSC) + R(via1 (24435 1675) (250 250)) + R(metal2 (-325 -325) (400 400)) + J(metal2_lbl OSC (-200 -200)) + ) + N(3 I(VSS) + J(metal2_lbl VSS (0 0)) + ) + N(4 I(VDD) + J(metal2_lbl VDD (0 2800)) + ) + N(5) + N(6) + N(7) + N(8) + N(9) + N(10) + N(11) + N(12) + N(13) + N(14) + N(15) + N(16) + N(17) + N(18) + N(19) + N(20) + N(21) + N(22) + P(1 I(FB)) + P(2 I(OSC)) + P(3 I(VSS)) + P(4 I(VDD)) + X(1 INV2 Y(23760 0) + F(#17 #342) + F('a_"non_quoted"_string' '3s') + F('a_float' ##30.5) + P(0 15) + P(1 1) + P(2 2) + P(3 3) + P(4 4) + ) + X(2 INV2 Y(0 0) + P(0 1) + P(1 13) + P(2 14) + P(3 3) + P(4 4) + ) + X(3 INV2 Y(2640 0) + P(0 14) + P(1 12) + P(2 22) + P(3 3) + P(4 4) + ) + X(4 INV2 Y(5280 0) + P(0 22) + P(1 11) + P(2 21) + P(3 3) + P(4 4) + ) + X(5 INV2 Y(7920 0) + P(0 21) + P(1 10) + P(2 20) + P(3 3) + P(4 4) + ) + X(6 INV2 Y(10560 0) + P(0 20) + P(1 9) + P(2 19) + P(3 3) + P(4 4) + ) + X(7 INV2 Y(13200 0) + P(0 19) + P(1 8) + P(2 18) + P(3 3) + P(4 4) + ) + X(8 INV2 Y(15840 0) + P(0 18) + P(1 7) + P(2 17) + P(3 3) + P(4 4) + ) + X(9 INV2 Y(18480 0) + P(0 17) + P(1 6) + P(2 16) + P(3 3) + P(4 4) + ) + X(10 INV2 Y(21120 0) + P(0 16) + P(1 5) + P(2 15) + P(3 3) + P(4 4) + ) +) diff --git a/testdata/algo/l2n_reader_in_s.txt b/testdata/algo/l2n_reader_in_s.txt new file mode 100644 index 000000000..fe37600ce --- /dev/null +++ b/testdata/algo/l2n_reader_in_s.txt @@ -0,0 +1,301 @@ +#%l2n-klayout +W(RINGO) +U(0.001) +L(poly '3/0') +L(poly_lbl '3/1') +L(diff_cont '4/0') +L(poly_cont '5/0') +L(metal1 '6/0') +L(metal1_lbl '6/1') +L(via1 '7/0') +L(metal2 '8/0') +L(metal2_lbl '8/1') +L(psd) +L(nsd) +C(poly poly poly_lbl poly_cont) +C(poly_lbl poly) +C(diff_cont diff_cont metal1 psd nsd) +C(poly_cont poly poly_cont metal1) +C(metal1 diff_cont poly_cont metal1 metal1_lbl via1) +C(metal1_lbl metal1) +C(via1 metal1 via1 metal2) +C(metal2 via1 metal2 metal2_lbl) +C(metal2_lbl metal2) +C(psd diff_cont psd) +C(nsd diff_cont nsd) +K(PMOS MOS3) +K(NMOS MOS3) +D(D$PMOS PMOS + T(S + R(psd (-650 -475) (525 950)) + ) + T(G + R(poly (-125 -475) (250 950)) + ) + T(D + R(psd (125 -475) (550 950)) + ) +) +D(D$PMOS$1 PMOS + T(S + R(psd (-675 -475) (550 950)) + ) + T(G + R(poly (-125 -475) (250 950)) + ) + T(D + R(psd (125 -475) (525 950)) + ) +) +D(D$NMOS NMOS + T(S + R(nsd (-650 -475) (525 950)) + ) + T(G + R(poly (-125 -475) (250 950)) + ) + T(D + R(nsd (125 -475) (550 950)) + ) +) +D(D$NMOS$1 NMOS + T(S + R(nsd (-675 -475) (550 950)) + ) + T(G + R(poly (-125 -475) (250 950)) + ) + T(D + R(nsd (125 -475) (525 950)) + ) +) +X(INV2 + R((-1700 -800) (3100 4600)) + N(1 I(IN) + R(poly (-525 -250) (250 2500)) + R(poly (-1425 -630) (1300 360)) + R(poly (-125 -2780) (250 1600)) + R(poly (-250 1200) (250 1600)) + J(poly_lbl IN (-525 -1800)) + R(poly_cont (-830 -110) (220 220)) + ) + N(2 + R(poly (275 -250) (250 2500)) + R(poly (-305 -1430) (360 360)) + R(poly (-305 820) (250 1600)) + R(poly (-250 -4400) (250 1600)) + R(diff_cont (-1435 1690) (220 220)) + R(diff_cont (-220 180) (220 220)) + R(diff_cont (-220 -3420) (220 220)) + R(diff_cont (-220 180) (220 220)) + R(poly_cont (980 580) (220 220)) + R(metal1 (-1310 -290) (1380 360)) + R(metal1 (-1560 -1600) (360 2840)) + R(metal1 (-360 0) (360 760)) + R(metal1 (-360 -3560) (360 760)) + R(psd (-430 1945) (525 950)) + R(nsd (-525 -3750) (525 950)) + ) + N(3 I(OUT) + R(diff_cont (690 2890) (220 220)) + R(diff_cont (-220 -620) (220 220)) + R(diff_cont (-220 -2620) (220 220)) + R(diff_cont (-220 -620) (220 220)) + Q(metal1 (-110 110) (0 360) (140 0) (0 1240) (-320 0) (0 800) (360 0) (0 -440) (320 0) (0 -1960)) + R(metal1 (-680 2400) (360 760)) + R(metal1 (-360 -3560) (360 760)) + J(metal1_lbl OUT (-180 1420)) + R(psd (-275 525) (525 950)) + R(nsd (-525 -3750) (525 950)) + ) + N(4 + R(diff_cont (-110 -310) (220 220)) + R(diff_cont (-220 180) (220 220)) + R(diff_cont (-220 -220) (220 220)) + R(diff_cont (-220 -620) (220 220)) + R(metal1 (-290 -290) (360 760)) + R(metal1 (-360 -760) (360 760)) + R(via1 (-305 -705) (250 250)) + R(via1 (-250 150) (250 250)) + R(metal2 (-1525 -775) (2800 900)) + R(nsd (-1675 -925) (550 950)) + ) + N(5 + R(diff_cont (-110 2490) (220 220)) + R(diff_cont (-220 180) (220 220)) + R(diff_cont (-220 -220) (220 220)) + R(diff_cont (-220 -620) (220 220)) + R(metal1 (-290 -290) (360 760)) + R(metal1 (-360 -760) (360 760)) + R(via1 (-305 -705) (250 250)) + R(via1 (-250 150) (250 250)) + R(metal2 (-1525 -775) (2800 900)) + R(psd (-1675 -925) (550 950)) + ) + P(1 I(IN)) + P(2) + P(3 I(OUT)) + P(4) + P(5) + D(1 D$PMOS + Y(-400 2800) + E(L 0.25) + E(W 0.95) + E(AS 0.49875) + E(AD 0.26125) + E(PS 2.95) + E(PD 1.5) + T(S 2) + T(G 1) + T(D 5) + ) + D(2 D$PMOS$1 + Y(400 2800) + E(L 0.25) + E(W 0.95) + E(AS 0.26125) + E(AD 0.49875) + E(PS 1.5) + E(PD 2.95) + T(S 5) + T(G 2) + T(D 3) + ) + D(3 D$NMOS + Y(-400 0) + E(L 0.25) + E(W 0.95) + E(AS 0.49875) + E(AD 0.26125) + E(PS 2.95) + E(PD 1.5) + T(S 2) + T(G 1) + T(D 4) + ) + D(4 D$NMOS$1 + Y(400 0) + E(L 0.25) + E(W 0.95) + E(AS 0.26125) + E(AD 0.49875) + E(PS 1.5) + E(PD 2.95) + T(S 4) + T(G 2) + T(D 3) + ) +) +X(RINGO + R((-1720 -800) (26880 4600)) + N(1 I(FB) + R(metal1 (-1700 1620) (360 360)) + R(via1 (-305 -305) (250 250)) + R(via1 (24230 -250) (250 250)) + R(metal2 (-24805 -325) (24880 400)) + J(metal2_lbl FB (-23160 -200)) + ) + N(2 I(OSC) + R(via1 (24435 1675) (250 250)) + R(metal2 (-325 -325) (400 400)) + J(metal2_lbl OSC (-200 -200)) + ) + N(3 I(VSS) + J(metal2_lbl VSS (0 0)) + ) + N(4 I(VDD) + J(metal2_lbl VDD (0 2800)) + ) + N(5) + N(6) + N(7) + N(8) + N(9) + N(10) + N(11) + N(12) + N(13) + N(14) + N(15) + N(16) + N(17) + N(18) + N(19) + N(20) + N(21) + N(22) + P(1 I(FB)) + P(2 I(OSC)) + P(3 I(VSS)) + P(4 I(VDD)) + X(1 INV2 Y(23760 0) + P(0 15) + P(1 1) + P(2 2) + P(3 3) + P(4 4) + ) + X(2 INV2 Y(0 0) + P(0 1) + P(1 13) + P(2 14) + P(3 3) + P(4 4) + ) + X(3 INV2 Y(2640 0) + P(0 14) + P(1 12) + P(2 22) + P(3 3) + P(4 4) + ) + X(4 INV2 Y(5280 0) + P(0 22) + P(1 11) + P(2 21) + P(3 3) + P(4 4) + ) + X(5 INV2 Y(7920 0) + P(0 21) + P(1 10) + P(2 20) + P(3 3) + P(4 4) + ) + X(6 INV2 Y(10560 0) + P(0 20) + P(1 9) + P(2 19) + P(3 3) + P(4 4) + ) + X(7 INV2 Y(13200 0) + P(0 19) + P(1 8) + P(2 18) + P(3 3) + P(4 4) + ) + X(8 INV2 Y(15840 0) + P(0 18) + P(1 7) + P(2 17) + P(3 3) + P(4 4) + ) + X(9 INV2 Y(18480 0) + P(0 17) + P(1 6) + P(2 16) + P(3 3) + P(4 4) + ) + X(10 INV2 Y(21120 0) + P(0 16) + P(1 5) + P(2 15) + P(3 3) + P(4 4) + ) +) diff --git a/testdata/algo/l2n_writer_au.txt b/testdata/algo/l2n_writer_au.txt index a93964577..15276f97a 100644 --- a/testdata/algo/l2n_writer_au.txt +++ b/testdata/algo/l2n_writer_au.txt @@ -95,8 +95,8 @@ circuit(INV2 rect(poly (-1425 -630) (1300 360)) rect(poly (-125 -2780) (250 1600)) rect(poly (-250 1200) (250 1600)) - - rect(poly_cont (-1355 -1910) (220 220)) + text(poly_lbl IN (-525 -1800)) + rect(poly_cont (-830 -110) (220 220)) ) net(2 rect(poly (275 -250) (250 2500)) @@ -123,8 +123,8 @@ circuit(INV2 polygon(metal1 (-110 110) (0 360) (140 0) (0 1240) (-320 0) (0 800) (360 0) (0 -440) (320 0) (0 -1960)) rect(metal1 (-680 2400) (360 760)) rect(metal1 (-360 -3560) (360 760)) - - rect(psd (-455 1945) (525 950)) + text(metal1_lbl OUT (-180 1420)) + rect(psd (-275 525) (525 950)) rect(nsd (-525 -3750) (525 950)) ) net(4 @@ -221,18 +221,18 @@ circuit(RINGO rect(via1 (-305 -305) (250 250)) rect(via1 (24230 -250) (250 250)) rect(metal2 (-24805 -325) (24880 400)) - + text(metal2_lbl FB (-23160 -200)) ) net(2 name(OSC) rect(via1 (24435 1675) (250 250)) rect(metal2 (-325 -325) (400 400)) - + text(metal2_lbl OSC (-200 -200)) ) net(3 name(VSS) - + text(metal2_lbl VSS (0 0)) ) net(4 name(VDD) - + text(metal2_lbl VDD (0 2800)) ) net(5) net(6) diff --git a/testdata/algo/l2n_writer_au_p.txt b/testdata/algo/l2n_writer_au_p.txt index cda14e439..84e52624e 100644 --- a/testdata/algo/l2n_writer_au_p.txt +++ b/testdata/algo/l2n_writer_au_p.txt @@ -76,8 +76,8 @@ X(INV2 R(poly (-1425 -630) (1300 360)) R(poly (-125 -2780) (250 1600)) R(poly (-250 1200) (250 1600)) - - R(poly_cont (-1355 -1910) (220 220)) + J(poly_lbl IN (-525 -1800)) + R(poly_cont (-830 -110) (220 220)) ) N(2 R(poly (275 -250) (250 2500)) @@ -104,8 +104,8 @@ X(INV2 Q(metal1 (-110 110) (0 360) (140 0) (0 1240) (-320 0) (0 800) (360 0) (0 -440) (320 0) (0 -1960)) R(metal1 (-680 2400) (360 760)) R(metal1 (-360 -3560) (360 760)) - - R(psd (-455 1945) (525 950)) + J(metal1_lbl OUT (-180 1420)) + R(psd (-275 525) (525 950)) R(nsd (-525 -3750) (525 950)) ) N(4 @@ -202,18 +202,18 @@ X(RINGO R(via1 (-305 -305) (250 250)) R(via1 (24230 -250) (250 250)) R(metal2 (-24805 -325) (24880 400)) - + J(metal2_lbl FB (-23160 -200)) ) N(2 I(OSC) R(via1 (24435 1675) (250 250)) R(metal2 (-325 -325) (400 400)) - + J(metal2_lbl OSC (-200 -200)) ) N(3 I(VSS) - + J(metal2_lbl VSS (0 0)) ) N(4 I(VDD) - + J(metal2_lbl VDD (0 2800)) ) N(5) N(6) diff --git a/testdata/algo/l2n_writer_au_s.txt b/testdata/algo/l2n_writer_au_s.txt index 91e299a0a..fe37600ce 100644 --- a/testdata/algo/l2n_writer_au_s.txt +++ b/testdata/algo/l2n_writer_au_s.txt @@ -76,8 +76,8 @@ X(INV2 R(poly (-1425 -630) (1300 360)) R(poly (-125 -2780) (250 1600)) R(poly (-250 1200) (250 1600)) - - R(poly_cont (-1355 -1910) (220 220)) + J(poly_lbl IN (-525 -1800)) + R(poly_cont (-830 -110) (220 220)) ) N(2 R(poly (275 -250) (250 2500)) @@ -104,8 +104,8 @@ X(INV2 Q(metal1 (-110 110) (0 360) (140 0) (0 1240) (-320 0) (0 800) (360 0) (0 -440) (320 0) (0 -1960)) R(metal1 (-680 2400) (360 760)) R(metal1 (-360 -3560) (360 760)) - - R(psd (-455 1945) (525 950)) + J(metal1_lbl OUT (-180 1420)) + R(psd (-275 525) (525 950)) R(nsd (-525 -3750) (525 950)) ) N(4 @@ -193,18 +193,18 @@ X(RINGO R(via1 (-305 -305) (250 250)) R(via1 (24230 -250) (250 250)) R(metal2 (-24805 -325) (24880 400)) - + J(metal2_lbl FB (-23160 -200)) ) N(2 I(OSC) R(via1 (24435 1675) (250 250)) R(metal2 (-325 -325) (400 400)) - + J(metal2_lbl OSC (-200 -200)) ) N(3 I(VSS) - + J(metal2_lbl VSS (0 0)) ) N(4 I(VDD) - + J(metal2_lbl VDD (0 2800)) ) N(5) N(6) diff --git a/testdata/python/dbLayoutToNetlist.py b/testdata/python/dbLayoutToNetlist.py index b305d9927..9532591cb 100644 --- a/testdata/python/dbLayoutToNetlist.py +++ b/testdata/python/dbLayoutToNetlist.py @@ -443,7 +443,7 @@ end; l2n = pya.LayoutToNetlist() - infile = os.path.join(ut_testsrc, "testdata", "algo", "l2n_writer_au.txt") + infile = os.path.join(ut_testsrc, "testdata", "algo", "l2n_reader_in.txt") l2n.read(infile) tmp = os.path.join(ut_testtmp, "tmp.txt") diff --git a/testdata/ruby/dbLayoutToNetlist.rb b/testdata/ruby/dbLayoutToNetlist.rb index 41fb7ec56..f161769c1 100644 --- a/testdata/ruby/dbLayoutToNetlist.rb +++ b/testdata/ruby/dbLayoutToNetlist.rb @@ -68,7 +68,7 @@ class DBLayoutToNetlist_TestClass < TestBase # cell mapping with nets l2n = RBA::LayoutToNetlist::new - l2n.read(File.join($ut_testsrc, "testdata", "algo", "l2n_writer_au.txt")) + l2n.read(File.join($ut_testsrc, "testdata", "algo", "l2n_reader_in.txt")) nets = [ l2n.netlist.circuit_by_name("RINGO").net_by_name("VSS"), @@ -481,7 +481,7 @@ END l2n = RBA::LayoutToNetlist::new - input = File.join($ut_testsrc, "testdata", "algo", "l2n_writer_au.txt") + input = File.join($ut_testsrc, "testdata", "algo", "l2n_reader_in.txt") l2n.read(input) tmp = File::join($ut_testtmp, "tmp.txt") @@ -499,7 +499,7 @@ END l2n = RBA::LayoutToNetlist::new - input = File.join($ut_testsrc, "testdata", "algo", "l2n_writer_au.txt") + input = File.join($ut_testsrc, "testdata", "algo", "l2n_reader_in.txt") l2n.read(input) # build_all_nets From daf8e5f8fcf024f264796dbd57497b8b1abb4b15 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 23 May 2020 13:19:46 +0200 Subject: [PATCH 23/35] Bugfix: Region::pull_interacting(edges) wasn't working properly. --- src/db/db/dbAsIfFlatRegion.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index d69bf3959..00053b423 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -496,7 +496,7 @@ AsIfFlatRegion::pull_generic (const Edges &other) const std::auto_ptr output (new FlatEdges (false)); region_to_edge_interaction_filter filter (output->raw_edges (), false); - AddressablePolygonDelivery p (begin (), has_valid_merged_polygons ()); + AddressablePolygonDelivery p (begin (), has_valid_polygons ()); for ( ; ! p.at_end (); ++p) { scanner.insert1 (p.operator-> (), 0); @@ -529,7 +529,7 @@ AsIfFlatRegion::pull_generic (const Texts &other) const std::auto_ptr output (new FlatTexts (false)); region_to_text_interaction_filter filter (output->raw_texts (), false); - AddressablePolygonDelivery p (begin (), has_valid_merged_polygons ()); + AddressablePolygonDelivery p (begin (), has_valid_polygons ()); for ( ; ! p.at_end (); ++p) { scanner.insert1 (p.operator-> (), 0); From 6f7cca81fb533ea0db3361e6b15447485af301a6 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 23 May 2020 13:19:52 +0200 Subject: [PATCH 24/35] Updated test data --- testdata/drc/drcSuiteTests_au3.oas | Bin 1191582 -> 1189162 bytes testdata/drc/drcSuiteTests_au4.oas | Bin 61359 -> 61762 bytes testdata/lvs/inv.lvsdb | 14 +++++++------- testdata/lvs/inv2.lvsdb | 14 +++++++------- testdata/lvs/nand2_split_gate.lvsdb.1 | 16 ++++++++-------- testdata/lvs/nand2_split_gate.lvsdb.2 | 16 ++++++++-------- 6 files changed, 30 insertions(+), 30 deletions(-) diff --git a/testdata/drc/drcSuiteTests_au3.oas b/testdata/drc/drcSuiteTests_au3.oas index 8717c39e93376459b54b4f90545fb4c3f2592d86..50f9a2516df232dfea74d9dbfe63ccc0e3895289 100644 GIT binary patch delta 30531 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 diff --git a/testdata/drc/drcSuiteTests_au4.oas b/testdata/drc/drcSuiteTests_au4.oas index 6a45d564829e83044b16b0bebf86972d55198cbe..5f3a3ad0f555f70dcc599fb650ad53db0c2482a9 100644 GIT binary patch delta 242 zcmZ2~pZU-u<_%IObT=|Hure|(WP70fK$}6#hJo>c&;t1zvOp#y;{vt`G6z(_q6c_> z*vt@|Tz*o~Q)zxE-dwPGqmUG#*CS#>sKl@c6>6>Q z>QY7-QRvQtq_m+%W@Jh!)WoX80d8}@^}Aj3U2J zSJ8MIL*sWGjgv_rEj)$Ra;8kl#%sf1N@8GmHE`Vi~X~sP155AzY^*!!2ho r%&k%Sn68zvVSd3ph=y~WiFg$Y0}{jM^2qc{#8_!5_zzm=ZBhCM)?|T) diff --git a/testdata/lvs/inv.lvsdb b/testdata/lvs/inv.lvsdb index a20e8a4e8..246a05b96 100644 --- a/testdata/lvs/inv.lvsdb +++ b/testdata/lvs/inv.lvsdb @@ -88,7 +88,7 @@ layout( rect(l4 (-800 -3100) (550 400)) rect(l8 (-450 -300) (200 200)) rect(l9 (-300 -300) (400 400)) - + text(l10 IN (-200 -200)) ) net(2 name(VSS) rect(l8 (550 300) (200 200)) @@ -97,8 +97,8 @@ layout( rect(l11 (-250 -950) (200 200)) rect(l11 (-200 300) (200 200)) rect(l12 (-750 -850) (2000 1000)) - - rect(l6 (-1550 -800) (450 900)) + text(l13 VSS (-100 -850)) + rect(l6 (-1450 50) (450 900)) ) net(3 name(VDD) rect(l8 (550 4350) (200 200)) @@ -108,8 +108,8 @@ layout( rect(l11 (-250 -800) (200 200)) rect(l11 (-200 300) (200 200)) rect(l12 (-750 -850) (2000 1000)) - - rect(l2 (-1550 -1700) (450 1500)) + text(l13 VDD (-150 -850)) + rect(l2 (-1400 -850) (450 1500)) ) net(4 name(OUT) rect(l8 (1300 4350) (200 200)) @@ -121,8 +121,8 @@ layout( rect(l9 (-300 -4600) (300 3200)) rect(l9 (-300 -2900) (450 400)) rect(l9 (-450 -1550) (300 850)) - - rect(l2 (-400 3150) (450 1500)) + text(l10 OUT (-50 500)) + rect(l2 (-350 2650) (450 1500)) rect(l6 (-450 -5500) (450 900)) ) net(5 name(NWELL) diff --git a/testdata/lvs/inv2.lvsdb b/testdata/lvs/inv2.lvsdb index c321762cf..3e799862b 100644 --- a/testdata/lvs/inv2.lvsdb +++ b/testdata/lvs/inv2.lvsdb @@ -69,7 +69,7 @@ J( R(l4 (-800 -3100) (550 400)) R(l8 (-450 -300) (200 200)) R(l11 (-300 -300) (400 400)) - + J(l12 IN (-200 -200)) ) N(2 I(VDD) R(l3 (0 2950) (3000 3200)) @@ -85,8 +85,8 @@ J( R(l13 (1400 -700) (200 200)) R(l13 (-200 300) (200 200)) R(l14 (-2350 -850) (3000 1000)) - - R(l2 (-2550 -1700) (450 1500)) + J(l15 VDD (-150 -850)) + R(l2 (-2400 -850) (450 1500)) R(l9 (1050 -1200) (600 1200)) ) N(3 I(OUT) @@ -99,8 +99,8 @@ J( R(l11 (-300 -4600) (300 3200)) R(l11 (-300 -2900) (450 400)) R(l11 (-450 -1550) (300 850)) - - R(l2 (-400 3150) (450 1500)) + J(l12 OUT (-50 500)) + R(l2 (-350 2650) (450 1500)) R(l6 (-450 -5500) (450 900)) ) N(4 I(VSS) @@ -115,8 +115,8 @@ J( R(l13 (1400 -700) (200 200)) R(l13 (-200 300) (200 200)) R(l14 (-2350 -850) (3000 1000)) - - R(l6 (-2550 -800) (450 900)) + J(l15 VSS (-150 -850)) + R(l6 (-2400 50) (450 900)) R(l10 (1050 -900) (600 1200)) ) D(1 D$PMOS diff --git a/testdata/lvs/nand2_split_gate.lvsdb.1 b/testdata/lvs/nand2_split_gate.lvsdb.1 index 6dbde1217..e0d758a88 100644 --- a/testdata/lvs/nand2_split_gate.lvsdb.1 +++ b/testdata/lvs/nand2_split_gate.lvsdb.1 @@ -121,7 +121,7 @@ layout( rect(l4 (-250 300) (250 1050)) rect(l8 (-700 400) (200 200)) rect(l11 (-300 -300) (400 400)) - + text(l12 B (-200 -200)) ) net(2 name(A) rect(l4 (1900 3400) (550 400)) @@ -131,7 +131,7 @@ layout( rect(l4 (-250 300) (250 1050)) rect(l8 (250 1050) (200 200)) rect(l11 (-300 -300) (400 400)) - + text(l12 A (-200 -200)) ) net(3 rect(l8 (1300 300) (200 200)) @@ -167,8 +167,8 @@ layout( rect(l11 (-1200 -300) (1050 300)) rect(l11 (-1050 1150) (300 1400)) rect(l11 (-300 -2700) (300 1950)) - - rect(l2 (-400 -700) (500 1500)) + text(l12 OUT (700 -2000)) + rect(l2 (-1100 1300) (500 1500)) rect(l6 (250 -5500) (450 900)) rect(l6 (-450 450) (450 900)) ) @@ -192,8 +192,8 @@ layout( rect(l13 (700 -700) (200 200)) rect(l13 (-200 300) (200 200)) rect(l14 (-3150 -850) (3750 1000)) - - rect(l2 (-3300 -1700) (450 1500)) + text(l15 VDD (-100 -850)) + rect(l2 (-3200 -850) (450 1500)) rect(l2 (1000 -1500) (450 1500)) rect(l9 (400 -1200) (600 1200)) ) @@ -212,8 +212,8 @@ layout( rect(l13 (2200 -700) (200 200)) rect(l13 (-200 300) (200 200)) rect(l14 (-3150 -850) (3750 1000)) - - rect(l6 (-3300 550) (450 900)) + text(l15 VSS (-100 -850)) + rect(l6 (-3200 1400) (450 900)) rect(l6 (-450 -2250) (450 900)) rect(l10 (1850 -900) (600 1200)) ) diff --git a/testdata/lvs/nand2_split_gate.lvsdb.2 b/testdata/lvs/nand2_split_gate.lvsdb.2 index 382f1cc89..4742977a2 100644 --- a/testdata/lvs/nand2_split_gate.lvsdb.2 +++ b/testdata/lvs/nand2_split_gate.lvsdb.2 @@ -121,7 +121,7 @@ layout( rect(l4 (-250 300) (250 1050)) rect(l8 (-700 400) (200 200)) rect(l11 (-300 -300) (400 400)) - + text(l12 B (-200 -200)) ) net(2 name(A) rect(l4 (1900 3400) (550 400)) @@ -131,7 +131,7 @@ layout( rect(l4 (-250 300) (250 1050)) rect(l8 (250 1050) (200 200)) rect(l11 (-300 -300) (400 400)) - + text(l12 A (-200 -200)) ) net(3 rect(l8 (1300 300) (200 200)) @@ -167,8 +167,8 @@ layout( rect(l11 (-1200 -300) (1050 300)) rect(l11 (-1050 1150) (300 1400)) rect(l11 (-300 -2700) (300 1950)) - - rect(l2 (-400 -700) (500 1500)) + text(l12 OUT (700 -2000)) + rect(l2 (-1100 1300) (500 1500)) rect(l6 (250 -5500) (450 900)) rect(l6 (-450 450) (450 900)) ) @@ -192,8 +192,8 @@ layout( rect(l13 (700 -700) (200 200)) rect(l13 (-200 300) (200 200)) rect(l14 (-3150 -850) (3750 1000)) - - rect(l2 (-3300 -1700) (450 1500)) + text(l15 VDD (-100 -850)) + rect(l2 (-3200 -850) (450 1500)) rect(l2 (1000 -1500) (450 1500)) rect(l9 (400 -1200) (600 1200)) ) @@ -212,8 +212,8 @@ layout( rect(l13 (2200 -700) (200 200)) rect(l13 (-200 300) (200 200)) rect(l14 (-3150 -850) (3750 1000)) - - rect(l6 (-3300 550) (450 900)) + text(l15 VSS (-100 -850)) + rect(l6 (-3200 1400) (450 900)) rect(l6 (-450 -2250) (450 900)) rect(l10 (1850 -900) (600 1200)) ) From 5135d76367b91ef3db71dc3138c9321dba517952 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 23 May 2020 13:31:26 +0200 Subject: [PATCH 25/35] Updated test data. --- testdata/drc/drcSuiteTests_au1.oas | Bin 13479 -> 13529 bytes testdata/drc/drcSuiteTests_au2.oas | Bin 61099 -> 61677 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/testdata/drc/drcSuiteTests_au1.oas b/testdata/drc/drcSuiteTests_au1.oas index 636910e6b5d6ea37462d40d1ceffe5d64ce98160..2288862ffbd3223fcadbaefb5086810f7f7029ac 100644 GIT binary patch delta 252 zcmZ3Uc{6jvPTh>38<`nc85j@ntQ0wEEM~#L_=D>v%R?7214hP~f*U!-Y#6~JH~qO8 zQ?$kW1;lI^7%%c~RBAK=3b?b_ih%TNWkMO;Mu4IR0ouQAk=8osSc7q$g@zMn<2%Y4J3S!=OsHt!2-60@*oE>GA>}7 zXu41y#9GL9P_x|?7;gf_8ohzq_*p=TL8gEt7#SxpuM}zYW&kmN za(&c0Y0S--@_=yzqnHK*Q2RkUJCO1NJS#;&wlD%&8{|DXrbFSA1AgD8-CpnX7f@|v@9 z>OiL) delta 282 zcmaF+ka_i8<_(9A*ZwJ1`Lcd1utAx2I-ihJ|@Ks6wT1H}*W-1r01D{8xmnUU=P&qe+pTn~hRrm%g` iTfoLBBQwFTLtWHnvWANI Date: Sat, 23 May 2020 16:23:40 +0200 Subject: [PATCH 26/35] Tiling processor enabling for text input/output, updated tests. --- src/db/db/dbAsIfFlatEdges.cc | 4 +- src/db/db/dbAsIfFlatTexts.cc | 2 +- src/db/db/dbTilingProcessor.cc | 95 +++++++++++++++++++---- src/db/db/dbTilingProcessor.h | 33 +++++++- src/db/db/gsiDeclDbTilingProcessor.cc | 107 +++++++++++++++++++++++--- testdata/drc/.drcSuiteTests.drc.swp | Bin 0 -> 36864 bytes testdata/drc/.drctest.drc.swp | Bin 0 -> 16384 bytes testdata/drc/drcSuiteTests.drc | 40 ++++++++++ testdata/drc/drcSuiteTests_au1.oas | Bin 13529 -> 13710 bytes testdata/drc/drcSuiteTests_au2.oas | Bin 61677 -> 62065 bytes testdata/drc/drcSuiteTests_au3.oas | Bin 1189162 -> 1192903 bytes testdata/drc/drcSuiteTests_au4.oas | Bin 61762 -> 61941 bytes testdata/drc/drcSuiteTests_au5.oas | Bin 13331 -> 13509 bytes testdata/drc/drcSuiteTests_au6.oas | Bin 19829 -> 20007 bytes testdata/drc/drctest.gds | Bin 3064 -> 3128 bytes 15 files changed, 250 insertions(+), 31 deletions(-) create mode 100644 testdata/drc/.drcSuiteTests.drc.swp create mode 100644 testdata/drc/.drctest.drc.swp diff --git a/src/db/db/dbAsIfFlatEdges.cc b/src/db/db/dbAsIfFlatEdges.cc index 9cb62ba1a..588eaf462 100644 --- a/src/db/db/dbAsIfFlatEdges.cc +++ b/src/db/db/dbAsIfFlatEdges.cc @@ -180,7 +180,7 @@ AsIfFlatEdges::pull_generic (const Edges &edges) const { db::box_scanner scanner (report_progress (), progress_desc ()); - AddressableEdgeDelivery e (begin (), true); + AddressableEdgeDelivery e (begin (), has_valid_edges ()); for ( ; ! e.at_end (); ++e) { scanner.insert (e.operator-> (), 1); @@ -507,7 +507,7 @@ AsIfFlatEdges::run_check (db::edge_relation_type rel, const Edges *other, db::Co db::box_scanner scanner (report_progress (), progress_desc ()); scanner.reserve (size () + (other ? other->size () : 0)); - AddressableEdgeDelivery e (begin_merged (), has_valid_edges ()); + AddressableEdgeDelivery e (begin_merged (), has_valid_merged_edges ()); size_t n = 0; for ( ; ! e.at_end (); ++e) { diff --git a/src/db/db/dbAsIfFlatTexts.cc b/src/db/db/dbAsIfFlatTexts.cc index a3b8a1958..fe9c86da3 100644 --- a/src/db/db/dbAsIfFlatTexts.cc +++ b/src/db/db/dbAsIfFlatTexts.cc @@ -342,7 +342,7 @@ AsIfFlatTexts::pull_generic (const Region &other) const db::box_scanner2 scanner (report_progress (), progress_desc ()); - AddressableTextDelivery e (begin (), true); + AddressableTextDelivery e (begin (), has_valid_texts ()); for ( ; ! e.at_end (); ++e) { scanner.insert1 (e.operator-> (), 0); diff --git a/src/db/db/dbTilingProcessor.cc b/src/db/db/dbTilingProcessor.cc index 7682293eb..db3604562 100644 --- a/src/db/db/dbTilingProcessor.cc +++ b/src/db/db/dbTilingProcessor.cc @@ -164,6 +164,34 @@ private: const db::ICplxTrans m_trans; }; +/** + * @brief A helper class for the generic implementation of the text collection insert functionality + */ +class TextsInserter +{ +public: + TextsInserter (db::Texts *texts, const db::ICplxTrans &trans) + : mp_texts (texts), m_trans (trans) + { + // .. nothing yet .. + } + + template + void operator() (const T &) + { + // .. discard anything except Texts .. + } + + void operator() (const db::Text &t) + { + mp_texts->insert (t.transformed (m_trans)); + } + +private: + db::Texts *mp_texts; + const db::ICplxTrans m_trans; +}; + class TileLayoutOutputReceiver : public db::TileOutputReceiver { @@ -271,6 +299,26 @@ private: db::EdgePairs *mp_edge_pairs; }; +class TileTextsOutputReceiver + : public db::TileOutputReceiver +{ +public: + TileTextsOutputReceiver (db::Texts *texts) + : mp_texts (texts) + { + // .. nothing yet .. + } + + void put (size_t /*ix*/, size_t /*iy*/, const db::Box &tile, size_t /*id*/, const tl::Variant &obj, double /*dbu*/, const db::ICplxTrans &trans, bool clip) + { + TextsInserter inserter (mp_texts, trans); + insert_var (inserter, obj, tile, clip); + } + +private: + db::Texts *mp_texts; +}; + class TilingProcessorJob : public tl::JobBase { @@ -395,6 +443,7 @@ private: TilingProcessorJob *mp_job; void do_perform (const TilingProcessorTask *task); + void make_input_var (const TilingProcessor::InputSpec &is, const db::RecursiveShapeIterator *iter, tl::Eval &eval, double sf); }; class TilingProcessorReceiverFunction @@ -452,6 +501,24 @@ public: } }; +void +TilingProcessorWorker::make_input_var (const TilingProcessor::InputSpec &is, const db::RecursiveShapeIterator *iter, tl::Eval &eval, double sf) +{ + if (! iter) { + iter = &is.iter; + } + + if (is.type == TilingProcessor::TypeRegion) { + eval.set_var (is.name, tl::Variant (db::Region (*iter, db::ICplxTrans (sf) * is.trans, is.merged_semantics))); + } else if (is.type == TilingProcessor::TypeEdges) { + eval.set_var (is.name, tl::Variant (db::Edges (*iter, db::ICplxTrans (sf) * is.trans, is.merged_semantics))); + } else if (is.type == TilingProcessor::TypeEdgePairs) { + eval.set_var (is.name, tl::Variant (db::EdgePairs (*iter, db::ICplxTrans (sf) * is.trans))); + } else if (is.type == TilingProcessor::TypeTexts) { + eval.set_var (is.name, tl::Variant (db::Texts (*iter, db::ICplxTrans (sf) * is.trans))); + } +} + void TilingProcessorWorker::do_perform (const TilingProcessorTask *tile_task) { @@ -492,11 +559,7 @@ TilingProcessorWorker::do_perform (const TilingProcessorTask *tile_task) if (! mp_job->has_tiles ()) { - if (i->region) { - eval.set_var (i->name, tl::Variant (db::Region (i->iter, db::ICplxTrans (sf) * i->trans, i->merged_semantics))); - } else { - eval.set_var (i->name, tl::Variant (db::Edges (i->iter, db::ICplxTrans (sf) * i->trans, i->merged_semantics))); - } + make_input_var (*i, 0, eval, sf); } else { @@ -509,11 +572,7 @@ TilingProcessorWorker::do_perform (const TilingProcessorTask *tile_task) iter.confine_region (region_dbu); } - if (i->region) { - eval.set_var (i->name, tl::Variant (db::Region (iter, db::ICplxTrans (sf) * i->trans, i->merged_semantics))); - } else { - eval.set_var (i->name, tl::Variant (db::Edges (iter, db::ICplxTrans (sf) * i->trans, i->merged_semantics))); - } + make_input_var (*i, &iter, eval, sf); } @@ -559,7 +618,7 @@ TilingProcessor::TilingProcessor () } void -TilingProcessor::input (const std::string &name, const db::RecursiveShapeIterator &iter, const db::ICplxTrans &trans, bool as_region, bool merged_semantics) +TilingProcessor::input (const std::string &name, const db::RecursiveShapeIterator &iter, const db::ICplxTrans &trans, Type type, bool merged_semantics) { if (m_inputs.empty () && iter.layout ()) { m_dbu = iter.layout ()->dbu (); @@ -568,7 +627,7 @@ TilingProcessor::input (const std::string &name, const db::RecursiveShapeIterato m_inputs.back ().name = name; m_inputs.back ().iter = iter; m_inputs.back ().trans = trans; - m_inputs.back ().region = as_region; + m_inputs.back ().type = type; m_inputs.back ().merged_semantics = merged_semantics; } @@ -699,7 +758,17 @@ TilingProcessor::output (const std::string &name, db::EdgePairs &edge_pairs) m_outputs.back ().receiver = new TileEdgePairsOutputReceiver (&edge_pairs); } -void +void +TilingProcessor::output (const std::string &name, db::Texts &texts) +{ + m_top_eval.set_var (name, m_outputs.size ()); + m_outputs.push_back (OutputSpec ()); + m_outputs.back ().name = name; + m_outputs.back ().id = 0; + m_outputs.back ().receiver = new TileTextsOutputReceiver (&texts); +} + +void TilingProcessor::output (const std::string &name, db::Edges &edges) { m_top_eval.set_var (name, m_outputs.size ()); diff --git a/src/db/db/dbTilingProcessor.h b/src/db/db/dbTilingProcessor.h index 0419f74a8..7a4359d34 100644 --- a/src/db/db/dbTilingProcessor.h +++ b/src/db/db/dbTilingProcessor.h @@ -346,6 +346,20 @@ void insert (X &inserter, const db::EdgePairs &data, const db::Box &tile, bool c } } +/** + * @brief Delivery of tiling processor output + * This utility is put between the container and the receiver. + * The inserter is an object having an operator() that takes the object. + * This function is responsible for preparing (i.e. clipping) and delivering the output. + */ +template +void insert (X &inserter, const db::Texts &data, const db::Box &tile, bool clip) +{ + for (db::Texts::const_iterator o = data.begin (); ! o.at_end (); ++o) { + insert (inserter, *o, tile, clip); + } +} + /** * @brief Delivery of tiling processor output * This utility is put between the container and the receiver. @@ -364,6 +378,9 @@ bool insert_var (X &inserter, const tl::Variant &obj, const db::Box &tile, bool } else if (obj.is_user ()) { insert (inserter, obj.to_user (), tile, clip); return true; + } else if (obj.is_user ()) { + insert (inserter, obj.to_user (), tile, clip); + return true; } else if (obj.is_user ()) { insert (inserter, obj.to_user (), tile, clip); return true; @@ -417,6 +434,8 @@ bool insert_var (X &inserter, const tl::Variant &obj, const db::Box &tile, bool class DB_PUBLIC TilingProcessor { public: + enum Type { TypeRegion, TypeEdges, TypeEdgePairs, TypeTexts }; + /** * @brief Constructor */ @@ -441,7 +460,7 @@ public: * The transformation can be used to convert between database units. * If "as_region" is false, the input is taken as edge input. */ - void input (const std::string &name, const db::RecursiveShapeIterator &iter, const db::ICplxTrans &trans = db::ICplxTrans (), bool as_region = true, bool merged_semantics = true); + void input (const std::string &name, const db::RecursiveShapeIterator &iter, const db::ICplxTrans &trans = db::ICplxTrans (), Type type = TypeRegion, bool merged_semantics = true); /** * @brief Specifies the output @@ -489,6 +508,14 @@ public: */ void output (const std::string &name, db::EdgePairs &edge_pairs); + /** + * @brief Specifies output to an text collection + * + * This version will specify output to a Texts object. + * Only texts will be stored. + */ + void output (const std::string &name, db::Texts &texts); + /** * @brief Specifies output to an edge collection * @@ -624,11 +651,11 @@ private: struct InputSpec { - InputSpec () : region (false), merged_semantics (false) { } + InputSpec () : type (TilingProcessor::TypeRegion), merged_semantics (false) { } std::string name; db::RecursiveShapeIterator iter; db::ICplxTrans trans; - bool region; + TilingProcessor::Type type; bool merged_semantics; }; diff --git a/src/db/db/gsiDeclDbTilingProcessor.cc b/src/db/db/gsiDeclDbTilingProcessor.cc index bfa92fc79..13e525f19 100644 --- a/src/db/db/gsiDeclDbTilingProcessor.cc +++ b/src/db/db/gsiDeclDbTilingProcessor.cc @@ -255,6 +255,11 @@ static void tp_output_edge_pairs (db::TilingProcessor *proc, const std::string & proc->output (name, edge_pairs); } +static void tp_output_texts (db::TilingProcessor *proc, const std::string &name, db::Texts &texts) +{ + proc->output (name, texts); +} + static void tp_output_double (db::TilingProcessor *proc, const std::string &name, double *v) { proc->output (name, 0, new DoubleCollectingTileOutputReceiver (v), db::ICplxTrans ()); @@ -311,25 +316,49 @@ static void tp_input7 (db::TilingProcessor *proc, const std::string &name, const static void tp_input8 (db::TilingProcessor *proc, const std::string &name, const db::Region ®ion) { std::pair it = region.begin_iter (); - proc->input (name, it.first, it.second, true /*as polygons*/, region.merged_semantics ()); + proc->input (name, it.first, it.second, db::TilingProcessor::TypeRegion, region.merged_semantics ()); } static void tp_input9 (db::TilingProcessor *proc, const std::string &name, const db::Region ®ion, const db::ICplxTrans &trans) { std::pair it = region.begin_iter (); - proc->input (name, it.first, trans * it.second, true /*as polygons*/, region.merged_semantics ()); + proc->input (name, it.first, trans * it.second, db::TilingProcessor::TypeRegion, region.merged_semantics ()); } static void tp_input10 (db::TilingProcessor *proc, const std::string &name, const db::Edges &edges) { std::pair it = edges.begin_iter (); - proc->input (name, it.first, it.second, false /*not as polygons*/, edges.merged_semantics ()); + proc->input (name, it.first, it.second, db::TilingProcessor::TypeEdges, edges.merged_semantics ()); } static void tp_input11 (db::TilingProcessor *proc, const std::string &name, const db::Edges &edges, const db::ICplxTrans &trans) { std::pair it = edges.begin_iter (); - proc->input (name, it.first, trans * it.second, false /*not as polygons*/, edges.merged_semantics ()); + proc->input (name, it.first, trans * it.second, db::TilingProcessor::TypeEdges, edges.merged_semantics ()); +} + +static void tp_input12 (db::TilingProcessor *proc, const std::string &name, const db::EdgePairs &edge_pairs) +{ + std::pair it = edge_pairs.begin_iter (); + proc->input (name, it.first, it.second, db::TilingProcessor::TypeEdgePairs); +} + +static void tp_input13 (db::TilingProcessor *proc, const std::string &name, const db::EdgePairs &edge_pairs, const db::ICplxTrans &trans) +{ + std::pair it = edge_pairs.begin_iter (); + proc->input (name, it.first, trans * it.second, db::TilingProcessor::TypeEdgePairs); +} + +static void tp_input14 (db::TilingProcessor *proc, const std::string &name, const db::Texts &texts) +{ + std::pair it = texts.begin_iter (); + proc->input (name, it.first, it.second, db::TilingProcessor::TypeTexts); +} + +static void tp_input15 (db::TilingProcessor *proc, const std::string &name, const db::Texts &texts, const db::ICplxTrans &trans) +{ + std::pair it = texts.begin_iter (); + proc->input (name, it.first, trans * it.second, db::TilingProcessor::TypeTexts); } Class decl_TilingProcessor ("db", "TilingProcessor", @@ -385,16 +414,16 @@ Class decl_TilingProcessor ("db", "TilingProcessor", method_ext ("input", &tp_input8, gsi::arg ("name"), gsi::arg ("region"), "@brief Specifies input for the tiling processor\n" "This method will establish an input channel for the processor. This version receives input from a \\Region object. " - "Regions don't always come with a database unit, hence a database unit should be specified with the \\dbu= method if only " - "regions and edges are used as input.\n" + "Regions don't always come with a database unit, hence a database unit should be specified with the \\dbu= method unless " + "a layout object is specified as input too.\n" "\n" "The name specifies the variable under which the input can be used in the scripts." ) + method_ext ("input", &tp_input9, gsi::arg ("name"), gsi::arg ("region"), gsi::arg ("trans"), "@brief Specifies input for the tiling processor\n" "This method will establish an input channel for the processor. This version receives input from a \\Region object. " - "Regions don't always come with a database unit, hence a database unit should be specified with the \\dbu= method if only " - "regions and edges are used as input.\n" + "Regions don't always come with a database unit, hence a database unit should be specified with the \\dbu= method unless " + "a layout object is specified as input too.\n" "\n" "The name specifies the variable under which the input can be used in the scripts." "\n" @@ -403,22 +432,62 @@ Class decl_TilingProcessor ("db", "TilingProcessor", method_ext ("input", &tp_input10, gsi::arg ("name"), gsi::arg ("edges"), "@brief Specifies input for the tiling processor\n" "This method will establish an input channel for the processor. This version receives input from an \\Edges object. " - "Edge collections don't always come with a database unit, hence a database unit should be specified with the \\dbu= method if only " - "regions and edges are used as input.\n" + "Edge collections don't always come with a database unit, hence a database unit should be specified with the \\dbu= method unless " + "a layout object is specified as input too.\n" "\n" "The name specifies the variable under which the input can be used in the scripts." ) + method_ext ("input", &tp_input11, gsi::arg ("name"), gsi::arg ("edges"), gsi::arg ("trans"), "@brief Specifies input for the tiling processor\n" "This method will establish an input channel for the processor. This version receives input from an \\Edges object. " - "Edge collections don't always come with a database unit, hence a database unit should be specified with the \\dbu= method if only " - "regions and edges are used as input.\n" + "Edge collections don't always come with a database unit, hence a database unit should be specified with the \\dbu= method unless " + "a layout object is specified as input too.\n" "\n" "The name specifies the variable under which the input can be used in the scripts." "\n" "This variant allows one to specify an additional transformation too. It has been introduced in version 0.23.2.\n" "\n" ) + + method_ext ("input", &tp_input12, gsi::arg ("name"), gsi::arg ("edge_pairs"), + "@brief Specifies input for the tiling processor\n" + "This method will establish an input channel for the processor. This version receives input from an \\EdgePairs object. " + "Edge pair collections don't always come with a database unit, hence a database unit should be specified with the \\dbu= method unless " + "a layout object is specified as input too.\n" + "\n" + "The name specifies the variable under which the input can be used in the scripts." + "\n" + "This variant has been introduced in version 0.27.\n" + ) + + method_ext ("input", &tp_input13, gsi::arg ("name"), gsi::arg ("edge_pairs"), gsi::arg ("trans"), + "@brief Specifies input for the tiling processor\n" + "This method will establish an input channel for the processor. This version receives input from an \\EdgePairs object. " + "Edge pair collections don't always come with a database unit, hence a database unit should be specified with the \\dbu= method unless " + "a layout object is specified as input too.\n" + "\n" + "The name specifies the variable under which the input can be used in the scripts." + "\n" + "This variant has been introduced in version 0.27.\n" + ) + + method_ext ("input", &tp_input14, gsi::arg ("name"), gsi::arg ("texts"), + "@brief Specifies input for the tiling processor\n" + "This method will establish an input channel for the processor. This version receives input from an \\Texts object. " + "Text collections don't always come with a database unit, hence a database unit should be specified with the \\dbu= method unless " + "a layout object is specified as input too.\n" + "\n" + "The name specifies the variable under which the input can be used in the scripts." + "\n" + "This variant has been introduced in version 0.27.\n" + ) + + method_ext ("input", &tp_input15, gsi::arg ("name"), gsi::arg ("texts"), gsi::arg ("trans"), + "@brief Specifies input for the tiling processor\n" + "This method will establish an input channel for the processor. This version receives input from an \\Texts object. " + "Text collections don't always come with a database unit, hence a database unit should be specified with the \\dbu= method unless " + "a layout object is specified as input too.\n" + "\n" + "The name specifies the variable under which the input can be used in the scripts." + "\n" + "This variant has been introduced in version 0.27.\n" + ) + method ("var", &db::TilingProcessor::var, gsi::arg ("name"), gsi::arg ("value"), "@brief Defines a variable for the tiling processor script\n" "\n" @@ -525,6 +594,20 @@ Class decl_TilingProcessor ("db", "TilingProcessor", "@param name The name of the channel\n" "@param edge_pairs The \\EdgePairs object to which the data is sent\n" ) + + method_ext ("output", &tp_output_texts, gsi::arg ("name"), gsi::arg ("texts"), + "@brief Specifies output to an \\Texts object\n" + "This method will establish an output channel to an \\Texts object. The output sent to that channel " + "will be put into the specified edge pair collection.\n" + "Only \\Text objects are accepted. Other objects are discarded.\n" + "\n" + "The name is the name which must be used in the _output function of the scripts in order to " + "address that channel.\n" + "\n" + "@param name The name of the channel\n" + "@param texts The \\Texts object to which the data is sent\n" + "\n" + "This variant has been introduced in version 0.27." + ) + method_ext ("output", &tp_output_double, gsi::arg ("name"), gsi::arg ("sum"), "@brief Specifies output to single value\n" "This method will establish an output channel which sums up float data delivered by calling the _output function.\n" diff --git a/testdata/drc/.drcSuiteTests.drc.swp b/testdata/drc/.drcSuiteTests.drc.swp new file mode 100644 index 0000000000000000000000000000000000000000..fd3a3af2f0e88356c2a0181773152b009977fb83 GIT binary patch literal 36864 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 TdDJGn*%r&-ztti&wY~ilt(p?X literal 0 HcmV?d00001 diff --git a/testdata/drc/drcSuiteTests.drc b/testdata/drc/drcSuiteTests.drc index be4c43ed6..969736ce9 100644 --- a/testdata/drc/drcSuiteTests.drc +++ b/testdata/drc/drcSuiteTests.drc @@ -15,8 +15,10 @@ def run_testsuite(dm, ic, tiled = false, hier = false) lb = 100 a = polygons(RBA::LayerInfo::new(1, 0)) + at = labels(1) b = polygons(2) c = polygons(3) + d = polygons(4) x = polygons(10) y = polygons(11) empty = polygons(1000) @@ -605,6 +607,44 @@ def run_testsuite(dm, ic, tiled = false, hier = false) p = b.edges.intersections(c.edges) p.output(lb + 5, dm) + lb += 10 #450 + message "--- texts and filters #{lb}" + + p = at + p.output(lb, dm) + p = at.texts + p.output(lb + 1, dm) + p = at.texts("A*") + p.output(lb + 2, dm) + p = at.texts(pattern("A*")) + p.output(lb + 3, dm) + p = at.texts(pattern("A*"), as_dots) + p.output(lb + 4, dm) + p = at.texts(text("A*"), as_boxes) + p.output(lb + 5, dm) + p = at.texts_not("A*") + p.output(lb + 6, dm) + p = at.texts_not(pattern("A*")) + p.output(lb + 7, dm) + p = at.texts_not(pattern("A*"), as_dots) + p.output(lb + 8, dm) + p = at.texts_not(text("A*"), as_boxes) + p.output(lb + 9, dm) + + lb += 10 #460 + message "--- texts and polygon booleans and interactions #{lb}" + + p = at & d + p.output(lb, dm) + p = d.interacting(at) + p.output(lb + 1, dm) + p = at.interacting(d) + p.output(lb + 2, dm) + p = d.pull_interacting(at) + p.output(lb + 3, dm) + p = at.pull_interacting(d) + p.output(lb + 4, dm) + end if $drc_test_mode == 1 diff --git a/testdata/drc/drcSuiteTests_au1.oas b/testdata/drc/drcSuiteTests_au1.oas index 2288862ffbd3223fcadbaefb5086810f7f7029ac..4dfbe6425458a07f02db4ec668a7d6e8c8a6b35f 100644 GIT binary patch delta 206 zcmcba*_S<`oST)&(GiHXSQ(u*mM0n43s*B8VrIC=zffMdg5jg+Pi5f(#*6&InM{Y7 z(S#I_Fbfv|l?WFy9%Tk90kOqwk1;bcg7tATOkfrexp|zK=`#OsW#LMu6F@~kBNR_E zi%FgWvqk2fX8tVtTbY|7MUYKc@eH$Yh7RLTWs%CW%zIeRaLg2(sRgw79LVAfpg53y X9>x}7yui#f`JwT*$sdf_nHU%Vv`#=o delta 21 ccmeCnzL`0pd}C9RF(cFDi6*~U8X6cF0BRu!WdHyG diff --git a/testdata/drc/drcSuiteTests_au2.oas b/testdata/drc/drcSuiteTests_au2.oas index f02a197396f48ece455842d5413ae58663dee28c..0f41d4df2b7d60f561d2bb97a554e46f9b90e0a3 100644 GIT binary patch delta 418 zcmZY5Jxjw-6b9gP?=gN=@#9{j)KsDp3jT#67=M7jM8QEfL*kY}Y z(wW;bbVkKy@@fm1zEq2CRAk$!*iTS#*P&Crb&@Z4k#BaB7kbDad&$2A`C1?Oo=JY& zPu>_HUrLg143g(9@=A*QYlwW+Cf^;_>E~`nsCXF#`EZ83?AB~%S!yaw3y&A||IrDY za|APW@jJ=vC2nVGHpum|dq{0bpJbZp%SrDF4~$Z4I8jW}0n70L<4RB0f0HyK1Reyz L%18av&~JbrXqbLV delta 16 YcmezPg!%15<_WbMI||+}F8s&{08_3BRR910 diff --git a/testdata/drc/drcSuiteTests_au3.oas b/testdata/drc/drcSuiteTests_au3.oas index 50f9a2516df232dfea74d9dbfe63ccc0e3895289..19c82e62240c0e049a60d4d0808a2156da74d2b1 100644 GIT binary patch delta 29049 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 delta 26560 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 Ik|`+YpVpQdMgRZ+ diff --git a/testdata/drc/drcSuiteTests_au4.oas b/testdata/drc/drcSuiteTests_au4.oas index 5f3a3ad0f555f70dcc599fb650ad53db0c2482a9..4feb67d3f5781f17df10c865c9729ff9d078ad57 100644 GIT binary patch delta 198 zcmX@~i23Vd<_WdjtW1uMK&-{e=(Mr+==*x%dZt6n3>O>^s4@uGFl?}Xp}-(q!g#@v zK{%J`Ff*p8>Jet30-!<$;Znw<%piqep2*$f%uMGTp8>VkGMxa5gS4uiWM&YVdYXBi zHG{~UbB_B!LT7;ba~Ofvh}52C-lM^KhNHvbgcQiSb71ShazNgB1W$zZ0`q3a4~&ce D`35`- delta 25 hcmezRnEB8n<_WbMJC43*WSY$Q@zZ31kK9ZQ3;?k*3zz@^ diff --git a/testdata/drc/drcSuiteTests_au5.oas b/testdata/drc/drcSuiteTests_au5.oas index c596d626f66f68d2ec28f950bf7a6b9b1d9acebe..c3f8dba2c6ba729109ef711aea9685da1b9d518b 100644 GIT binary patch delta 203 zcmbQ7aWr#6IX5elqazS&u`)VsET3akFI>%Zh?(Ic|3Z1;3WkrOKb3_G7%%b*XEGgT zMiWvz!Yo_>R3co+c$68a1jH7zJ;uz)2-e5VFo9V>1FjZi$v zEGBsh%odq@n)$QnZ)I+V6hSs&#WT#p8Jdhgl|?GgGVftM!!c8ErWVlRb0CW|fa1c6 b=YcAi7Rrk-USMXLtZ4jUvVk!#69WSP`U^dS delta 23 fcmX?_IXPoO`NpO>MvP38FB*TE{J@x-iGcwCgg*&! diff --git a/testdata/drc/drcSuiteTests_au6.oas b/testdata/drc/drcSuiteTests_au6.oas index bf3a28492f4ab8495330340596b4fe3802c805d1..9cd6913eeaf2f5cf822a29eb353679ffa7c272b3 100644 GIT binary patch delta 198 zcmex5i*flJ#tBW_tW1uMK&-{e=(MpZ!LVMqn&}WT!$tmu^1>AiA4PvE3l}h6I6@)VdYGWRs|XVKrv+zcs#Y{H6Xn1wSm7=J2@RGwwt!+M5err=C1pvC7v7H0s( Wg%!^ORWL1-7h$}>y!nygWN84sXg!<& delta 17 ZcmZ2Jhw=*FmRtZ^I+3~ani3@i+6d`t`s3_1eL|NsBq^8f$W z5(xeC!2kdM3jY6x(J=9^B@8Tr3=Ayn4EXGyT*X~2jmLeHuW|L_a^B<$E@x&I76t$w CNJc&Y delta 227 zcmdlX@k2a{fsKKQDS|{L4=vr&auYBy5yxTg Date: Sat, 23 May 2020 16:23:54 +0200 Subject: [PATCH 27/35] WIP: doc update --- src/lay/lay/doc/manual/drc_basic.xml | 1 + src/lay/lay/doc/manual/drc_runsets.xml | 62 ++++++++++++++++++++++++-- 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/src/lay/lay/doc/manual/drc_basic.xml b/src/lay/lay/doc/manual/drc_basic.xml index 2d3a31b6a..4fe88fc7a 100644 --- a/src/lay/lay/doc/manual/drc_basic.xml +++ b/src/lay/lay/doc/manual/drc_basic.xml @@ -20,6 +20,7 @@

  • Support for edge objects derived from polygons or as output from other functions. Edge objects are useful to implement edge-related operations, for example selective sizing.
  • The capability the work with multiple input layouts.
  • +
  • Support for text object layers. Text objects are convenient for tagging polygons or labelling nets.
  • Cell filtering, local (region-constrained) operation.
  • A tiling approach for large layouts which can be configured to make use of multiple CPU cores.
  • A hierarchical option.
  • diff --git a/src/lay/lay/doc/manual/drc_runsets.xml b/src/lay/lay/doc/manual/drc_runsets.xml index 57ede77ad..fc928a702 100644 --- a/src/lay/lay/doc/manual/drc_runsets.xml +++ b/src/lay/lay/doc/manual/drc_runsets.xml @@ -329,6 +329,8 @@ output(w, "width violations")
    select, clip, input, + labels, + polygons, output, report, target @@ -362,6 +364,7 @@ output(w, "width violations") in, inside, interacting, + pull_interacting, outside, touching, overlapping
    @@ -395,6 +398,10 @@ output(w, "width violations") without_angle, without_length +
  • Text filters:
    + texts, + texts_not, +
  • Transformations:
    moved, rotated, @@ -444,11 +451,21 @@ output(w, "width violations")
  • -

    Edge and polygon layers

    +

    Polygon and edge layers

    - KLayout knows two basic layer types: polygon and edge layers. - Input from layout is always of polygon type initially. + KLayout knows four layer types: polygon, edge, edge pair and text layers. + Polygon and edge layers are the basic layer types for geometrical operations. +

    + +

    + Polygon layers are created from original layers using input or + polygons. + "input" will also turn texts into small polygons with a size of 2x2 DBU + while "polygons" will skip texts. For handling texts, the + labels method is + recommended which renders a true text layer. Text layers are described + below.

    @@ -501,6 +518,45 @@ output(w, "width violations") the DRC check functions.

    +

    Text collections

    + +

    + Starting with version 0.27, KLayout offers support for text layers. + "Texts" are basically locations with a label, i.e. a dot with + an arbitrary string attached. "Text collections" are collections of + such objects. +

    + +

    + Texts can be used to select polygons or as net names in + net extractions. +

    + +

    + Text collections are kept in "text layers". These are created + using the labels + methods instead of "input". +

    + +

    + These operations are supported for text layers: +

    + +
      +
    • Boolean AND with a polygon layer: will select those texts + which are inside or at the border of a polygon. + "interact" is a synonym for this operation.
    • +
    • Text filtering by string: texts can be filtered either + by matching against a fixed text or a glob pattern. + The methods provided for this purpose are: + texts and + texts_not
    • +
    • flatten + will flatten the hierarchy of a text layer.
    • +
    • Polygon or edge generation around the text's location: + polygons and + edges
    • +

    Edge pairs and edge pair collections

    From ba9a05640c1c0fd043c482cb75557f17d0daa300 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 23 May 2020 19:03:42 +0200 Subject: [PATCH 28/35] Bugfixed tiled mode with text input, DRC tests added and test data updated. --- src/db/db/dbAsIfFlatRegion.cc | 4 ++-- src/drc/drc/built-in-macros/_drc_engine.rb | 2 +- src/drc/drc/built-in-macros/_drc_layer.rb | 13 ++++++++++--- src/lay/lay/doc/manual/drc_runsets.xml | 5 ++++- testdata/drc/.drcSuiteTests.drc.swp | Bin 36864 -> 36864 bytes testdata/drc/drcSuiteTests.drc | 18 ++++++++++++++++++ testdata/drc/drcSuiteTests_au1.oas | Bin 13710 -> 13755 bytes testdata/drc/drcSuiteTests_au2.oas | Bin 62065 -> 62118 bytes testdata/drc/drcSuiteTests_au3.oas | Bin 1192903 -> 1196372 bytes testdata/drc/drcSuiteTests_au4.oas | Bin 61941 -> 61994 bytes testdata/drc/drcSuiteTests_au5.oas | Bin 13509 -> 13556 bytes testdata/drc/drcSuiteTests_au6.oas | Bin 20007 -> 20054 bytes testdata/drc/drctest.gds | Bin 3128 -> 3192 bytes 13 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index 00053b423..047137407 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -393,8 +393,8 @@ AsIfFlatRegion::selected_interacting_generic (const Texts &other, bool inverse) scanner.reserve1 (size ()); scanner.reserve2 (other.size ()); - std::auto_ptr output (new FlatRegion (false)); - region_to_text_interaction_filter filter (output->raw_polygons (), inverse); + std::auto_ptr output (new FlatRegion (true)); + region_to_text_interaction_filter filter (*output, inverse); AddressablePolygonDelivery p (begin_merged (), has_valid_merged_polygons ()); diff --git a/src/drc/drc/built-in-macros/_drc_engine.rb b/src/drc/drc/built-in-macros/_drc_engine.rb index 5e1ce030d..d31cb68bc 100644 --- a/src/drc/drc/built-in-macros/_drc_engine.rb +++ b/src/drc/drc/built-in-macros/_drc_engine.rb @@ -1448,7 +1448,7 @@ CODE tp.input("self", obj) tp.threads = (@tt || 1) args.each_with_index do |a,i| - if a.is_a?(RBA::Edges) || a.is_a?(RBA::Region) + if a.is_a?(RBA::Edges) || a.is_a?(RBA::Region) || a.is_a?(RBA::EdgePairs) || a.is_a?(RBA::Texts) tp.input("a#{i}", a) else tp.var("a#{i}", a) diff --git a/src/drc/drc/built-in-macros/_drc_layer.rb b/src/drc/drc/built-in-macros/_drc_layer.rb index bebaa7dae..4f90e01f9 100644 --- a/src/drc/drc/built-in-macros/_drc_layer.rb +++ b/src/drc/drc/built-in-macros/_drc_layer.rb @@ -1807,12 +1807,19 @@ CODE # In tiled mode, there are no modifying versions. Emulate using the non-modifying one. eval <<"CODE" def #{f}(other) - if :#{fi} != :interacting && :#{f} != :not_interacting + if :#{fi} != :interacting && :#{fi} != :not_interacting + requires_edges_or_region("#{f}") requires_same_type(other, "#{f}") else - other.requires_edges_or_region("#{f}") + requires_edges_texts_or_region("#{f}") + if @data.is_a?(RBA::Text) + other.requires_region("#{f}") + elsif @data.is_a?(RBA::Region) + other.requires_edges_texts_or_region("#{f}") + else + other.requires_edges_or_region("#{f}") + end end - requires_edges_or_region("#{f}") if @engine.is_tiled? @data = @engine._tcmd(@data, 0, @data.class, :#{fi}, other.data) DRCLayer::new(@engine, @data) diff --git a/src/lay/lay/doc/manual/drc_runsets.xml b/src/lay/lay/doc/manual/drc_runsets.xml index fc928a702..6123f5e0a 100644 --- a/src/lay/lay/doc/manual/drc_runsets.xml +++ b/src/lay/lay/doc/manual/drc_runsets.xml @@ -545,7 +545,10 @@ output(w, "width violations")