diff --git a/scripts/create_drc_samples.rb b/scripts/create_drc_samples.rb index 962c026ac..b8ea6665a 100644 --- a/scripts/create_drc_samples.rb +++ b/scripts/create_drc_samples.rb @@ -2,9 +2,45 @@ # Run with: # ./klayout -z -r ./create_drc_samples.rb -t -c klayoutrc_drc_samples +class QRCGenerator + + def res_path + "src/lay/lay" + end + + def img_path + "doc/images" + end + + def initialize + @path = res_path + "/" + "layDRCLVSHelpResources.qrc" + @file = File.open(@path, "w") + @file.puts("") + @file.puts(" ") + end + + def <<(str) + @file.puts(str) + end + + def finish + @file.puts(" ") + @file.puts("") + @file.close + puts "---> resource file written to #{@path}" + end + + def self.instance + @@inst ||= QRCGenerator::new + @@inst + end + +end + def run_demo(gen, cmd, out) - img_path = "src/lay/lay/doc/images" + res_path = QRCGenerator::instance.res_path + img_path = QRCGenerator::instance.img_path mw = RBA::Application::instance::main_window @@ -81,7 +117,9 @@ def run_demo(gen, cmd, out) input1 = input(1, 0) input = input1 input2 = input(2, 0) - #{cmd}.data + labels1 = labels(1, 0) + labels = labels1 + (#{cmd}).data SCRIPT if data.is_a?(RBA::Region) @@ -101,15 +139,19 @@ SCRIPT elsif data.is_a?(RBA::EdgePairs) cell.shapes(lout_poly).insert_as_polygons(data, 1) cell.shapes(lout).insert(data.edges) + elsif data.is_a?(RBA::Texts) + cell.shapes(lout).insert(data) end view.update_content - view.save_image(img_path + "/" + out, 400, 400) + view.save_image(res_path + "/" + img_path + "/" + out, 400, 400) - puts "---> written #{img_path}/#{out}" + puts "---> written #{res_path}/#{img_path}/#{out}" mw.close_all + QRCGenerator::instance << " #{img_path}/#{out}" + end class Gen @@ -631,3 +673,41 @@ run_demo gen, "input.corners.sized(0.1)", "drc_corners1.png" run_demo gen, "input.corners(90.0).sized(0.1)", "drc_corners2.png" run_demo gen, "input.corners(-90.0 .. -45.0).sized(0.1)", "drc_corners3.png" + +class Gen + def produce(s1, s2) + s1.insert(RBA::Text::new("ABC", RBA::Trans::new(RBA::Vector::new(0, 2000)))) + s1.insert(RBA::Text::new("A", RBA::Trans::new(RBA::Vector::new(0, 6000)))) + s1.insert(RBA::Text::new("XYZ", RBA::Trans::new(RBA::Vector::new(4000, 2000)))) + s1.insert(RBA::Text::new("A*", RBA::Trans::new(RBA::Vector::new(4000, 6000)))) + end +end + +gen = Gen::new + +run_demo gen, "labels.texts(\"A*\")", "drc_texts1.png" +run_demo gen, "labels.texts(text(\"A*\"))", "drc_texts2.png" + +class Gen + def produce(s1, s2) + s1.insert(RBA::Text::new("T1", RBA::Trans::new(RBA::Vector::new(0, 2000)))) + s1.insert(RBA::Text::new("T2", RBA::Trans::new(RBA::Vector::new(2000, 2000)))) + s1.insert(RBA::Text::new("T3", RBA::Trans::new(RBA::Vector::new(4000, 2000)))) + pts = [ + RBA::Point::new(2000, 0), + RBA::Point::new(2000, 4000), + RBA::Point::new(6000, 4000), + RBA::Point::new(6000, 0) + ]; + s2.insert(RBA::Polygon::new(pts)) + end +end + +gen = Gen::new + +run_demo gen, "labels & input2", "drc_textpoly1.png" +run_demo gen, "labels - input2", "drc_textpoly2.png" + + +QRCGenerator::instance.finish + diff --git a/src/db/db/db.pro b/src/db/db/db.pro index ea36ff395..6ee1e93fd 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -184,7 +184,19 @@ 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 \ + dbNetShape.cc \ + dbShapeCollection.cc \ + gsiDeclDbShapeCollection.cc HEADERS = \ dbArray.h \ @@ -331,7 +343,17 @@ 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 \ + dbNetShape.h \ + dbShapeCollection.h !equals(HAVE_QT, "0") { 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/dbAsIfFlatEdges.cc b/src/db/db/dbAsIfFlatEdges.cc index 26bfe7689..588eaf462 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 { @@ -170,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); @@ -497,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/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..047137407 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" @@ -55,6 +56,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 { @@ -364,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 (true)); + region_to_text_interaction_filter filter (*output, 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 { @@ -440,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); @@ -457,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_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 ed232d858..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,17 +262,20 @@ 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); 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 new file mode 100644 index 000000000..fe9c86da3 --- /dev/null +++ b/src/db/db/dbAsIfFlatTexts.cc @@ -0,0 +1,384 @@ + +/* + + 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 "dbEmptyRegion.h" +#include "dbTexts.h" +#include "dbBoxConvert.h" +#include "dbRegion.h" +#include "dbTextsUtils.h" + +#include + +namespace db +{ + +// ------------------------------------------------------------------------------------------------------------- +// AsIfFlagTexts implementation + +AsIfFlatTexts::AsIfFlatTexts () + : TextsDelegate (), m_bbox_valid (false) +{ + // .. nothing yet .. +} + +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 +{ + 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 ()); + + 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)); + } +} + +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 ()); + + 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, db::Text> 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 (), has_valid_texts ()); + + 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 new file mode 100644 index 000000000..b0f4611fe --- /dev/null +++ b/src/db/db/dbAsIfFlatTexts.h @@ -0,0 +1,96 @@ + +/* + + 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 { + +class Region; + +/** + * @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; + + 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 (); + AsIfFlatTexts &operator= (const AsIfFlatTexts &other); + +private: + + mutable bool m_bbox_valid; + 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; +}; + +} + +#endif + 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 4b9eec059..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) { @@ -145,6 +147,25 @@ DeepEdges::DeepEdges (const DeepEdges &other) } } +DeepEdges & +DeepEdges::operator= (const DeepEdges &other) +{ + if (this != &other) { + + AsIfFlatEdges::operator= (other); + DeepShapeCollectionDelegateBase::operator= (other); + + 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; @@ -182,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 ()); @@ -190,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 ()); } @@ -262,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); @@ -273,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); } @@ -384,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 (), db::ShapeIterator::Edges, 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? @@ -436,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; @@ -454,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 @@ -650,11 +671,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 (); @@ -730,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; } @@ -753,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; } @@ -771,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; } @@ -1051,7 +1079,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) { @@ -1278,7 +1306,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); } @@ -1295,7 +1323,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); @@ -1374,7 +1402,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/dbDeepEdges.h b/src/db/db/dbDeepEdges.h index 662ac5cd1..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; @@ -178,6 +172,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..e0ba85dc5 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" @@ -101,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); } @@ -116,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 ()); @@ -129,8 +132,9 @@ DeepRegion::DeepRegion () } DeepRegion::DeepRegion (const DeepLayer &dl) - : AsIfFlatRegion (), m_deep_layer (dl) + : AsIfFlatRegion () { + set_deep_layer (dl); init (); } @@ -140,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) { @@ -150,6 +153,25 @@ DeepRegion::DeepRegion (const DeepRegion &other) } } +DeepRegion & +DeepRegion::operator= (const DeepRegion &other) +{ + if (this != &other) { + + AsIfFlatRegion::operator= (other); + DeepShapeCollectionDelegateBase::operator= (other); + + 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; @@ -192,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 ()); @@ -200,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 ()); } @@ -273,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); @@ -285,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); } @@ -421,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 (), db::ShapeIterator::Polygons, 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? @@ -473,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 * @@ -523,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; } @@ -648,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; @@ -726,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 @@ -1085,11 +1107,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 (); @@ -1170,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; @@ -1205,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 (), db::ShapeIterator::Polygons, 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) { @@ -1502,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 ()); @@ -1870,6 +1899,143 @@ public: } }; +struct TextResultInserter +{ + typedef db::TextRef value_type; + + TextResultInserter (std::unordered_set &result) + : mp_result (&result) + { + // .. nothing yet .. + } + + void insert (const db::TextRef &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 * @@ -2016,4 +2182,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 c1665d658..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: @@ -176,10 +171,10 @@ protected: private: friend class DeepEdges; + friend class DeepTexts; DeepRegion &operator= (const DeepRegion &other); - DeepLayer m_deep_layer; mutable DeepLayer m_merged_polygons; mutable bool m_merged_polygons_valid; bool m_is_merged; @@ -192,8 +187,11 @@ 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 c1fcb9009..a2e11a840 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -25,7 +25,14 @@ #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 "dbShapeCollection.h" #include "tlTimer.h" @@ -48,6 +55,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) { @@ -459,9 +490,39 @@ DeepLayer DeepShapeStore::create_from_flat (const db::Edges &edges, const db::IC return dl; } -std::pair DeepShapeStore::layer_for_flat (const db::Region ®ion) const +DeepLayer DeepShapeStore::create_from_flat (const db::Texts &texts, const db::ICplxTrans &trans) { - return layer_for_flat (tl::id_of (region.delegate ())); + // 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 (&layout ()); + + 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 ShapeCollection &coll) const +{ + return layer_for_flat (tl::id_of (coll.get_delegate ())); } std::pair DeepShapeStore::layer_for_flat (size_t region_id) const @@ -807,64 +868,23 @@ 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 { +DeepLayer DeepShapeStore::create_text_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; - 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); + db::TextBuildingHierarchyBuilderShapeReceiver refs (&layout); + return create_custom_layer (si, &refs, trans); } void @@ -1123,6 +1143,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/dbDeepShapeStore.h b/src/db/db/dbDeepShapeStore.h index 3290d5573..9e6d30dad 100644 --- a/src/db/db/dbDeepShapeStore.h +++ b/src/db/db/dbDeepShapeStore.h @@ -43,6 +43,9 @@ class DeepShapeStore; class DeepShapeStoreState; class Region; class Edges; +class EdgePairs; +class Texts; +class ShapeCollection; /** * @brief Represents a shape collection from the deep shape store @@ -75,6 +78,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 */ @@ -338,15 +359,26 @@ 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 Gets the layer for a given flat region. + * @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 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 @@ -395,6 +427,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..50f6e2623 --- /dev/null +++ b/src/db/db/dbDeepTexts.cc @@ -0,0 +1,613 @@ + +/* + + 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 "dbLocalOperation.h" +#include "dbTextsUtils.h" +#include "dbHierProcessor.h" +#include "dbRegion.h" + +#include +#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 () +{ + // .. nothing yet .. +} + +DeepTexts::DeepTexts (const db::Texts &other, DeepShapeStore &dss) + : AsIfFlatTexts () +{ + set_deep_layer (dss.create_from_flat (other)); +} + +DeepTexts::DeepTexts (const RecursiveShapeIterator &si, DeepShapeStore &dss) + : AsIfFlatTexts () +{ + set_deep_layer (dss.create_text_layer (si)); +} + +DeepTexts::DeepTexts (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans) + : AsIfFlatTexts () +{ + set_deep_layer (dss.create_text_layer (si, trans)); +} + +DeepTexts::DeepTexts (const DeepTexts &other) + : AsIfFlatTexts (other), DeepShapeCollectionDelegateBase (other) +{ + // .. nothing yet .. +} + +DeepTexts & +DeepTexts::operator= (const DeepTexts &other) +{ + if (this != &other) { + AsIfFlatTexts::operator= (other); + DeepShapeCollectionDelegateBase::operator= (other); + } + return *this; +} + +DeepTexts::DeepTexts (const DeepLayer &dl) + : AsIfFlatTexts () +{ + set_deep_layer (dl); +} + +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 = 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 (deep_layer ().layout (), top_cell, deep_layer ().layer ()); + return std::make_pair (iter, db::ICplxTrans ()); + + } +} + +size_t DeepTexts::size () const +{ + size_t n = 0; + + 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 (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 deep_layer ().initial_cell ().bbox (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 as really in place + *this = *apply_filter (filter); + return this; +} + +TextsDelegate *DeepTexts::filtered (const TextFilterBase &filter) const +{ + 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 +{ + 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 (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 = 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 (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->deep_layer ().layout () == &deep_layer ().layout () + && other_delegate->deep_layer ().layer () == 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->deep_layer ().layout () == &deep_layer ().layout ()) { + return other_delegate->deep_layer ().layer () < 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 +{ + 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 +{ + 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::TextRef &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, 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::TextRef &subject = interactions.subject_shape (i->first); + if (interacting.find (subject) == interacting.end ()) { + result.insert (subject); + } + } + + } else { + + text_to_region_interaction_filter, db::TextRef> 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::TextRef &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 new file mode 100644 index 000000000..812582b0d --- /dev/null +++ b/src/db/db/dbDeepTexts.h @@ -0,0 +1,100 @@ + +/* + + 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 db::DeepShapeCollectionDelegateBase +{ +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); + + 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; + + virtual DeepShapeCollectionDelegateBase *deep () + { + return this; + } + +private: + DeepTexts &operator= (const DeepTexts &other); + + 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; +}; + +} + +#endif + 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 3634e5d4e..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 */ @@ -1301,6 +1308,7 @@ public: private: friend class EdgePairs; + friend class Texts; EdgesDelegate *mp_delegate; 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/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/dbEmptyTexts.cc b/src/db/db/dbEmptyTexts.cc new file mode 100644 index 000000000..9ef48abc2 --- /dev/null +++ b/src/db/db/dbEmptyTexts.cc @@ -0,0 +1,106 @@ + +/* + + 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; +} + +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 new file mode 100644 index 000000000..99b1623ac --- /dev/null +++ b/src/db/db/dbEmptyTexts.h @@ -0,0 +1,89 @@ + +/* + + 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 { } + + 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); +}; + +} + +#endif + diff --git a/src/db/db/dbFlatTexts.cc b/src/db/db/dbFlatTexts.cc new file mode 100644 index 000000000..96668a150 --- /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_text ()) { + + 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..90b3e9b24 --- /dev/null +++ b/src/db/db/dbFlatTexts.h @@ -0,0 +1,173 @@ + +/* + + 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::Text value_type; + + 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/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index 08ca4d269..f2d4dd92e 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; @@ -747,10 +791,10 @@ namespace template struct cluster_building_receiver - : public db::box_scanner_receiver > + : public db::box_scanner_receiver > { typedef typename local_cluster::id_type id_type; - typedef std::pair > shape_value; + typedef std::pair > shape_value; typedef std::vector shape_vector; typedef std::set global_nets; typedef std::pair cluster_value; @@ -778,7 +822,7 @@ struct cluster_building_receiver } } - void add (const T *s1, std::pair p1, const T *s2, std::pair p2) + void add (const T *s1, std::pair p1, const T *s2, std::pair p2) { if (! mp_conn->interacts (*s1, p1.first, *s2, p2.first)) { return; @@ -824,7 +868,7 @@ struct cluster_building_receiver } } - void finish (const T *s, std::pair p) + void finish (const T *s, std::pair p) { // if the shape has not been handled yet, insert a single cluster with only this shape typename std::map::iterator>::iterator ic = m_shape_to_clusters.find (s); @@ -886,22 +930,108 @@ 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() () const + { + return db::ShapeIterator::Edges; + } +}; + +template <> +struct get_shape_flags +{ + db::ShapeIterator::flags_type operator() () const + { + return db::ShapeIterator::Polygons; + } +}; + +template <> +struct get_shape_flags +{ + db::ShapeIterator::flags_type operator() () const + { + return db::ShapeIterator::flags_type (db::ShapeIterator::Polygons | db::ShapeIterator::Texts); + } +}; + } 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 () (); 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 +1046,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 +1069,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 +1092,7 @@ local_clusters::apply_attr_equivalences (const tl::equivalence_clusters; template class DB_PUBLIC local_clusters; template class DB_PUBLIC local_clusters; @@ -984,6 +1115,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 +1185,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 +1266,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 +2072,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 +2090,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 +2107,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 +2154,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 +2163,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 +2469,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 +2594,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 +2668,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 +2750,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..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 @@ -505,7 +506,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 +541,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 +999,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 +1037,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 +1336,49 @@ 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) + 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 (); +} + } #endif diff --git a/src/db/db/dbHierProcessor.cc b/src/db/db/dbHierProcessor.cc index c3adf6449..674f81430 100644 --- a/src/db/db/dbHierProcessor.cc +++ b/src/db/db/dbHierProcessor.cc @@ -633,8 +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; // --------------------------------------------------------------------------------------------- // Helper classes for the LocalProcessor @@ -656,6 +659,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 +859,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 +941,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; } @@ -1743,11 +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; } diff --git a/src/db/db/dbHierarchyBuilder.cc b/src/db/db/dbHierarchyBuilder.cc index a548c0341..35424cabc 100644 --- a/src/db/db/dbHierarchyBuilder.cc +++ b/src/db/db/dbHierarchyBuilder.cc @@ -704,4 +704,22 @@ void EdgePairBuildingHierarchyBuilderShapeReceiver::push (const db::Shape &shape } } +// --------------------------------------------------------------------------------------------- + +TextBuildingHierarchyBuilderShapeReceiver::TextBuildingHierarchyBuilderShapeReceiver (db::Layout *layout) + : mp_layout (layout) +{ + // .. 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 ()) { + // 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 b1d323dc7..2ddd6fe22 100644 --- a/src/db/db/dbHierarchyBuilder.h +++ b/src/db/db/dbHierarchyBuilder.h @@ -189,6 +189,23 @@ 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 (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; +}; + /** * @brief A class building a hierarchy from a recursive shape iterator in push mode * 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..96aaf475e 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; @@ -557,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 */ @@ -565,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 */ @@ -1123,6 +1140,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/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index d362aa4c5..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) @@ -206,7 +207,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 +222,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 (); @@ -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; @@ -613,49 +617,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 +798,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 +844,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 +1046,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 +1092,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 +1194,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..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. @@ -522,7 +563,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 +571,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 +785,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,15 +827,17 @@ 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; - 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/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 599b08aa1..1fc9ed56e 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); @@ -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 { @@ -524,7 +539,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 (); @@ -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)); } } } @@ -561,8 +576,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 +1040,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..75d577f16 100644 --- a/src/db/db/dbLayoutToNetlistReader.h +++ b/src/db/db/dbLayoutToNetlistReader.h @@ -139,11 +139,11 @@ 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 (); - 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..8af2f2049 100644 --- a/src/db/db/dbLayoutToNetlistWriter.cc +++ b/src/db/db/dbLayoutToNetlistWriter.cc @@ -397,30 +397,49 @@ 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) { - const db::Polygon &poly = s->obj (); - if (poly.is_box ()) { + db::PolygonRef pr = s->polygon_ref (); + db::ICplxTrans t = tr * db::ICplxTrans (pr.trans ()); - 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 << ")"; + const db::Polygon &poly = pr.obj (); + if (poly.is_box ()) { - } else { + 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 << ")"; - *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 << ")"; } @@ -435,7 +454,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 +469,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 +589,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 +606,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..1b5f6f453 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) @@ -161,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 ()); @@ -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..862f355f7 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" @@ -204,8 +205,8 @@ 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 db::hier_clusters hier_clusters_type; + typedef std::map input_layers; + 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..7783ffbc6 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,13 +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) { - const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (*a); - for (db::PropertiesRepository::properties_set::const_iterator j = ps.begin (); j != ps.end (); ++j) { + if (db::is_prop_id_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) { + + 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)); + } } @@ -343,13 +371,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/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/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/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 bc8aa21df..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 */ @@ -1322,6 +1329,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 +1441,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 * @@ -1612,6 +1675,7 @@ public: private: friend class Edges; friend class EdgePairs; + friend class Texts; RegionDelegate *mp_delegate; 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 9909145f2..562f08ca7 100644 --- a/src/db/db/dbRegionDelegate.h +++ b/src/db/db/dbRegionDelegate.h @@ -28,9 +28,10 @@ #include "dbPolygon.h" #include "dbEdges.h" +#include "dbTexts.h" #include "dbEdgePairs.h" #include "dbEdgePairRelations.h" -#include "tlUniqueId.h" +#include "dbShapeCollection.h" #include @@ -182,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; @@ -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..6a4829fe0 100644 --- a/src/db/db/dbRegionUtils.cc +++ b/src/db/db/dbRegionUtils.cc @@ -350,6 +350,62 @@ 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 TextType *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 = 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); + } 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; +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..6bddbb65e 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 TextType *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/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/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/dbTexts.cc b/src/db/db/dbTexts.cc new file mode 100644 index 000000000..6d1fbc5fd --- /dev/null +++ b/src/db/db/dbTexts.cc @@ -0,0 +1,212 @@ + +/* + + 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) + : db::ShapeCollection (), 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; +} + +void Texts::pull_interacting (Region &output, const Region &other) const +{ + output = Region (mp_delegate->pull_interacting (other)); +} + +} + +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..35ce50c05 --- /dev/null +++ b/src/db/db/dbTexts.h @@ -0,0 +1,724 @@ + +/* + + 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 "dbShapeCollection.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; + virtual bool wants_variants () 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 db::ShapeCollection +{ +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 Implementation of the ShapeCollection interface + */ + ShapeCollectionDelegateBase *get_delegate () const + { + return mp_delegate; + } + + /** + * @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 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 + */ + 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..00b49181c --- /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) + : db::ShapeCollectionDelegateBase () +{ + 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..551f91389 --- /dev/null +++ b/src/db/db/dbTextsDelegate.h @@ -0,0 +1,144 @@ + +/* + + 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 "dbShapeCollection.h" +#include "dbText.h" + +namespace db { + +class RecursiveShapeIterator; +class Texts; +class Region; +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 ShapeCollectionDelegateBase +{ +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; + + 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 + { + 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..d1a5926f3 --- /dev/null +++ b/src/db/db/dbTextsUtils.h @@ -0,0 +1,208 @@ + +/* + + 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 "dbBoxScanner.h" +#include "dbPolygonTools.h" +#include "tlGlobPattern.h" +#include "tlSelect.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; +}; + +/** + * @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 + * 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::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; + 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/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/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 2d375fc40..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" @@ -426,13 +428,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 +861,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 +869,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 +891,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 +899,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 +907,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 +915,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/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/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 54b210363..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" @@ -1509,6 +1511,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 +1618,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/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/gsiDeclDbShapes.cc b/src/db/db/gsiDeclDbShapes.cc index cf2e175de..2dff334b9 100644 --- a/src/db/db/gsiDeclDbShapes.cc +++ b/src/db/db/gsiDeclDbShapes.cc @@ -419,6 +419,29 @@ static void insert_edge_pairs_with_dtrans (db::Shapes *sh, const db::EdgePairs & } } +static void insert_texts (db::Shapes *sh, const db::Texts &r) +{ + for (db::Texts::const_iterator s = r.begin (); ! s.at_end (); ++s) { + sh->insert (*s); + } +} + +static void insert_texts_with_trans (db::Shapes *sh, const db::Texts &r, const db::ICplxTrans &trans) +{ + for (db::Texts::const_iterator s = r.begin (); ! s.at_end (); ++s) { + sh->insert (s->transformed (trans)); + } +} + +static void insert_texts_with_dtrans (db::Shapes *sh, const db::Texts &r, const db::DCplxTrans &trans) +{ + db::CplxTrans dbu_trans (shapes_dbu (sh)); + db::ICplxTrans itrans = dbu_trans.inverted () * trans * dbu_trans; + for (db::Texts::const_iterator s = r.begin (); ! s.at_end (); ++s) { + sh->insert (s->transformed (itrans)); + } +} + static unsigned int s_all () { return db::ShapeIterator::All; } static unsigned int s_all_with_properties () { return db::ShapeIterator::AllWithProperties; } static unsigned int s_properties () { return db::ShapeIterator::Properties; } @@ -599,7 +622,7 @@ Class decl_Shapes ("db", "Shapes", "@param edges The edge pairs to insert\n" "@param trans The transformation to apply (displacement in micrometer units)\n" "\n" - "This method inserts all edge pairs from the edge collection into this shape container.\n" + "This method inserts all edge pairs from the edge pair collection into this shape container.\n" "Before an edge pair is inserted, the given transformation is applied.\n" "\n" "This method has been introduced in version 0.26.\n" @@ -682,6 +705,34 @@ Class decl_Shapes ("db", "Shapes", "\n" "This method has been introduced in version 0.25.\n" ) + + gsi::method_ext ("insert", &insert_texts, gsi::arg ("texts"), + "@brief Inserts the texts from the text collection into this shape container\n" + "@param texts The texts to insert\n" + "\n" + "This method inserts all texts from the text collection into this shape container.\n" + "\n" + "This method has been introduced in version 0.27.\n" + ) + + gsi::method_ext ("insert", &insert_texts_with_trans, gsi::arg ("texts"), gsi::arg ("trans"), + "@brief Inserts the texts from the text collection into this shape container with a transformation\n" + "@param edges The texts to insert\n" + "@param trans The transformation to apply\n" + "\n" + "This method inserts all texts from the text collection into this shape container.\n" + "Before an text is inserted, the given transformation is applied.\n" + "\n" + "This method has been introduced in version 0.27.\n" + ) + + gsi::method_ext ("insert", &insert_texts_with_dtrans, gsi::arg ("texts"), gsi::arg ("trans"), + "@brief Inserts the texts from the text collection into this shape container with a transformation (given in micrometer units)\n" + "@param edges The text to insert\n" + "@param trans The transformation to apply (displacement in micrometer units)\n" + "\n" + "This method inserts all texts from the text collection into this shape container.\n" + "Before an text is inserted, the given transformation is applied.\n" + "\n" + "This method has been introduced in version 0.27.\n" + ) + gsi::method_ext ("transform", &transform_shapes, gsi::arg ("trans"), "@brief Transforms all shapes with the given transformation\n" "This method will invalidate all references to shapes inside this collection.\n\n" diff --git a/src/db/db/gsiDeclDbTexts.cc b/src/db/db/gsiDeclDbTexts.cc new file mode 100644 index 000000000..f7c33c1cb --- /dev/null +++ b/src/db/db/gsiDeclDbTexts.cc @@ -0,0 +1,518 @@ + +/* + + 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_match (const db::Texts *r, const std::string &pattern, bool inverse) +{ + db::TextPatternFilter f (pattern, inverse); + 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; +} + +extern Class decl_dbShapeCollection; + +Class decl_Texts (decl_dbShapeCollection, "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_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" + "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"), + "@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"), + "@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::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::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" + "\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" + ) + + 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 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"), + "@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 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_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" + "\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" +); + +} 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/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/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/dbDeepTextsTests.cc b/src/db/unit_tests/dbDeepTextsTests.cc new file mode 100644 index 000000000..a833feb89 --- /dev/null +++ b/src/db/unit_tests/dbDeepTextsTests.cc @@ -0,0 +1,180 @@ + +/* + + 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 "dbTextsUtils.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"); +} + +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"); +} + +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/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/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/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/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/dbLayoutToNetlistTests.cc b/src/db/unit_tests/dbLayoutToNetlistTests.cc index f352bdb0c..ae2ecaf4d 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) { @@ -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/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/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/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/dbNetShapeTests.cc b/src/db/unit_tests/dbNetShapeTests.cc new file mode 100644 index 000000000..8bf3a0d36 --- /dev/null +++ b/src/db/unit_tests/dbNetShapeTests.cc @@ -0,0 +1,184 @@ + +/* + + 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) != (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) != (s2 < s), true); + + 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) != (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..8b3600bd5 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)); @@ -59,7 +67,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 +77,8 @@ 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 ()); + 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; for (std::map::const_iterator m = lmap.begin (); m != lmap.end () && !any_shapes; ++m) { @@ -78,14 +87,13 @@ 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 ())); 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 +145,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 +241,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"); @@ -280,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 @@ -291,14 +307,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 +390,214 @@ 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); + + // 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 + // 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) @@ -452,7 +679,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 +913,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 +1162,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 +1409,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 +1676,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 +1883,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 +2017,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 +2178,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 +2411,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 +2579,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 +2701,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 +2855,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/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 93% rename from src/db/unit_tests/dbRegion.cc rename to src/db/unit_tests/dbRegionTests.cc index 86f52f6db..6addaa424 100644 --- a/src/db/unit_tests/dbRegion.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/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 98% rename from src/db/unit_tests/dbShapes.cc rename to src/db/unit_tests/dbShapesTests.cc index a43778b8f..3bb3bd4ef 100644 --- a/src/db/unit_tests/dbShapes.cc +++ b/src/db/unit_tests/dbShapesTests.cc @@ -1314,87 +1314,13 @@ TEST(5) for (db::Shapes::shape_iterator shape = topcell.shapes (lindex).begin (db::Shapes::shape_iterator::All); ! shape.at_end (); ++shape) { copy.insert (*shape); } - EXPECT_EQ (shapes_to_string (_this, 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 0,50) #0\n" - "text ('B',r90 -90,140) #0\n" - "text ('C',m90 -180,230) #0\n" - "text ('A',r0 10,40) #0\n" - "text ('A',r0 10,10040) #0\n" - "text ('A',r0 10,20040) #0\n" - "text ('A',r0 11010,40) #0\n" - "text ('A',r0 11010,10040) #0\n" - "text ('A',r0 11010,20040) #0\n" - "text ('A',r0 22010,40) #0\n" - "text ('A',r0 22010,10040) #0\n" - "text ('A',r0 22010,20040) #0\n" - "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" - "text ('A',r0 10,40) #8\n" - "text ('A',r0 10,10040) #8\n" - "text ('A',r0 10,20040) #8\n" - "text ('A',r0 11010,40) #8\n" - "text ('A',r0 11010,10040) #8\n" - "text ('A',r0 11010,20040) #8\n" - "text ('A',r0 22010,40) #8\n" - "text ('A',r0 22010,10040) #8\n" - "text ('A',r0 22010,20040) #8\n" - "text ('A',r0 33010,40) #8\n" - "text ('A',r0 33010,10040) #8\n" - "text ('A',r0 33010,20040) #8\n" - ); + EXPECT_EQ (shapes_to_string_norm (_this, copy), shapes_to_string_norm (_this, topcell.shapes (lindex))); db::Shapes sa_copy; 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), - "text ('A',r0 10,35) #0\n" - "text ('B',r90 20,25) #0\n" - "text ('C',m90 30,15) #0\n" - "text ('A',r0 0,50) #0\n" - "text ('B',r90 -90,140) #0\n" - "text ('C',m90 -180,230) #0\n" - "text ('A',r0 10,40) #0\n" - "text ('A',r0 10,10040) #0\n" - "text ('A',r0 10,20040) #0\n" - "text ('A',r0 11010,40) #0\n" - "text ('A',r0 11010,10040) #0\n" - "text ('A',r0 11010,20040) #0\n" - "text ('A',r0 22010,40) #0\n" - "text ('A',r0 22010,10040) #0\n" - "text ('A',r0 22010,20040) #0\n" - "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" - "text ('A',r0 10,40) #8\n" - "text ('A',r0 10,10040) #8\n" - "text ('A',r0 10,20040) #8\n" - "text ('A',r0 11010,40) #8\n" - "text ('A',r0 11010,10040) #8\n" - "text ('A',r0 11010,20040) #8\n" - "text ('A',r0 22010,40) #8\n" - "text ('A',r0 22010,10040) #8\n" - "text ('A',r0 22010,20040) #8\n" - "text ('A',r0 33010,40) #8\n" - "text ('A',r0 33010,10040) #8\n" - "text ('A',r0 33010,20040) #8\n" - ); + EXPECT_EQ (shapes_to_string_norm (_this, sa_copy), shapes_to_string_norm (_this, topcell.shapes (lindex))); db::Shapes::shape_iterator shape = topcell.shapes (lindex).begin (db::Shapes::shape_iterator::All); ++shape; 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..e99bb6960 --- /dev/null +++ b/src/db/unit_tests/dbTextsTests.cc @@ -0,0 +1,204 @@ + +/* + + 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::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)"); +} 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..d2753f09a 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,50 @@ 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 \ + dbDeepTextsTests.cc \ + dbNetShapeTests.cc INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC DEPENDPATH += $$TL_INC $$DB_INC $$GSI_INC diff --git a/src/drc/drc/built-in-macros/_drc_engine.rb b/src/drc/drc/built-in-macros/_drc_engine.rb index 7ffcc1b28..d31cb68bc 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 @@ -1428,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) @@ -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..089cb7115 100644 --- a/src/drc/drc/built-in-macros/_drc_layer.rb +++ b/src/drc/drc/built-in-macros/_drc_layer.rb @@ -593,6 +593,12 @@ CODE # selected text. By using the "as_dots" option, degenerated point-like edges will be # produced. # + # The preferred method however is to use true text layers created with \labels. + # In this case, without specifying "as_dots" or "as_boxes" retains the text + # objects as such a text filtering is applied. In contrast to this, layers generated + # with \input cannot maintain the text nature of the selected objects and + # produce dots or small polygon boxes in the \texts method. + # # 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: @@ -608,21 +614,54 @@ CODE # # @code # # Selects all texts - # t = input(1, 0).texts + # t = labels(1, 0).texts # # Selects all texts beginning with an "A" - # t = input(1, 0).texts("A*") - # t = input(1, 0).texts(pattern("A*")) - # # Selects all texts whose string is "A*" - # t = input(1, 0).texts(text("A*")) + # t = labels(1, 0).texts("A*") + # t = labels(1, 0).texts(pattern("A*")) + # # Selects all texts whose string is "ABC" + # t = labels(1, 0).texts(text("ABC")) # @/code + # + # The effect of the operation is shown in these examples: + # + # @table + # @tr + # @td @img(/images/drc_texts1.png) @/td + # @td @img(/images/drc_texts2.png) @/td + # @/tr + # @/table 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 +676,30 @@ 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 + result = @engine._tcmd(@data, 0, RBA::Texts, :with_match, pattern, invert) + else + result = @engine._tcmd(@data, 0, RBA::Texts, :with_text, pattern, invert) + end + if as_dots + return DRCLayer::new(@engine, @engine._tcmd(result, 0, RBA::Region, :edges)) + elsif as_dots == false + return DRCLayer::new(@engine, @engine._tcmd(result, 0, RBA::Region, :polygons)) + else + return DRCLayer::new(@engine, result) + end + else + if as_dots + return DRCLayer::new(@engine, @engine._tcmd(@data, 0, RBA::Region, :texts_dots, pattern, as_pattern)) + else + return DRCLayer::new(@engine, @engine._tcmd(@data, 0, RBA::Region, :texts, pattern, as_pattern)) + end end end - + # %DRC% # @name corners # @brief Selects corners of polygons @@ -1124,7 +1178,7 @@ CODE # borders of the polygons of the second operand. # # The following images show the effect of the "and" method - # on polygons and edges (layer1: red, layer2: blue): + # on polygons and edges (input1: red, input2: blue): # # @table # @tr @@ -1133,6 +1187,16 @@ CODE # @td @img(/images/drc_and3.png) @/td # @/tr # @/table + # + # The AND operation can be applied between a text and a polygon + # layer. In this case, the texts inside or at the border of the + # polygons will be written to the output (labels: red, input2: blue): + # + # @table + # @tr + # @td @img(/images/drc_textpoly1.png) @/td + # @/tr + # @/table def and(other) self & other @@ -1151,7 +1215,7 @@ CODE # of the second operand. # # The following images show the effect of the "not" method - # on polygons and edges (layer1: red, layer2: blue): + # on polygons and edges (input1: red, input2: blue): # # @table # @tr @@ -1160,6 +1224,16 @@ CODE # @td @img(/images/drc_not3.png) @/td # @/tr # @/table + # + # The NOT operation can be applied between a text and a polygon + # layer. In this case, the texts outside the polygons will be + # written to the output (labels: red, input2: blue): + # + # @table + # @tr + # @td @img(/images/drc_textpoly2.png) @/td + # @/tr + # @/table def not(other) self - other @@ -1175,7 +1249,7 @@ CODE # This method is available for polygon and edge layers. # # The following images show the effect of the "xor" method - # on polygons and edges (layer1: red, layer2: blue): + # on polygons and edges (input1: red, input2: blue): # # @table # @tr @@ -1198,7 +1272,7 @@ CODE # This method is available for polygon and edge layers. # # The following images show the effect of the "or" method - # on polygons and edges (layer1: red, layer2: blue): + # on polygons and edges (input1: red, input2: blue): # # @table # @tr @@ -1221,7 +1295,7 @@ CODE # This method is available for polygon, edge and edge pair layers. # # The following images show the effect of the "join" method - # on polygons and edges (layer1: red, layer2: blue): + # on polygons and edges (input1: red, input2: blue): # # @table # @tr @@ -1543,8 +1617,9 @@ CODE # It returns a new layer containing the selected shapes. A version which modifies self # is \select_interacting. # - # This method is available for polygon and edge layers. Edges can be selected - # with respect to other edges or polygons. + # This method is available for polygon, text and edge layers. Edges can be selected + # with respect to other edges or polygons. Texts can be selected with respect to + # polygons. Polygons can be selected with respect to edges, texts and other polygons. # # The following image shows the effect of the "interacting" method (input1: red, input2: blue): # @@ -1564,8 +1639,9 @@ CODE # It returns a new layer containing the selected shapes. A version which modifies self # is \select_not_interacting. # - # This method is available for polygon and edge layers. Edges can be selected - # with respect to other edges or polygons. + # This method is available for polygon, text and edge layers. Edges can be selected + # with respect to other edges or polygons. Texts can be selected with respect to + # polygons. Polygons can be selected with respect to edges, texts and other polygons. # # The following image shows the effect of the "not_interacting" method (input1: red, input2: blue): # @@ -1585,8 +1661,9 @@ CODE # It modifies self to contain the selected shapes. A version which does not modify self # is \interacting. # - # This method is available for polygon and edge layers. Edges can be selected - # with respect to other edges or polygons. + # This method is available for polygon, text and edge layers. Edges can be selected + # with respect to other edges or polygons. Texts can be selected with respect to + # polygons. Polygons can be selected with respect to edges, texts and other polygons. # %DRC% # @name select_not_interacting @@ -1598,8 +1675,9 @@ CODE # It modifies self to contain the selected shapes. A version which does not modify self # is \not_interacting. # - # This method is available for polygon and edge layers. Edges can be selected - # with respect to other edges or polygons. + # This method is available for polygon, text and edge layers. Edges can be selected + # with respect to other edges or polygons. Texts can be selected with respect to + # polygons. Polygons can be selected with respect to edges, texts and other polygons. # %DRC% # @name intersections @@ -1657,8 +1735,7 @@ CODE # # This method will neither modify self nor other. # - # This method is available for polygon layers. Other can be an edge or polygon layer. - # Edges or polygons can be selected with respect to polygons of self. + # This method is available for polygon, edge and text layers, similar to interacting. # %DRC% # @name pull_overlapping @@ -1695,7 +1772,37 @@ 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}") + elsif @data.is_a?(RBA::Region) + other.requires_edges_texts_or_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,17 +1810,26 @@ 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::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 - if :#{f} != :+ - requires_edges_or_region("#{f}") - end DRCLayer::new(@engine, @engine._tcmd(@data, 0, @data.class, :#{f}, other.data)) end CODE @@ -1724,12 +1840,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) @@ -1745,12 +1868,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 @@ -1760,12 +1878,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 @@ -2207,7 +2320,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 +2348,6 @@ CODE # @synopsis layer.is_empty? def is_empty? - requires_edges_or_region("is_empty?") @data.is_empty? end @@ -2423,7 +2535,7 @@ CODE # Distance values can be given as floating-point values (in micron) or integer values (in # database units). To explicitly specify the unit, use the unit denominators. # - # The following image shows the effect of the separation check (layer1: red, layer2: blue): + # The following image shows the effect of the separation check (input1: red, input2: blue): # # @table # @tr @@ -2458,7 +2570,7 @@ CODE # Distance values can be given as floating-point values (in micron) or integer values (in # database units). To explicitly specify the unit, use the unit denominators. # - # The following images show the effect of the overlap check (layer1: red, layer2: blue): + # The following images show the effect of the overlap check (input1: red, input2: blue): # # @table # @tr @@ -3006,6 +3118,14 @@ 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_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 @@ -3018,6 +3138,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_netter.rb b/src/drc/drc/built-in-macros/_drc_netter.rb index 163f094dd..bfc95d8cc 100644 --- a/src/drc/drc/built-in-macros/_drc_netter.rb +++ b/src/drc/drc/built-in-macros/_drc_netter.rb @@ -76,13 +76,19 @@ module DRC # @name connect # @brief Specifies a connection between two layers # @synopsis connect(a, b) - # a and b must be polygon layers. After calling this function, the + # a and b must be polygon or text layers. After calling this function, the # Netter regards all overlapping or touching shapes on these layers # to form an electrical connection between the materials formed by # these layers. This also implies intra-layer connections: shapes # on these layers touching or overlapping other shapes on these # layers will form bigger, electrically connected areas. # + # Texts will be used to assign net names to the nets. The preferred + # method is to use \labels to create a text layer from a design + # layer. When using \input, text labels are carried implicitly + # with the polygons but at the cost of small dummy shapes (2x2 DBU + # marker polygons) and limited functionality. + # # Multiple connect calls must be made to form larger connectivity # stacks across multiple layers. Such stacks may include forks and # joins. @@ -94,13 +100,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 @@ -112,15 +118,15 @@ module DRC # Connects the shapes from the given layer l to a global net with the given name. # Global nets are common to all cells. Global nets automatically connect to parent # cells throughs implied pins. An example is the substrate (bulk) net which connects - # to shapes belonging to tie-down diodes. + # to shapes belonging to tie-down diodes. "l" can be a polygon or text layer. 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 +195,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/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% diff --git a/src/lay/lay/doc/about/drc_ref_global.xml b/src/lay/lay/doc/about/drc_ref_global.xml index 7e4be95ba..5cf550238 100644 --- a/src/lay/lay/doc/about/drc_ref_global.xml +++ b/src/lay/lay/doc/about/drc_ref_global.xml @@ -362,6 +362,24 @@ This function creates an edge object. The arguments are the same than for the The intention of that method is to create an empty layer which can be filled with edge objects using Layer#insert.

+

"edge_pairs" - Gets the edges from an original layer

+ +

Usage:

+
    +
  • edge_pairs(args)
  • +
+

+See Source#edge_pairs for a description of that function. +

+

"edges" - Gets the edges from an original layer

+ +

Usage:

+
    +
  • edges(args)
  • +
+

+See Source#edges for a description of that function. +

"error" - Prints an error

Usage:

@@ -446,7 +464,7 @@ See
Netter#l2n_data for a descr

Usage:

    -
  • labels
  • +
  • labels(args)

See Source#labels for a description of that function. diff --git a/src/lay/lay/doc/about/drc_ref_layer.xml b/src/lay/lay/doc/about/drc_ref_layer.xml index d7287b733..f2a1d8043 100644 --- a/src/lay/lay/doc/about/drc_ref_layer.xml +++ b/src/lay/lay/doc/about/drc_ref_layer.xml @@ -76,7 +76,7 @@ result will be the edges of the first operand which are inside or on the borders of the polygons of the second operand.

The following images show the effect of the "and" method -on polygons and edges (layer1: red, layer2: blue): +on polygons and edges (input1: red, input2: blue):

@@ -85,6 +85,16 @@ on polygons and edges (layer1: red, layer2: blue):
+

+The AND operation can be applied between a text and a polygon +layer. In this case, the texts inside or at the border of the +polygons will be written to the output (labels: red, input2: blue): +

+ + + + +

"area" - Returns the total area of the polygons in the region

@@ -594,7 +604,7 @@ Returns the first edges of the edge pairs in the collection. 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.

"holes" - Selects all polygon holes from the input

@@ -740,8 +750,9 @@ otherwise individual shapes are selected. It returns a new layer containing the selected shapes. A version which modifies self is
select_interacting.

-This method is available for polygon and edge layers. Edges can be selected -with respect to other edges or polygons. +This method is available for polygon, text and edge layers. Edges can be selected +with respect to other edges or polygons. Texts can be selected with respect to +polygons. Polygons can be selected with respect to edges, texts and other polygons.

The following image shows the effect of the "interacting" method (input1: red, input2: blue):

@@ -860,7 +871,7 @@ It is an alias for the "+" operator. This method is available for polygon, edge and edge pair layers.

The following images show the effect of the "join" method -on polygons and edges (layer1: red, layer2: blue): +on polygons and edges (input1: red, input2: blue):

@@ -1030,7 +1041,7 @@ result will be the edges of the first operand which are outside the polygons of the second operand.

The following images show the effect of the "not" method -on polygons and edges (layer1: red, layer2: blue): +on polygons and edges (input1: red, input2: blue):

@@ -1039,6 +1050,16 @@ on polygons and edges (layer1: red, layer2: blue):
+

+The NOT operation can be applied between a text and a polygon +layer. In this case, the texts outside the polygons will be +written to the output (labels: red, input2: blue): +

+ + + + +

"not_in" - Selects shapes or regions of self which are not contained in the other layer

@@ -1103,8 +1124,9 @@ otherwise individual shapes are selected. It returns a new layer containing the selected shapes. A version which modifies self is
select_not_interacting.

-This method is available for polygon and edge layers. Edges can be selected -with respect to other edges or polygons. +This method is available for polygon, text and edge layers. Edges can be selected +with respect to other edges or polygons. Texts can be selected with respect to +polygons. Polygons can be selected with respect to edges, texts and other polygons.

The following image shows the effect of the "not_interacting" method (input1: red, input2: blue):

@@ -1216,7 +1238,7 @@ It is an alias for the "|" operator. This method is available for polygon and edge layers.

The following images show the effect of the "or" method -on polygons and edges (layer1: red, layer2: blue): +on polygons and edges (input1: red, input2: blue):

@@ -1318,7 +1340,7 @@ are the same than for width. Distance values can be given as floating-point values (in micron) or integer values (in database units). To explicitly specify the unit, use the unit denominators.

-The following images show the effect of the overlap check (layer1: red, layer2: blue): +The following images show the effect of the overlap check (input1: red, input2: blue):

@@ -1419,8 +1441,7 @@ provides a way to pull shapes from other to the hierarchy to self.

This method will neither modify self nor other.

-This method is available for polygon layers. Other can be an edge or polygon layer. -Edges or polygons can be selected with respect to polygons of self. +This method is available for polygon, edge and text layers, similar to interacting.

"pull_overlapping" - Selects shapes or regions of other which overlap shapes from the this region

@@ -1634,8 +1655,9 @@ otherwise individual shapes are selected. It modifies self to contain the selected shapes. A version which does not modify self is
interacting.

-This method is available for polygon and edge layers. Edges can be selected -with respect to other edges or polygons. +This method is available for polygon, text and edge layers. Edges can be selected +with respect to other edges or polygons. Texts can be selected with respect to +polygons. Polygons can be selected with respect to edges, texts and other polygons.

"select_not_inside" - Selects shapes or regions of self which are not inside the other region

@@ -1667,8 +1689,9 @@ otherwise individual shapes are selected. It modifies self to contain the selected shapes. A version which does not modify self is
not_interacting.

-This method is available for polygon and edge layers. Edges can be selected -with respect to other edges or polygons. +This method is available for polygon, text and edge layers. Edges can be selected +with respect to other edges or polygons. Texts can be selected with respect to +polygons. Polygons can be selected with respect to edges, texts and other polygons.

"select_not_outside" - Selects shapes or regions of self which are not outside the other region

@@ -1766,7 +1789,7 @@ are the same than for
width. Distance values can be given as floating-point values (in micron) or integer values (in database units). To explicitly specify the unit, use the unit denominators.

-The following image shows the effect of the separation check (layer1: red, layer2: blue): +The following image shows the effect of the separation check (input1: red, input2: blue):

@@ -1985,6 +2008,12 @@ been created with input. By default, a small box (2x2 DBU) selected text. By using the "as_dots" option, degenerated point-like edges will be produced.

+The preferred method however is to use true text layers created with labels. +In this case, without specifying "as_dots" or "as_boxes" retains the text +objects as such a text filtering is applied. In contrast to this, layers generated +with input cannot maintain the text nature of the selected objects and +produce dots or small polygon boxes in the texts method. +

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: @@ -2000,13 +2029,38 @@ Here are some examples:

 # Selects all texts
-t = input(1, 0).texts
+t = labels(1, 0).texts
 # Selects all texts beginning with an "A"
-t = input(1, 0).texts("A*")
-t = input(1, 0).texts(pattern("A*"))
-# Selects all texts whose string is "A*"
-t = input(1, 0).texts(text("A*"))
+t = labels(1, 0).texts("A*")
+t = labels(1, 0).texts(pattern("A*"))
+# Selects all texts whose string is "ABC"
+t = labels(1, 0).texts(text("ABC"))
 
+

+The effect of the operation is shown in these examples: +

+

+ + + + +
+

+

"texts_not" - Selects texts from an original layer not matching a specific selection

+ +

Usage:

+
    +
  • layer.texts_not
  • +
  • layer.texts_not(p)
  • +
  • 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.

"transform" - Transforms a layer (modifies the layer)

@@ -2388,7 +2442,7 @@ It is an alias for the "^" operator. This method is available for polygon and edge layers.

The following images show the effect of the "xor" method -on polygons and edges (layer1: red, layer2: blue): +on polygons and edges (input1: red, input2: blue):

diff --git a/src/lay/lay/doc/about/drc_ref_netter.xml b/src/lay/lay/doc/about/drc_ref_netter.xml index c56e060df..a08620943 100644 --- a/src/lay/lay/doc/about/drc_ref_netter.xml +++ b/src/lay/lay/doc/about/drc_ref_netter.xml @@ -153,13 +153,19 @@ See connect for more details.
  • connect(a, b)
  • -a and b must be polygon layers. After calling this function, the +a and b must be polygon or text layers. After calling this function, the Netter regards all overlapping or touching shapes on these layers to form an electrical connection between the materials formed by these layers. This also implies intra-layer connections: shapes on these layers touching or overlapping other shapes on these layers will form bigger, electrically connected areas.

    +Texts will be used to assign net names to the nets. The preferred +method is to use labels to create a text layer from a design +layer. When using input, text labels are carried implicitly +with the polygons but at the cost of small dummy shapes (2x2 DBU +marker polygons) and limited functionality. +

    Multiple connect calls must be made to form larger connectivity stacks across multiple layers. Such stacks may include forks and joins. @@ -177,7 +183,7 @@ can be cleared with clear_connections. Connects the shapes from the given layer l to a global net with the given name. Global nets are common to all cells. Global nets automatically connect to parent cells throughs implied pins. An example is the substrate (bulk) net which connects -to shapes belonging to tie-down diodes. +to shapes belonging to tie-down diodes. "l" can be a polygon or text layer.

    "connect_implicit" - Specifies a search pattern for labels which create implicit net connections

    diff --git a/src/lay/lay/doc/about/drc_ref_source.xml b/src/lay/lay/doc/about/drc_ref_source.xml index a620c0b4b..d30545115 100644 --- a/src/lay/lay/doc/about/drc_ref_source.xml +++ b/src/lay/lay/doc/about/drc_ref_source.xml @@ -54,6 +54,48 @@ This method will create a new source which delivers the shapes from that region clipped to the rectangle. A method doing the same but without clipping is
    touching or overlapping.

    +

    "edge_pairs" - Gets the edge pairs from an input layer

    + +

    Usage:

    +
      +
    • source.edge_pairs(layer)
    • +
    • source.edge_pairs(layer, datatype)
    • +
    • source.edge_pairs(layer_into)
    • +
    • 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. +

    +

    "edges" - Gets the edge shapes (or shapes that can be converted edges) from an input layer

    + +

    Usage:

    +
      +
    • source.edges(layer)
    • +
    • source.edges(layer, datatype)
    • +
    • source.edges(layer_into)
    • +
    • 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. +

    "extent" - Returns a layer with the bounding box of the selected layout

    Usage:

    @@ -95,7 +137,7 @@ Some filter expressions are: not have names)

    -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 @@ -106,6 +148,11 @@ Texts can later be selected on the layer returned by "input" with the 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.

    "labels" - Gets the labels (texts) from an input layer

    @@ -118,10 +165,12 @@ Use the global version of "input" without a source object to address the default
  • 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.

    diff --git a/src/lay/lay/doc/images/drc_and1.png b/src/lay/lay/doc/images/drc_and1.png index 5964e1939..a0c736476 100644 Binary files a/src/lay/lay/doc/images/drc_and1.png and b/src/lay/lay/doc/images/drc_and1.png differ diff --git a/src/lay/lay/doc/images/drc_and2.png b/src/lay/lay/doc/images/drc_and2.png index f6a9cfe6b..8c99cc75e 100644 Binary files a/src/lay/lay/doc/images/drc_and2.png and b/src/lay/lay/doc/images/drc_and2.png differ diff --git a/src/lay/lay/doc/images/drc_and3.png b/src/lay/lay/doc/images/drc_and3.png index 08ba54228..4078a55a3 100644 Binary files a/src/lay/lay/doc/images/drc_and3.png and b/src/lay/lay/doc/images/drc_and3.png differ diff --git a/src/lay/lay/doc/images/drc_centers1.png b/src/lay/lay/doc/images/drc_centers1.png index 5f5b07296..9f7318210 100644 Binary files a/src/lay/lay/doc/images/drc_centers1.png and b/src/lay/lay/doc/images/drc_centers1.png differ diff --git a/src/lay/lay/doc/images/drc_centers2.png b/src/lay/lay/doc/images/drc_centers2.png index 65e267b7e..949971f74 100644 Binary files a/src/lay/lay/doc/images/drc_centers2.png and b/src/lay/lay/doc/images/drc_centers2.png differ diff --git a/src/lay/lay/doc/images/drc_corners1.png b/src/lay/lay/doc/images/drc_corners1.png index 461054bdf..f5782c1a6 100644 Binary files a/src/lay/lay/doc/images/drc_corners1.png and b/src/lay/lay/doc/images/drc_corners1.png differ diff --git a/src/lay/lay/doc/images/drc_corners2.png b/src/lay/lay/doc/images/drc_corners2.png index 24c48a316..36de46255 100644 Binary files a/src/lay/lay/doc/images/drc_corners2.png and b/src/lay/lay/doc/images/drc_corners2.png differ diff --git a/src/lay/lay/doc/images/drc_corners3.png b/src/lay/lay/doc/images/drc_corners3.png index ed6f97696..f0224dba8 100644 Binary files a/src/lay/lay/doc/images/drc_corners3.png and b/src/lay/lay/doc/images/drc_corners3.png differ diff --git a/src/lay/lay/doc/images/drc_enc1.png b/src/lay/lay/doc/images/drc_enc1.png index d4b448284..c0c25dc5f 100644 Binary files a/src/lay/lay/doc/images/drc_enc1.png and b/src/lay/lay/doc/images/drc_enc1.png differ diff --git a/src/lay/lay/doc/images/drc_enc2.png b/src/lay/lay/doc/images/drc_enc2.png index 27a38ac48..93c1b4c14 100644 Binary files a/src/lay/lay/doc/images/drc_enc2.png and b/src/lay/lay/doc/images/drc_enc2.png differ diff --git a/src/lay/lay/doc/images/drc_end_segments1.png b/src/lay/lay/doc/images/drc_end_segments1.png index e146be063..0c2c424ae 100644 Binary files a/src/lay/lay/doc/images/drc_end_segments1.png and b/src/lay/lay/doc/images/drc_end_segments1.png differ diff --git a/src/lay/lay/doc/images/drc_end_segments2.png b/src/lay/lay/doc/images/drc_end_segments2.png index 2bbf6f78b..cd56d40ec 100644 Binary files a/src/lay/lay/doc/images/drc_end_segments2.png and b/src/lay/lay/doc/images/drc_end_segments2.png differ diff --git a/src/lay/lay/doc/images/drc_extended1.png b/src/lay/lay/doc/images/drc_extended1.png index 04ae3e835..12db6370d 100644 Binary files a/src/lay/lay/doc/images/drc_extended1.png and b/src/lay/lay/doc/images/drc_extended1.png differ diff --git a/src/lay/lay/doc/images/drc_extended2.png b/src/lay/lay/doc/images/drc_extended2.png index 287ad4aa7..90816d5f8 100644 Binary files a/src/lay/lay/doc/images/drc_extended2.png and b/src/lay/lay/doc/images/drc_extended2.png differ diff --git a/src/lay/lay/doc/images/drc_extended3.png b/src/lay/lay/doc/images/drc_extended3.png index 185d601d0..330ed208a 100644 Binary files a/src/lay/lay/doc/images/drc_extended3.png and b/src/lay/lay/doc/images/drc_extended3.png differ diff --git a/src/lay/lay/doc/images/drc_extended4.png b/src/lay/lay/doc/images/drc_extended4.png index 6e24afc48..8caea794f 100644 Binary files a/src/lay/lay/doc/images/drc_extended4.png and b/src/lay/lay/doc/images/drc_extended4.png differ diff --git a/src/lay/lay/doc/images/drc_extent_refs1.png b/src/lay/lay/doc/images/drc_extent_refs1.png index 2ab241463..c32c46129 100644 Binary files a/src/lay/lay/doc/images/drc_extent_refs1.png and b/src/lay/lay/doc/images/drc_extent_refs1.png differ diff --git a/src/lay/lay/doc/images/drc_extent_refs10.png b/src/lay/lay/doc/images/drc_extent_refs10.png index 81a5603fe..2771cae38 100644 Binary files a/src/lay/lay/doc/images/drc_extent_refs10.png and b/src/lay/lay/doc/images/drc_extent_refs10.png differ diff --git a/src/lay/lay/doc/images/drc_extent_refs11.png b/src/lay/lay/doc/images/drc_extent_refs11.png index 9b3618059..f1feb7337 100644 Binary files a/src/lay/lay/doc/images/drc_extent_refs11.png and b/src/lay/lay/doc/images/drc_extent_refs11.png differ diff --git a/src/lay/lay/doc/images/drc_extent_refs12.png b/src/lay/lay/doc/images/drc_extent_refs12.png index f84556d24..1a9dae0b8 100644 Binary files a/src/lay/lay/doc/images/drc_extent_refs12.png and b/src/lay/lay/doc/images/drc_extent_refs12.png differ diff --git a/src/lay/lay/doc/images/drc_extent_refs13.png b/src/lay/lay/doc/images/drc_extent_refs13.png index d1ebc5eaa..4543ee821 100644 Binary files a/src/lay/lay/doc/images/drc_extent_refs13.png and b/src/lay/lay/doc/images/drc_extent_refs13.png differ diff --git a/src/lay/lay/doc/images/drc_extent_refs20.png b/src/lay/lay/doc/images/drc_extent_refs20.png index 170aa1b52..4b3a2c2e3 100644 Binary files a/src/lay/lay/doc/images/drc_extent_refs20.png and b/src/lay/lay/doc/images/drc_extent_refs20.png differ diff --git a/src/lay/lay/doc/images/drc_extent_refs21.png b/src/lay/lay/doc/images/drc_extent_refs21.png index 26efee149..cbb4fd30d 100644 Binary files a/src/lay/lay/doc/images/drc_extent_refs21.png and b/src/lay/lay/doc/images/drc_extent_refs21.png differ diff --git a/src/lay/lay/doc/images/drc_extent_refs22.png b/src/lay/lay/doc/images/drc_extent_refs22.png index 54581748d..0def07a46 100644 Binary files a/src/lay/lay/doc/images/drc_extent_refs22.png and b/src/lay/lay/doc/images/drc_extent_refs22.png differ diff --git a/src/lay/lay/doc/images/drc_extent_refs23.png b/src/lay/lay/doc/images/drc_extent_refs23.png index f3ad4bdca..4e44e294d 100644 Binary files a/src/lay/lay/doc/images/drc_extent_refs23.png and b/src/lay/lay/doc/images/drc_extent_refs23.png differ diff --git a/src/lay/lay/doc/images/drc_extent_refs24.png b/src/lay/lay/doc/images/drc_extent_refs24.png index 673df6948..35b36f9ae 100644 Binary files a/src/lay/lay/doc/images/drc_extent_refs24.png and b/src/lay/lay/doc/images/drc_extent_refs24.png differ diff --git a/src/lay/lay/doc/images/drc_extent_refs25.png b/src/lay/lay/doc/images/drc_extent_refs25.png index f3a0db1a2..b90e4bfcc 100644 Binary files a/src/lay/lay/doc/images/drc_extent_refs25.png and b/src/lay/lay/doc/images/drc_extent_refs25.png differ diff --git a/src/lay/lay/doc/images/drc_extent_refs26.png b/src/lay/lay/doc/images/drc_extent_refs26.png index d855fb789..c61984c21 100644 Binary files a/src/lay/lay/doc/images/drc_extent_refs26.png and b/src/lay/lay/doc/images/drc_extent_refs26.png differ diff --git a/src/lay/lay/doc/images/drc_extent_refs27.png b/src/lay/lay/doc/images/drc_extent_refs27.png index 73b9597c0..eee91b62a 100644 Binary files a/src/lay/lay/doc/images/drc_extent_refs27.png and b/src/lay/lay/doc/images/drc_extent_refs27.png differ diff --git a/src/lay/lay/doc/images/drc_extent_refs30.png b/src/lay/lay/doc/images/drc_extent_refs30.png index c8ac61634..1d76c687d 100644 Binary files a/src/lay/lay/doc/images/drc_extent_refs30.png and b/src/lay/lay/doc/images/drc_extent_refs30.png differ diff --git a/src/lay/lay/doc/images/drc_extent_refs31.png b/src/lay/lay/doc/images/drc_extent_refs31.png index 755dd2922..c490f81e5 100644 Binary files a/src/lay/lay/doc/images/drc_extent_refs31.png and b/src/lay/lay/doc/images/drc_extent_refs31.png differ diff --git a/src/lay/lay/doc/images/drc_extents1.png b/src/lay/lay/doc/images/drc_extents1.png index edc3fa060..5f9c37e02 100644 Binary files a/src/lay/lay/doc/images/drc_extents1.png and b/src/lay/lay/doc/images/drc_extents1.png differ diff --git a/src/lay/lay/doc/images/drc_extents2.png b/src/lay/lay/doc/images/drc_extents2.png index bb14947ce..29608ac31 100644 Binary files a/src/lay/lay/doc/images/drc_extents2.png and b/src/lay/lay/doc/images/drc_extents2.png differ diff --git a/src/lay/lay/doc/images/drc_holes.png b/src/lay/lay/doc/images/drc_holes.png index e245a0b88..c56f83164 100644 Binary files a/src/lay/lay/doc/images/drc_holes.png and b/src/lay/lay/doc/images/drc_holes.png differ diff --git a/src/lay/lay/doc/images/drc_hulls.png b/src/lay/lay/doc/images/drc_hulls.png index 65ef90930..e3f6fd16e 100644 Binary files a/src/lay/lay/doc/images/drc_hulls.png and b/src/lay/lay/doc/images/drc_hulls.png differ diff --git a/src/lay/lay/doc/images/drc_in.png b/src/lay/lay/doc/images/drc_in.png index 75ba7043b..b3017edb3 100644 Binary files a/src/lay/lay/doc/images/drc_in.png and b/src/lay/lay/doc/images/drc_in.png differ diff --git a/src/lay/lay/doc/images/drc_inside.png b/src/lay/lay/doc/images/drc_inside.png index 3e8e74b0f..03cf210a6 100644 Binary files a/src/lay/lay/doc/images/drc_inside.png and b/src/lay/lay/doc/images/drc_inside.png differ diff --git a/src/lay/lay/doc/images/drc_inside_part.png b/src/lay/lay/doc/images/drc_inside_part.png index eb827a8b1..0d407c4dd 100644 Binary files a/src/lay/lay/doc/images/drc_inside_part.png and b/src/lay/lay/doc/images/drc_inside_part.png differ diff --git a/src/lay/lay/doc/images/drc_interacting.png b/src/lay/lay/doc/images/drc_interacting.png index 96de49249..9feceacdc 100644 Binary files a/src/lay/lay/doc/images/drc_interacting.png and b/src/lay/lay/doc/images/drc_interacting.png differ diff --git a/src/lay/lay/doc/images/drc_join1.png b/src/lay/lay/doc/images/drc_join1.png index 74c2b4354..93422273d 100644 Binary files a/src/lay/lay/doc/images/drc_join1.png and b/src/lay/lay/doc/images/drc_join1.png differ diff --git a/src/lay/lay/doc/images/drc_join2.png b/src/lay/lay/doc/images/drc_join2.png index c6c751efe..b0dfc41d8 100644 Binary files a/src/lay/lay/doc/images/drc_join2.png and b/src/lay/lay/doc/images/drc_join2.png differ diff --git a/src/lay/lay/doc/images/drc_merged1.png b/src/lay/lay/doc/images/drc_merged1.png index 2f02b2930..d6c2d3e6d 100644 Binary files a/src/lay/lay/doc/images/drc_merged1.png and b/src/lay/lay/doc/images/drc_merged1.png differ diff --git a/src/lay/lay/doc/images/drc_merged2.png b/src/lay/lay/doc/images/drc_merged2.png index 76ea5368e..c5aec6c9d 100644 Binary files a/src/lay/lay/doc/images/drc_merged2.png and b/src/lay/lay/doc/images/drc_merged2.png differ diff --git a/src/lay/lay/doc/images/drc_merged3.png b/src/lay/lay/doc/images/drc_merged3.png index 2f7ead9dd..12bc538b5 100644 Binary files a/src/lay/lay/doc/images/drc_merged3.png and b/src/lay/lay/doc/images/drc_merged3.png differ diff --git a/src/lay/lay/doc/images/drc_merged4.png b/src/lay/lay/doc/images/drc_merged4.png index 0dc6f5580..e744c80fe 100644 Binary files a/src/lay/lay/doc/images/drc_merged4.png and b/src/lay/lay/doc/images/drc_merged4.png differ diff --git a/src/lay/lay/doc/images/drc_middle1.png b/src/lay/lay/doc/images/drc_middle1.png index 4fddc996b..335793134 100644 Binary files a/src/lay/lay/doc/images/drc_middle1.png and b/src/lay/lay/doc/images/drc_middle1.png differ diff --git a/src/lay/lay/doc/images/drc_moved1.png b/src/lay/lay/doc/images/drc_moved1.png index 649de520a..40319a781 100644 Binary files a/src/lay/lay/doc/images/drc_moved1.png and b/src/lay/lay/doc/images/drc_moved1.png differ diff --git a/src/lay/lay/doc/images/drc_not1.png b/src/lay/lay/doc/images/drc_not1.png index c62d8a9d3..dad0049f2 100644 Binary files a/src/lay/lay/doc/images/drc_not1.png and b/src/lay/lay/doc/images/drc_not1.png differ diff --git a/src/lay/lay/doc/images/drc_not2.png b/src/lay/lay/doc/images/drc_not2.png index c501c3ada..e3f229224 100644 Binary files a/src/lay/lay/doc/images/drc_not2.png and b/src/lay/lay/doc/images/drc_not2.png differ diff --git a/src/lay/lay/doc/images/drc_not3.png b/src/lay/lay/doc/images/drc_not3.png index 51b96ba4f..4a4553a3d 100644 Binary files a/src/lay/lay/doc/images/drc_not3.png and b/src/lay/lay/doc/images/drc_not3.png differ diff --git a/src/lay/lay/doc/images/drc_not_in.png b/src/lay/lay/doc/images/drc_not_in.png index c3e7986b3..a2556074c 100644 Binary files a/src/lay/lay/doc/images/drc_not_in.png and b/src/lay/lay/doc/images/drc_not_in.png differ diff --git a/src/lay/lay/doc/images/drc_not_inside.png b/src/lay/lay/doc/images/drc_not_inside.png index aa4c880eb..48398c45a 100644 Binary files a/src/lay/lay/doc/images/drc_not_inside.png and b/src/lay/lay/doc/images/drc_not_inside.png differ diff --git a/src/lay/lay/doc/images/drc_not_interacting.png b/src/lay/lay/doc/images/drc_not_interacting.png index 27a48eb06..3455d262b 100644 Binary files a/src/lay/lay/doc/images/drc_not_interacting.png and b/src/lay/lay/doc/images/drc_not_interacting.png differ diff --git a/src/lay/lay/doc/images/drc_not_outside.png b/src/lay/lay/doc/images/drc_not_outside.png index e6ede552a..738af1cb8 100644 Binary files a/src/lay/lay/doc/images/drc_not_outside.png and b/src/lay/lay/doc/images/drc_not_outside.png differ diff --git a/src/lay/lay/doc/images/drc_not_overlapping.png b/src/lay/lay/doc/images/drc_not_overlapping.png index 89f571221..254bac8c6 100644 Binary files a/src/lay/lay/doc/images/drc_not_overlapping.png and b/src/lay/lay/doc/images/drc_not_overlapping.png differ diff --git a/src/lay/lay/doc/images/drc_or1.png b/src/lay/lay/doc/images/drc_or1.png index 78386d1ff..a14ec27eb 100644 Binary files a/src/lay/lay/doc/images/drc_or1.png and b/src/lay/lay/doc/images/drc_or1.png differ diff --git a/src/lay/lay/doc/images/drc_or2.png b/src/lay/lay/doc/images/drc_or2.png index ae2974fa0..76fa8b7e4 100644 Binary files a/src/lay/lay/doc/images/drc_or2.png and b/src/lay/lay/doc/images/drc_or2.png differ diff --git a/src/lay/lay/doc/images/drc_outside.png b/src/lay/lay/doc/images/drc_outside.png index 190b2537c..c12dfb826 100644 Binary files a/src/lay/lay/doc/images/drc_outside.png and b/src/lay/lay/doc/images/drc_outside.png differ diff --git a/src/lay/lay/doc/images/drc_outside_part.png b/src/lay/lay/doc/images/drc_outside_part.png index 16789b517..8e3552e70 100644 Binary files a/src/lay/lay/doc/images/drc_outside_part.png and b/src/lay/lay/doc/images/drc_outside_part.png differ diff --git a/src/lay/lay/doc/images/drc_overlap1.png b/src/lay/lay/doc/images/drc_overlap1.png index 75d18813d..8a3653124 100644 Binary files a/src/lay/lay/doc/images/drc_overlap1.png and b/src/lay/lay/doc/images/drc_overlap1.png differ diff --git a/src/lay/lay/doc/images/drc_overlap2.png b/src/lay/lay/doc/images/drc_overlap2.png index 06d17e418..dbcea6cf9 100644 Binary files a/src/lay/lay/doc/images/drc_overlap2.png and b/src/lay/lay/doc/images/drc_overlap2.png differ diff --git a/src/lay/lay/doc/images/drc_overlapping.png b/src/lay/lay/doc/images/drc_overlapping.png index 2afb3ba85..33ebb1460 100644 Binary files a/src/lay/lay/doc/images/drc_overlapping.png and b/src/lay/lay/doc/images/drc_overlapping.png differ diff --git a/src/lay/lay/doc/images/drc_raw1.png b/src/lay/lay/doc/images/drc_raw1.png index fa2b1e6fd..3fea7103b 100644 Binary files a/src/lay/lay/doc/images/drc_raw1.png and b/src/lay/lay/doc/images/drc_raw1.png differ diff --git a/src/lay/lay/doc/images/drc_raw2.png b/src/lay/lay/doc/images/drc_raw2.png index 6bc582de5..3391b35e5 100644 Binary files a/src/lay/lay/doc/images/drc_raw2.png and b/src/lay/lay/doc/images/drc_raw2.png differ diff --git a/src/lay/lay/doc/images/drc_raw3.png b/src/lay/lay/doc/images/drc_raw3.png index 0288c1784..f4146586e 100644 Binary files a/src/lay/lay/doc/images/drc_raw3.png and b/src/lay/lay/doc/images/drc_raw3.png differ diff --git a/src/lay/lay/doc/images/drc_rotated1.png b/src/lay/lay/doc/images/drc_rotated1.png index 02011ed60..40bff10aa 100644 Binary files a/src/lay/lay/doc/images/drc_rotated1.png and b/src/lay/lay/doc/images/drc_rotated1.png differ diff --git a/src/lay/lay/doc/images/drc_rounded_corners.png b/src/lay/lay/doc/images/drc_rounded_corners.png index c77f0da8b..c0c8e3228 100644 Binary files a/src/lay/lay/doc/images/drc_rounded_corners.png and b/src/lay/lay/doc/images/drc_rounded_corners.png differ diff --git a/src/lay/lay/doc/images/drc_scaled1.png b/src/lay/lay/doc/images/drc_scaled1.png index 32c75761e..e29d4ecbf 100644 Binary files a/src/lay/lay/doc/images/drc_scaled1.png and b/src/lay/lay/doc/images/drc_scaled1.png differ diff --git a/src/lay/lay/doc/images/drc_separation1.png b/src/lay/lay/doc/images/drc_separation1.png index 1204d1d8a..4b370a1da 100644 Binary files a/src/lay/lay/doc/images/drc_separation1.png and b/src/lay/lay/doc/images/drc_separation1.png differ diff --git a/src/lay/lay/doc/images/drc_sized1.png b/src/lay/lay/doc/images/drc_sized1.png index c4a9d56a2..cfb54b87e 100644 Binary files a/src/lay/lay/doc/images/drc_sized1.png and b/src/lay/lay/doc/images/drc_sized1.png differ diff --git a/src/lay/lay/doc/images/drc_sized2.png b/src/lay/lay/doc/images/drc_sized2.png index af9090297..6803ba021 100644 Binary files a/src/lay/lay/doc/images/drc_sized2.png and b/src/lay/lay/doc/images/drc_sized2.png differ diff --git a/src/lay/lay/doc/images/drc_sized3.png b/src/lay/lay/doc/images/drc_sized3.png index d5a1f1ad6..090f30393 100644 Binary files a/src/lay/lay/doc/images/drc_sized3.png and b/src/lay/lay/doc/images/drc_sized3.png differ diff --git a/src/lay/lay/doc/images/drc_sized4.png b/src/lay/lay/doc/images/drc_sized4.png index d178ed236..35bb940f4 100644 Binary files a/src/lay/lay/doc/images/drc_sized4.png and b/src/lay/lay/doc/images/drc_sized4.png differ diff --git a/src/lay/lay/doc/images/drc_sized5.png b/src/lay/lay/doc/images/drc_sized5.png index 556ffb531..5efc64543 100644 Binary files a/src/lay/lay/doc/images/drc_sized5.png and b/src/lay/lay/doc/images/drc_sized5.png differ diff --git a/src/lay/lay/doc/images/drc_sized6.png b/src/lay/lay/doc/images/drc_sized6.png index c81dbdcd2..17cdf1f57 100644 Binary files a/src/lay/lay/doc/images/drc_sized6.png and b/src/lay/lay/doc/images/drc_sized6.png differ diff --git a/src/lay/lay/doc/images/drc_space1.png b/src/lay/lay/doc/images/drc_space1.png index 81b377a1a..0665068bb 100644 Binary files a/src/lay/lay/doc/images/drc_space1.png and b/src/lay/lay/doc/images/drc_space1.png differ diff --git a/src/lay/lay/doc/images/drc_space2.png b/src/lay/lay/doc/images/drc_space2.png index c4cc02b5b..65d1c9dc9 100644 Binary files a/src/lay/lay/doc/images/drc_space2.png and b/src/lay/lay/doc/images/drc_space2.png differ diff --git a/src/lay/lay/doc/images/drc_space3.png b/src/lay/lay/doc/images/drc_space3.png index db0b50898..5ac751bc3 100644 Binary files a/src/lay/lay/doc/images/drc_space3.png and b/src/lay/lay/doc/images/drc_space3.png differ diff --git a/src/lay/lay/doc/images/drc_start_segments1.png b/src/lay/lay/doc/images/drc_start_segments1.png index a6b45ecab..12ba8a091 100644 Binary files a/src/lay/lay/doc/images/drc_start_segments1.png and b/src/lay/lay/doc/images/drc_start_segments1.png differ diff --git a/src/lay/lay/doc/images/drc_start_segments2.png b/src/lay/lay/doc/images/drc_start_segments2.png index af8dfa514..806eb05ef 100644 Binary files a/src/lay/lay/doc/images/drc_start_segments2.png and b/src/lay/lay/doc/images/drc_start_segments2.png differ diff --git a/src/lay/lay/doc/images/drc_textpoly1.png b/src/lay/lay/doc/images/drc_textpoly1.png new file mode 100644 index 000000000..537997008 Binary files /dev/null and b/src/lay/lay/doc/images/drc_textpoly1.png differ diff --git a/src/lay/lay/doc/images/drc_textpoly2.png b/src/lay/lay/doc/images/drc_textpoly2.png new file mode 100644 index 000000000..6294f9f6d Binary files /dev/null and b/src/lay/lay/doc/images/drc_textpoly2.png differ diff --git a/src/lay/lay/doc/images/drc_texts1.png b/src/lay/lay/doc/images/drc_texts1.png new file mode 100644 index 000000000..af37d9f6f Binary files /dev/null and b/src/lay/lay/doc/images/drc_texts1.png differ diff --git a/src/lay/lay/doc/images/drc_texts2.png b/src/lay/lay/doc/images/drc_texts2.png new file mode 100644 index 000000000..125fc17a7 Binary files /dev/null and b/src/lay/lay/doc/images/drc_texts2.png differ diff --git a/src/lay/lay/doc/images/drc_transformed1.png b/src/lay/lay/doc/images/drc_transformed1.png index d232cbd6e..fd0ec2828 100644 Binary files a/src/lay/lay/doc/images/drc_transformed1.png and b/src/lay/lay/doc/images/drc_transformed1.png differ diff --git a/src/lay/lay/doc/images/drc_width1.png b/src/lay/lay/doc/images/drc_width1.png index 8fa847a50..75cfa7f14 100644 Binary files a/src/lay/lay/doc/images/drc_width1.png and b/src/lay/lay/doc/images/drc_width1.png differ diff --git a/src/lay/lay/doc/images/drc_width2.png b/src/lay/lay/doc/images/drc_width2.png index 1448ababb..6708ebf7d 100644 Binary files a/src/lay/lay/doc/images/drc_width2.png and b/src/lay/lay/doc/images/drc_width2.png differ diff --git a/src/lay/lay/doc/images/drc_width3.png b/src/lay/lay/doc/images/drc_width3.png index 2b4af24d9..3848ce744 100644 Binary files a/src/lay/lay/doc/images/drc_width3.png and b/src/lay/lay/doc/images/drc_width3.png differ diff --git a/src/lay/lay/doc/images/drc_width4.png b/src/lay/lay/doc/images/drc_width4.png index 727007a4b..9b281830f 100644 Binary files a/src/lay/lay/doc/images/drc_width4.png and b/src/lay/lay/doc/images/drc_width4.png differ diff --git a/src/lay/lay/doc/images/drc_with_angle1.png b/src/lay/lay/doc/images/drc_with_angle1.png index 4c9ba1f72..dadeb6727 100644 Binary files a/src/lay/lay/doc/images/drc_with_angle1.png and b/src/lay/lay/doc/images/drc_with_angle1.png differ diff --git a/src/lay/lay/doc/images/drc_with_angle2.png b/src/lay/lay/doc/images/drc_with_angle2.png index 5fe220c01..fe3b022a8 100644 Binary files a/src/lay/lay/doc/images/drc_with_angle2.png and b/src/lay/lay/doc/images/drc_with_angle2.png differ diff --git a/src/lay/lay/doc/images/drc_with_angle3.png b/src/lay/lay/doc/images/drc_with_angle3.png index 1aa664498..b3c8c978d 100644 Binary files a/src/lay/lay/doc/images/drc_with_angle3.png and b/src/lay/lay/doc/images/drc_with_angle3.png differ diff --git a/src/lay/lay/doc/images/drc_with_angle4.png b/src/lay/lay/doc/images/drc_with_angle4.png index 6e5246d2a..30aa5e33d 100644 Binary files a/src/lay/lay/doc/images/drc_with_angle4.png and b/src/lay/lay/doc/images/drc_with_angle4.png differ diff --git a/src/lay/lay/doc/images/drc_xor1.png b/src/lay/lay/doc/images/drc_xor1.png index 6a53ec961..5ca89f97b 100644 Binary files a/src/lay/lay/doc/images/drc_xor1.png and b/src/lay/lay/doc/images/drc_xor1.png differ diff --git a/src/lay/lay/doc/images/drc_xor2.png b/src/lay/lay/doc/images/drc_xor2.png index 5b391cd3f..d67542b76 100644 Binary files a/src/lay/lay/doc/images/drc_xor2.png and b/src/lay/lay/doc/images/drc_xor2.png differ 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..cf1afed49 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,50 @@ 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.
    • +
    • Boolean NOT with a polygon layer: will select those texts + which are outside of any polygon. + not_interact is a synonym for this operation.
    • +
    • As second layer for region interact: this way, polygons + can be selected which are tagged with certain texts.
    • +
    • 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

    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" diff --git a/src/lay/lay/lay.pro b/src/lay/lay/lay.pro index c5b7c4cf9..cfb7e9c75 100644 --- a/src/lay/lay/lay.pro +++ b/src/lay/lay/lay.pro @@ -165,7 +165,8 @@ RESOURCES = layBuildInMacros.qrc \ layHelpResources.qrc \ layMacroTemplates.qrc \ layResources.qrc \ - laySaltTemplates.qrc + laySaltTemplates.qrc \ + layDRCLVSHelpResources.qrc INCLUDEPATH += $$TL_INC $$GSI_INC $$DB_INC $$RDB_INC $$LAYBASIC_INC $$ANT_INC $$IMG_INC $$EDT_INC $$LYM_INC DEPENDPATH += $$TL_INC $$GSI_INC $$DB_INC $$RDB_INC $$LAYBASIC_INC $$ANT_INC $$IMG_INC $$EDT_INC $$LYM_INC diff --git a/src/lay/lay/layDRCLVSHelpResources.qrc b/src/lay/lay/layDRCLVSHelpResources.qrc new file mode 100644 index 000000000..39a37e95b --- /dev/null +++ b/src/lay/lay/layDRCLVSHelpResources.qrc @@ -0,0 +1,99 @@ + + + doc/images/drc_width1.png + doc/images/drc_width2.png + doc/images/drc_width3.png + doc/images/drc_width4.png + doc/images/drc_space1.png + doc/images/drc_space2.png + doc/images/drc_space3.png + doc/images/drc_separation1.png + doc/images/drc_raw1.png + doc/images/drc_raw2.png + doc/images/drc_raw3.png + doc/images/drc_enc1.png + doc/images/drc_enc2.png + doc/images/drc_overlap1.png + doc/images/drc_overlap2.png + doc/images/drc_start_segments1.png + doc/images/drc_start_segments2.png + doc/images/drc_end_segments1.png + doc/images/drc_end_segments2.png + doc/images/drc_centers1.png + doc/images/drc_centers2.png + doc/images/drc_extended1.png + doc/images/drc_extended2.png + doc/images/drc_extended3.png + doc/images/drc_extended4.png + doc/images/drc_extents1.png + doc/images/drc_extents2.png + doc/images/drc_inside.png + doc/images/drc_not_inside.png + doc/images/drc_outside.png + doc/images/drc_not_outside.png + doc/images/drc_interacting.png + doc/images/drc_not_interacting.png + doc/images/drc_overlapping.png + doc/images/drc_not_overlapping.png + doc/images/drc_and1.png + doc/images/drc_or1.png + doc/images/drc_xor1.png + doc/images/drc_not1.png + doc/images/drc_join1.png + doc/images/drc_and2.png + doc/images/drc_or2.png + doc/images/drc_xor2.png + doc/images/drc_not2.png + doc/images/drc_join2.png + doc/images/drc_and3.png + doc/images/drc_not3.png + doc/images/drc_inside_part.png + doc/images/drc_outside_part.png + doc/images/drc_in.png + doc/images/drc_not_in.png + doc/images/drc_hulls.png + doc/images/drc_holes.png + doc/images/drc_merged1.png + doc/images/drc_merged2.png + doc/images/drc_merged3.png + doc/images/drc_merged4.png + doc/images/drc_moved1.png + doc/images/drc_rotated1.png + doc/images/drc_scaled1.png + doc/images/drc_transformed1.png + doc/images/drc_sized1.png + doc/images/drc_sized2.png + doc/images/drc_sized3.png + doc/images/drc_sized4.png + doc/images/drc_sized5.png + doc/images/drc_sized6.png + doc/images/drc_with_angle1.png + doc/images/drc_with_angle2.png + doc/images/drc_with_angle3.png + doc/images/drc_with_angle4.png + doc/images/drc_rounded_corners.png + doc/images/drc_middle1.png + doc/images/drc_extent_refs1.png + doc/images/drc_extent_refs10.png + doc/images/drc_extent_refs11.png + doc/images/drc_extent_refs12.png + doc/images/drc_extent_refs13.png + doc/images/drc_extent_refs20.png + doc/images/drc_extent_refs21.png + doc/images/drc_extent_refs22.png + doc/images/drc_extent_refs23.png + doc/images/drc_extent_refs24.png + doc/images/drc_extent_refs25.png + doc/images/drc_extent_refs26.png + doc/images/drc_extent_refs27.png + doc/images/drc_extent_refs30.png + doc/images/drc_extent_refs31.png + doc/images/drc_corners1.png + doc/images/drc_corners2.png + doc/images/drc_corners3.png + doc/images/drc_texts1.png + doc/images/drc_texts2.png + doc/images/drc_textpoly1.png + doc/images/drc_textpoly2.png + + diff --git a/src/lay/lay/layHelpResources.qrc b/src/lay/lay/layHelpResources.qrc index d6ba81d93..731ef64c8 100644 --- a/src/lay/lay/layHelpResources.qrc +++ b/src/lay/lay/layHelpResources.qrc @@ -2,100 +2,6 @@ doc/help_format.css - - doc/navigator_sep.png - doc/images/drc_width1.png - doc/images/drc_width2.png - doc/images/drc_width3.png - doc/images/drc_width4.png - doc/images/drc_space1.png - doc/images/drc_space2.png - doc/images/drc_space3.png - doc/images/drc_separation1.png - doc/images/drc_raw1.png - doc/images/drc_raw2.png - doc/images/drc_raw3.png - doc/images/drc_enc1.png - doc/images/drc_enc2.png - doc/images/drc_overlap1.png - doc/images/drc_overlap2.png - doc/images/drc_start_segments1.png - doc/images/drc_start_segments2.png - doc/images/drc_end_segments1.png - doc/images/drc_end_segments2.png - doc/images/drc_centers1.png - doc/images/drc_centers2.png - doc/images/drc_extended1.png - doc/images/drc_extended2.png - doc/images/drc_extended3.png - doc/images/drc_extended4.png - doc/images/drc_extents1.png - doc/images/drc_extents2.png - doc/images/drc_inside.png - doc/images/drc_outside.png - doc/images/drc_interacting.png - doc/images/drc_overlapping.png - doc/images/drc_not_inside.png - doc/images/drc_not_outside.png - doc/images/drc_not_interacting.png - doc/images/drc_not_overlapping.png - doc/images/drc_and1.png - doc/images/drc_or1.png - doc/images/drc_xor1.png - doc/images/drc_not1.png - doc/images/drc_join1.png - doc/images/drc_and2.png - doc/images/drc_or2.png - doc/images/drc_xor2.png - doc/images/drc_not2.png - doc/images/drc_and3.png - doc/images/drc_not3.png - doc/images/drc_inside_part.png - doc/images/drc_outside_part.png - doc/images/drc_join2.png - doc/images/drc_in.png - doc/images/drc_not_in.png - doc/images/drc_hulls.png - doc/images/drc_holes.png - doc/images/drc_merged1.png - doc/images/drc_merged2.png - doc/images/drc_merged3.png - doc/images/drc_merged4.png - doc/images/drc_moved1.png - doc/images/drc_rotated1.png - doc/images/drc_scaled1.png - doc/images/drc_transformed1.png - doc/images/drc_sized1.png - doc/images/drc_sized2.png - doc/images/drc_sized3.png - doc/images/drc_sized4.png - doc/images/drc_sized5.png - doc/images/drc_sized6.png - doc/images/drc_with_angle1.png - doc/images/drc_with_angle2.png - doc/images/drc_with_angle3.png - doc/images/drc_with_angle4.png - doc/images/drc_rounded_corners.png - doc/images/drc_middle1.png - doc/images/drc_extent_refs1.png - doc/images/drc_extent_refs10.png - doc/images/drc_extent_refs11.png - doc/images/drc_extent_refs12.png - doc/images/drc_extent_refs13.png - doc/images/drc_extent_refs20.png - doc/images/drc_extent_refs21.png - doc/images/drc_extent_refs22.png - doc/images/drc_extent_refs23.png - doc/images/drc_extent_refs24.png - doc/images/drc_extent_refs25.png - doc/images/drc_extent_refs26.png - doc/images/drc_extent_refs27.png - doc/images/drc_extent_refs30.png - doc/images/drc_extent_refs31.png - doc/images/drc_corners1.png - doc/images/drc_corners2.png - doc/images/drc_corners3.png - doc/about/rba_notation.xml doc/about/about_libraries.xml 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 ()) { diff --git a/src/lvs/unit_tests/lvsSimpleTests.cc b/src/lvs/unit_tests/lvsSimpleTests.cc index 44ee2133e..01283fa1e 100644 --- a/src/lvs/unit_tests/lvsSimpleTests.cc +++ b/src/lvs/unit_tests/lvsSimpleTests.cc @@ -182,7 +182,13 @@ TEST(20_double_height2_inv) run_test (_this, "double_height2", "double_height2_inv.gds"); } -TEST(21_split_gate) +// testing cell specific net joining for VSS of the double-height inverter standard cell +TEST(21_double_height2_inv_texts) +{ + run_test (_this, "double_height2_texts", "double_height2_inv.gds"); +} + +TEST(22_split_gate) { run_test (_this, "nand2_split_gate", "nand2_split_gate.oas"); } diff --git a/src/plugins/streamers/cif/db_plugin/dbCIFReader.cc b/src/plugins/streamers/cif/db_plugin/dbCIFReader.cc index 8ad8894f7..c13e3c6a5 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/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/algo/deep_region_au29.gds b/testdata/algo/deep_region_au29.gds new file mode 100644 index 000000000..96a5c0c0f Binary files /dev/null and b/testdata/algo/deep_region_au29.gds differ diff --git a/testdata/algo/deep_texts_au1.gds b/testdata/algo/deep_texts_au1.gds new file mode 100644 index 000000000..6efbcec79 Binary files /dev/null and b/testdata/algo/deep_texts_au1.gds differ diff --git a/testdata/algo/deep_texts_au2.gds b/testdata/algo/deep_texts_au2.gds new file mode 100644 index 000000000..9adb95c95 Binary files /dev/null and b/testdata/algo/deep_texts_au2.gds differ diff --git a/testdata/algo/deep_texts_au3.gds b/testdata/algo/deep_texts_au3.gds new file mode 100644 index 000000000..766da2bcc Binary files /dev/null and b/testdata/algo/deep_texts_au3.gds differ diff --git a/testdata/algo/deep_texts_l1.gds b/testdata/algo/deep_texts_l1.gds new file mode 100644 index 000000000..fbde83f92 Binary files /dev/null and b/testdata/algo/deep_texts_l1.gds differ diff --git a/testdata/algo/deep_texts_l2.gds b/testdata/algo/deep_texts_l2.gds new file mode 100644 index 000000000..4db693c1a Binary files /dev/null and b/testdata/algo/deep_texts_l2.gds differ diff --git a/testdata/algo/deep_texts_l3.gds b/testdata/algo/deep_texts_l3.gds new file mode 100644 index 000000000..4db693c1a Binary files /dev/null and b/testdata/algo/deep_texts_l3.gds differ diff --git a/testdata/algo/device_extract_au1.gds b/testdata/algo/device_extract_au1.gds index 903b6bf0d..776991004 100644 Binary files a/testdata/algo/device_extract_au1.gds and b/testdata/algo/device_extract_au1.gds differ diff --git a/testdata/algo/device_extract_au1a.gds b/testdata/algo/device_extract_au1a.gds new file mode 100644 index 000000000..47ac063c7 Binary files /dev/null and b/testdata/algo/device_extract_au1a.gds differ diff --git a/testdata/algo/l2n_reader_au_p.oas b/testdata/algo/l2n_reader_au_p.oas new file mode 100644 index 000000000..83a8f061a Binary files /dev/null and b/testdata/algo/l2n_reader_au_p.oas differ 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 b56ff4d5f..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_lbl (-526 -1801) (2 2)) - rect(poly_cont (-831 -111) (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(metal1_lbl (-181 1419) (2 2)) - rect(psd (-276 524) (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)) - rect(metal2_lbl (-23161 -201) (2 2)) + text(metal2_lbl FB (-23160 -200)) ) net(2 name(OSC) rect(via1 (24435 1675) (250 250)) rect(metal2 (-325 -325) (400 400)) - rect(metal2_lbl (-201 -201) (2 2)) + text(metal2_lbl OSC (-200 -200)) ) net(3 name(VSS) - rect(metal2_lbl (-1 -1) (2 2)) + text(metal2_lbl VSS (0 0)) ) net(4 name(VDD) - rect(metal2_lbl (-1 2799) (2 2)) + 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 aeefcf946..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_lbl (-526 -1801) (2 2)) - R(poly_cont (-831 -111) (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(metal1_lbl (-181 1419) (2 2)) - R(psd (-276 524) (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)) - R(metal2_lbl (-23161 -201) (2 2)) + J(metal2_lbl FB (-23160 -200)) ) N(2 I(OSC) R(via1 (24435 1675) (250 250)) R(metal2 (-325 -325) (400 400)) - R(metal2_lbl (-201 -201) (2 2)) + J(metal2_lbl OSC (-200 -200)) ) N(3 I(VSS) - R(metal2_lbl (-1 -1) (2 2)) + J(metal2_lbl VSS (0 0)) ) N(4 I(VDD) - R(metal2_lbl (-1 2799) (2 2)) + 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 fbe139f9b..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_lbl (-526 -1801) (2 2)) - R(poly_cont (-831 -111) (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(metal1_lbl (-181 1419) (2 2)) - R(psd (-276 524) (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)) - R(metal2_lbl (-23161 -201) (2 2)) + J(metal2_lbl FB (-23160 -200)) ) N(2 I(OSC) R(via1 (24435 1675) (250 250)) R(metal2 (-325 -325) (400 400)) - R(metal2_lbl (-201 -201) (2 2)) + J(metal2_lbl OSC (-200 -200)) ) N(3 I(VSS) - R(metal2_lbl (-1 -1) (2 2)) + J(metal2_lbl VSS (0 0)) ) N(4 I(VDD) - R(metal2_lbl (-1 2799) (2 2)) + J(metal2_lbl VDD (0 2800)) ) N(5) N(6) diff --git a/testdata/buddies/buddies.rb b/testdata/buddies/buddies.rb index 92694c41b..482e714f8 100644 --- a/testdata/buddies/buddies.rb +++ b/testdata/buddies/buddies.rb @@ -17,8 +17,9 @@ # 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)) +ruby_dir = File.join(File::dirname($0), "..", "ruby") +if !$:.member?(ruby_dir) + $:.push(ruby_dir) end load("test_prologue.rb") diff --git a/testdata/buddies/test_epilogue.rb b/testdata/buddies/test_epilogue.rb deleted file mode 100644 index f0f5bacc3..000000000 --- a/testdata/buddies/test_epilogue.rb +++ /dev/null @@ -1,36 +0,0 @@ - -# In the test environment, we cannot make sure that we destroy the ruby interpreter before the RBA -# environment is shut down. Therefore we must release all RBA objects by explicitly calling the GC -# and start the test suite manually. - -err = 0 -any = nil -repeat = (ENV["TESTREPEAT"] || "1").to_i - -class MyTestRunner < Test::Unit::UI::Console::TestRunner - def initialize(suite, *args) - super(suite, *args) - end - def test_started(name) - super - end -end - -Object.constants.each do |c| - if c.to_s =~ /_TestClass$/ - repeat.times do - r = MyTestRunner::new(Object.const_get(c)).start - err += r.error_count + r.failure_count - end - any = true - end -end - -if !any - raise("No test class defined (any ending with _TestClass)") -end - -if err > 0 - raise("Tests failed (#{err} Errors + Failures)") -end - diff --git a/testdata/buddies/test_prologue.rb b/testdata/buddies/test_prologue.rb deleted file mode 100644 index 4dcd70124..000000000 --- a/testdata/buddies/test_prologue.rb +++ /dev/null @@ -1,37 +0,0 @@ - -# in MSVC environment: -if ENV["RUBY"] - ruby_libs = "#{ENV["RUBY"]}/lib/ruby/#{RUBY_VERSION}" - if !$:.member?(ruby_libs) - $:.push(ruby_libs) - end -end - -# Set this to true to disable some tests involving exceptions -$leak_check = ENV["TEST_LEAK_CHECK"] - -# Fetch location of source files and the temp files -$ut_testsrc = ENV["TESTSRC"] || raise("Environment variable $TESTSRC not set") -$ut_testtmp = ENV["TESTTMP_WITH_NAME"] || ENV["TESTTMP"] || raise("Environment variable $TESTTMP not set") - -# Pull packages from vendor drop-in -vendor = File.join($ut_testsrc, "testdata", "vendor", "ruby") -if !$:.member?(vendor) - $:.unshift(vendor) -end - -# Require Test::Unit -require 'test/unit/ui/console/testrunner' - -# TestBase is an alias for "TestCase" -Object.const_defined?(:TestBase) && Object.send(:remove_const, :TestBase) -TestBase = Test::Unit::TestCase - -# undefine existing classes - -Object.constants.each do |c| - if c.to_s =~ /_TestClass$/ - Object.send(:remove_const, c) - end -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 86825b3c5..92a97ed8a 100644 Binary files a/testdata/drc/drcSimpleTests_au8.gds and b/testdata/drc/drcSimpleTests_au8.gds differ diff --git a/testdata/drc/drcSuiteTests.drc b/testdata/drc/drcSuiteTests.drc index be4c43ed6..55cbbedd2 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,70 @@ 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) + ddup = d.dup + ddup.select_interacting(at) + ddup.output(lb + 1, dm + 1) + p = at.interacting(d) + p.output(lb + 2, dm) + atdup = at.dup + atdup.select_interacting(d) + atdup.output(lb + 2, dm + 1) + p = d.pull_interacting(at) + p.output(lb + 3, dm) + p = at.pull_interacting(d) + p.output(lb + 4, dm) + p = at - d + p.output(lb + 5, dm) + p = d.not_interacting(at) + p.output(lb + 6, dm) + ddup = d.dup + ddup.select_not_interacting(at) + ddup.output(lb + 6, dm + 1) + p = at.not_interacting(d) + p.output(lb + 7, dm) + atdup = at.dup + atdup.select_not_interacting(d) + atdup.output(lb + 7, dm + 1) + p = d.interacting(at) + p.output(lb + 8, dm) + p = d.not_interacting(at) + p.output(lb + 8, dm + 1) + p = d.pull_interacting(at) + p.output(lb + 9, dm) + p = at.pull_interacting(d) + p.output(lb + 9, dm + 1) + end if $drc_test_mode == 1 diff --git a/testdata/drc/drcSuiteTests_au1.oas b/testdata/drc/drcSuiteTests_au1.oas index 636910e6b..47716726f 100644 Binary files a/testdata/drc/drcSuiteTests_au1.oas and b/testdata/drc/drcSuiteTests_au1.oas differ diff --git a/testdata/drc/drcSuiteTests_au2.oas b/testdata/drc/drcSuiteTests_au2.oas index d9a80d47f..17b7942ef 100644 Binary files a/testdata/drc/drcSuiteTests_au2.oas and b/testdata/drc/drcSuiteTests_au2.oas differ diff --git a/testdata/drc/drcSuiteTests_au3.oas b/testdata/drc/drcSuiteTests_au3.oas index 8717c39e9..eb87b64f1 100644 Binary files a/testdata/drc/drcSuiteTests_au3.oas and b/testdata/drc/drcSuiteTests_au3.oas differ diff --git a/testdata/drc/drcSuiteTests_au4.oas b/testdata/drc/drcSuiteTests_au4.oas index 6a45d5648..969c76839 100644 Binary files a/testdata/drc/drcSuiteTests_au4.oas and b/testdata/drc/drcSuiteTests_au4.oas differ diff --git a/testdata/drc/drcSuiteTests_au5.oas b/testdata/drc/drcSuiteTests_au5.oas index c596d626f..f7bda7376 100644 Binary files a/testdata/drc/drcSuiteTests_au5.oas and b/testdata/drc/drcSuiteTests_au5.oas differ diff --git a/testdata/drc/drcSuiteTests_au6.oas b/testdata/drc/drcSuiteTests_au6.oas index bf3a28492..ae57f6a90 100644 Binary files a/testdata/drc/drcSuiteTests_au6.oas and b/testdata/drc/drcSuiteTests_au6.oas differ diff --git a/testdata/drc/drctest.gds b/testdata/drc/drctest.gds index 460e30ad8..4cea4d523 100644 Binary files a/testdata/drc/drctest.gds and b/testdata/drc/drctest.gds differ diff --git a/testdata/drc/texts.gds b/testdata/drc/texts.gds index 241b8f894..3296de656 100644 Binary files a/testdata/drc/texts.gds and b/testdata/drc/texts.gds differ diff --git a/testdata/lvs/double_height2_texts.cir b/testdata/lvs/double_height2_texts.cir new file mode 100644 index 000000000..882e59444 --- /dev/null +++ b/testdata/lvs/double_height2_texts.cir @@ -0,0 +1,17 @@ +* Extracted by KLayout + +.SUBCKT INVCHAIN ANY R ANY$1 PWR GND +X$1 ANY R R ANY$1 PWR GND INV2 +.ENDS INVCHAIN + +.SUBCKT INV2 A1 A2 Q1 Q2 R VSS +X$1 VSS R A1 Q1 INV +X$2 VSS R A2 Q2 INV +.ENDS INV2 + +.SUBCKT INV \$1 \$2 \$3 \$4 +M$1 \$4 \$3 \$2 \$4 PMOS L=0.25U W=0.95U AS=0.73625P AD=0.73625P PS=3.45U ++ PD=3.45U +M$2 \$4 \$3 \$1 \$4 NMOS L=0.25U W=0.95U AS=0.73625P AD=0.73625P PS=3.45U ++ PD=3.45U +.ENDS INV diff --git a/testdata/lvs/double_height2_texts.lvs b/testdata/lvs/double_height2_texts.lvs new file mode 100644 index 000000000..34eca592b --- /dev/null +++ b/testdata/lvs/double_height2_texts.lvs @@ -0,0 +1,135 @@ + +source($lvs_test_source) + +report_lvs($lvs_test_target_lvsdb) + +writer = write_spice(true, false) +target_netlist($lvs_test_target_cir, writer, "Extracted by KLayout") + +# needs this delegate because we use MOS3 which is not available in Spice +class SpiceReaderDelegate < RBA::NetlistSpiceReaderDelegate + + # says we want to catch these subcircuits as devices + def wants_subcircuit(name) + name == "HVNMOS" || name == "HVPMOS" + end + + # translate the element + def element(circuit, el, name, model, value, nets, params) + + if el != "M" + # all other elements are left to the standard implementation + return super + end + + if nets.size != 4 + error("Device #{model} needs four nodes") + end + + # provide a device class + cls = circuit.netlist.device_class_by_name(model) + if ! cls + cls = RBA::DeviceClassMOS3Transistor::new + cls.name = model + circuit.netlist.add(cls) + end + + # create a device + device = circuit.create_device(cls, name) + + # and configure the device + [ "S", "G", "D" ].each_with_index do |t,index| + device.connect_terminal(t, nets[index]) + end + device.set_parameter("W", params["W"] * 1e6) + device.set_parameter("L", params["L"] * 1e6) + + device + + end + +end + +reader = RBA::NetlistSpiceReader::new(SpiceReaderDelegate::new) +schematic("double_height_inv.cir", reader) + +deep + +# Drawing layers + +nwell = input(1, 0) +active = input(2, 0) +poly = input(3, 0) +poly_lbl = labels(3, 1) +diff_cont = input(4, 0) +poly_cont = input(5, 0) +metal1 = input(6, 0) +metal1_lbl = labels(6, 1) +via1 = input(7, 0) +metal2 = input(8, 0) +metal2_lbl = labels(8, 1) + +# Bulk layer for terminal provisioning + +bulk = polygon_layer + +psd = nil +nsd = nil + +# Computed layers + +active_in_nwell = active & nwell +pactive = active_in_nwell +pgate = pactive & poly +psd = pactive - pgate + +active_outside_nwell = active - nwell +nactive = active_outside_nwell +ngate = nactive & poly +nsd = nactive - ngate + +# Device extraction + +# PMOS transistor device extraction +extract_devices(mos3("PMOS"), { "SD" => psd, "G" => pgate, + "tS" => psd, "tD" => psd, "tG" => poly }) + +# NMOS transistor device extraction +extract_devices(mos3("NMOS"), { "SD" => nsd, "G" => ngate, + "tS" => nsd, "tD" => nsd, "tG" => poly }) + +# Define connectivity for netlist extraction + +# Inter-layer +connect(psd, diff_cont) +connect(nsd, diff_cont) +connect(poly, poly_cont) +connect(diff_cont, metal1) +connect(poly_cont, metal1) +connect(metal1, via1) +connect(via1, metal2) + +# attach labels +connect(poly, poly_lbl) +connect(metal1, metal1_lbl) +connect(metal2, metal2_lbl) + +# Global +connect_global(bulk, "SUBSTRATE") + +# Implicit connection of the INV2 +# VSS nets +connect_implicit("GND") +connect_implicit("?") # "R" +connect_implicit("DOESNOTEXIST") +connect_implicit("*2", "*SS") +connect_implicit("*", "R") +connect_implicit("DOESNOTEXIST", "DOESNOTEXIST") + +# Compare section + +netlist.simplify +align + +compare + diff --git a/testdata/lvs/double_height2_texts.lvsdb b/testdata/lvs/double_height2_texts.lvsdb new file mode 100644 index 000000000..b40026de2 --- /dev/null +++ b/testdata/lvs/double_height2_texts.lvsdb @@ -0,0 +1,325 @@ +#%lvsdb-klayout +J( + W(INVCHAIN) + U(0.001) + L(l3 '3/0') + L(l11 '3/1') + L(l6 '4/0') + L(l7 '2/0') + L(l8 '6/0') + L(l12 '6/1') + L(l9 '7/0') + L(l10 '8/0') + L(l13 '8/1') + L(l14) + L(l2) + L(l5) + C(l3 l3 l11 l7) + C(l11 l3) + C(l6 l6 l8 l2 l5) + C(l7 l3 l7 l8) + C(l8 l6 l7 l8 l12 l9) + C(l12 l8) + C(l9 l8 l9 l10) + C(l10 l9 l10 l13) + C(l13 l10) + C(l14 l14) + C(l2 l6 l2) + C(l5 l6 l5) + G(l14 SUBSTRATE) + K(PMOS MOS3) + K(NMOS MOS3) + D(D$PMOS PMOS + T(S + R(l2 (-900 -475) (775 950)) + ) + T(G + R(l3 (-125 -475) (250 950)) + ) + T(D + R(l2 (125 -475) (775 950)) + ) + ) + D(D$NMOS NMOS + T(S + R(l5 (-900 -475) (775 950)) + ) + T(G + R(l3 (-125 -475) (250 950)) + ) + T(D + R(l5 (125 -475) (775 950)) + ) + ) + X(INV + R((-1500 -800) (3000 4600)) + N(1 + R(l6 (290 -310) (220 220)) + R(l6 (-220 180) (220 220)) + R(l8 (-290 -690) (360 760)) + R(l9 (-305 -705) (250 250)) + R(l9 (-250 150) (250 250)) + R(l10 (-2025 -775) (3000 900)) + R(l5 (-1375 -925) (775 950)) + ) + N(2 + R(l6 (290 2490) (220 220)) + R(l6 (-220 180) (220 220)) + R(l8 (-290 -690) (360 760)) + R(l9 (-305 -705) (250 250)) + R(l9 (-250 150) (250 250)) + R(l10 (-2025 -775) (3000 900)) + R(l2 (-1375 -925) (775 950)) + ) + N(3 + R(l3 (-125 -250) (250 2500)) + R(l3 (-250 -3050) (250 1600)) + R(l3 (-250 1200) (250 1600)) + ) + N(4 + R(l6 (-510 -310) (220 220)) + R(l6 (-220 180) (220 220)) + R(l6 (-220 2180) (220 220)) + R(l6 (-220 180) (220 220)) + R(l8 (-290 -3530) (360 2840)) + R(l8 (-360 -2800) (360 760)) + R(l8 (-360 2040) (360 760)) + R(l2 (-680 -855) (775 950)) + R(l5 (-775 -3750) (775 950)) + ) + P(1) + P(2) + P(3) + P(4) + D(1 D$PMOS + Y(0 2800) + E(L 0.25) + E(W 0.95) + E(AS 0.73625) + E(AD 0.73625) + E(PS 3.45) + E(PD 3.45) + T(S 4) + T(G 3) + T(D 2) + ) + D(2 D$NMOS + Y(0 0) + E(L 0.25) + E(W 0.95) + E(AS 0.73625) + E(AD 0.73625) + E(PS 3.45) + E(PD 3.45) + T(S 4) + T(G 3) + T(D 1) + ) + ) + X(INV2 + R((0 0) (3000 9200)) + N(1 I(A1) + J(l11 A1 (1480 7110)) + ) + N(2 I(A2) + J(l11 A2 (1520 1950)) + ) + N(3 I(Q1) + J(l12 Q1 (1920 7070)) + ) + N(4 I(Q2) + J(l12 Q2 (1940 1950)) + ) + N(5 I(R) + J(l13 R (2720 5560)) + J(l13 R (-90 -1940)) + ) + N(6 I(VSS) + J(l13 VSS (2680 8390)) + J(l13 VSS (-30 -7640)) + ) + P(1 I(A1)) + P(2 I(A2)) + P(3 I(Q1)) + P(4 I(Q2)) + P(5 I(R)) + P(6 I(VSS)) + X(1 INV O(180) Y(1500 8400) + P(0 6) + P(1 5) + P(2 1) + P(3 3) + ) + X(2 INV M O(180) Y(1500 800) + P(0 6) + P(1 5) + P(2 2) + P(3 4) + ) + ) + X(INVCHAIN + R((-90 0) (3090 9200)) + N(1 I(ANY) + R(l3 (-90 6850) (1590 650)) + J(l11 ANY (-700 -350)) + ) + N(2 I(R) + J(l11 R (1480 2370)) + R(l8 (440 4580) (690 510)) + J(l12 R (-300 -290)) + ) + N(3 I(ANY) + R(l8 (-90 1720) (1890 470)) + J(l12 ANY (-1170 -230)) + ) + N(4 I(PWR) + J(l13 PWR (300 5550)) + J(l13 PWR (-10 -1990)) + ) + N(5 I(GND) + J(l13 GND (320 8400)) + J(l13 GND (-50 -7600)) + ) + P(1 I(ANY)) + P(2 I(R)) + P(3 I(ANY)) + P(4 I(PWR)) + P(5 I(GND)) + X(1 INV2 Y(0 0) + P(0 1) + P(1 2) + P(2 2) + P(3 3) + P(4 4) + P(5 5) + ) + ) +) +H( + K(PMOS MOS3) + K(NMOS MOS3) + X(INV + N(1 I(VDD)) + N(2 I(VSS)) + N(3 I(A)) + N(4 I(Q)) + P(1 I(VDD)) + P(2 I(VSS)) + P(3 I(A)) + P(4 I(Q)) + D(1 PMOS + I($1) + E(L 0.25) + E(W 0.95) + E(AS 0) + E(AD 0) + E(PS 0) + E(PD 0) + T(S 1) + T(G 3) + T(D 4) + ) + D(2 NMOS + I($3) + E(L 0.25) + E(W 0.95) + E(AS 0) + E(AD 0) + E(PS 0) + E(PD 0) + T(S 2) + T(G 3) + T(D 4) + ) + ) + X(INV2 + N(1 I(VDD)) + N(2 I(VSS)) + N(3 I(A1)) + N(4 I(Q1)) + N(5 I(A2)) + N(6 I(Q2)) + P(1 I(VDD)) + P(2 I(VSS)) + P(3 I(A1)) + P(4 I(Q1)) + P(5 I(A2)) + P(6 I(Q2)) + X(1 INV I($1) + P(0 1) + P(1 2) + P(2 3) + P(3 4) + ) + X(2 INV I($2) + P(0 1) + P(1 2) + P(2 5) + P(3 6) + ) + ) + X(INVCHAIN + N(1 I('1')) + N(2 I('2')) + N(3 I('3')) + N(4 I('4')) + N(5 I('5')) + X(1 INV2 I($2) + P(0 1) + P(1 2) + P(2 3) + P(3 4) + P(4 4) + P(5 5) + ) + ) +) +Z( + X(INV INV 1 + Z( + N(3 3 1) + N(4 4 1) + N(2 1 1) + N(1 2 1) + P(2 2 1) + P(3 3 1) + P(1 0 1) + P(0 1 1) + D(2 2 1) + D(1 1 1) + ) + ) + X(INV2 INV2 1 + Z( + N(1 3 1) + N(2 5 1) + N(3 4 W) + N(4 6 W) + N(5 1 1) + N(6 2 1) + P(0 2 1) + P(1 4 1) + P(2 3 1) + P(3 5 1) + P(4 0 1) + P(5 1 1) + X(1 1 1) + X(2 2 1) + ) + ) + X(INVCHAIN INVCHAIN 1 + Z( + N(1 3 1) + N(3 5 1) + N(5 2 1) + N(4 1 1) + N(2 4 1) + P(2 () 1) + P(0 () 1) + P(4 () 1) + P(3 () 1) + P(1 () 1) + X(1 1 1) + ) + ) +) diff --git a/testdata/lvs/inv.lvsdb b/testdata/lvs/inv.lvsdb index 4b8431f79..246a05b96 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)) + 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(l13 (-101 -851) (2 2)) - rect(l6 (-1451 49) (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(l13 (-151 -851) (2 2)) - rect(l2 (-1401 -851) (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(l10 (-51 499) (2 2)) - rect(l2 (-351 2649) (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 5f4e3fee5..3e799862b 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)) + 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(l15 (-151 -851) (2 2)) - R(l2 (-2401 -851) (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(l12 (-51 499) (2 2)) - R(l2 (-351 2649) (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(l15 (-151 -851) (2 2)) - R(l6 (-2401 49) (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 b37d55d89..e0d758a88 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)) + 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)) - rect(l12 (-201 -201) (2 2)) + 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(l12 (699 -2001) (2 2)) - rect(l2 (-1101 1299) (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(l15 (-101 -851) (2 2)) - rect(l2 (-3201 -851) (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(l15 (-101 -851) (2 2)) - rect(l6 (-3201 1399) (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 d99519cfe..4742977a2 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)) + 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)) - rect(l12 (-201 -201) (2 2)) + 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(l12 (699 -2001) (2 2)) - rect(l2 (-1101 1299) (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(l15 (-101 -851) (2 2)) - rect(l2 (-3201 -851) (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(l15 (-101 -851) (2 2)) - rect(l6 (-3201 1399) (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/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 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 diff --git a/testdata/ruby/dbTextsTest.rb b/testdata/ruby/dbTextsTest.rb new file mode 100644 index 000000000..42e1a520b --- /dev/null +++ b/testdata/ruby/dbTextsTest.rb @@ -0,0 +1,315 @@ +# 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 = 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 = [] + 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 = 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 = [] + 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)") + + 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)) + 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)") + 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)") + assert_equal(g2.pull_interacting(r).to_s, "('abc',r0 100,200)") + + end + +end + + +load("test_epilogue.rb")