diff --git a/src/db/db/dbDeepEdges.cc b/src/db/db/dbDeepEdges.cc index 4b9eec059..5f556ad5a 100644 --- a/src/db/db/dbDeepEdges.cc +++ b/src/db/db/dbDeepEdges.cc @@ -650,11 +650,18 @@ EdgesDelegate * DeepEdges::filter_in_place (const EdgeFilterBase &filter) { // TODO: implement to be really in-place - return filtered (filter); + *this = *apply_filter (filter); + return this; } EdgesDelegate * DeepEdges::filtered (const EdgeFilterBase &filter) const +{ + return apply_filter (filter); +} + +DeepEdges * +DeepEdges::apply_filter (const EdgeFilterBase &filter) const { const db::DeepLayer &edges = filter.requires_raw_input () ? deep_layer () : merged_deep_layer (); diff --git a/src/db/db/dbDeepEdges.h b/src/db/db/dbDeepEdges.h index 662ac5cd1..2cfa35e2f 100644 --- a/src/db/db/dbDeepEdges.h +++ b/src/db/db/dbDeepEdges.h @@ -178,6 +178,8 @@ private: virtual RegionDelegate *pull_generic (const Region ®ion) const; virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, bool invert) const; virtual EdgesDelegate *selected_interacting_generic (const Region ®ion, bool invert) const; + DeepEdges *apply_filter (const EdgeFilterBase &filter) const; + template OutputContainer *processed_impl (const edge_processor &filter) const; }; diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index 078924859..893eba147 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -1085,11 +1085,18 @@ RegionDelegate * DeepRegion::filter_in_place (const PolygonFilterBase &filter) { // TODO: implement to be really in-place - return filtered (filter); + *this = *apply_filter (filter); + return this; } RegionDelegate * DeepRegion::filtered (const PolygonFilterBase &filter) const +{ + return apply_filter (filter); +} + +DeepRegion * +DeepRegion::apply_filter (const PolygonFilterBase &filter) const { const db::DeepLayer &polygons = filter.requires_raw_input () ? deep_layer () : merged_deep_layer (); diff --git a/src/db/db/dbDeepRegion.h b/src/db/db/dbDeepRegion.h index c1665d658..2dc7f6a0c 100644 --- a/src/db/db/dbDeepRegion.h +++ b/src/db/db/dbDeepRegion.h @@ -194,6 +194,7 @@ private: virtual RegionDelegate *selected_interacting_generic (const Edges &other, bool inverse) const; virtual RegionDelegate *pull_generic (const Region &other, int mode, bool touching) const; virtual EdgesDelegate *pull_generic (const Edges &other) const; + DeepRegion *apply_filter (const PolygonFilterBase &filter) const; template OutputContainer *processed_impl (const polygon_processor &filter) const; }; diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index 061b4b180..db7a95c55 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -1079,6 +1079,12 @@ DeepShapeStore::insert_as_polygons (const DeepLayer &deep_layer, db::Layout *int s->polygon (poly); out.insert (poly); + } else if (s->is_text ()) { + + db::Text t; + s->text (t); + out.insert (db::SimplePolygon (t.box ().enlarged (db::Vector (enl, enl)))); + } } diff --git a/src/db/db/dbDeepTexts.cc b/src/db/db/dbDeepTexts.cc index 479ee93c5..4878f95a1 100644 --- a/src/db/db/dbDeepTexts.cc +++ b/src/db/db/dbDeepTexts.cc @@ -231,14 +231,86 @@ TextsDelegate *DeepTexts::add (const Texts &other) const TextsDelegate *DeepTexts::filter_in_place (const TextFilterBase &filter) { - // TODO: implement - return AsIfFlatTexts::filter_in_place (filter); + // TODO: implement as really in place + *this = *apply_filter (filter); + return this; } TextsDelegate *DeepTexts::filtered (const TextFilterBase &filter) const { - // TODO: implement - return AsIfFlatTexts::filtered (filter); + return apply_filter (filter); +} + +DeepTexts *DeepTexts::apply_filter (const TextFilterBase &filter) const +{ + const db::DeepLayer &texts = deep_layer (); + + std::auto_ptr vars; + if (filter.vars ()) { + + vars.reset (new db::VariantsCollectorBase (filter.vars ())); + + vars->collect (texts.layout (), texts.initial_cell ()); + + if (filter.wants_variants ()) { + const_cast (texts).separate_variants (*vars); + } + + } + + db::Layout &layout = const_cast (texts.layout ()); + std::map > to_commit; + + std::auto_ptr res (new db::DeepTexts (texts.derived ())); + for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { + + const db::Shapes &s = c->shapes (texts.layer ()); + + if (vars.get ()) { + + const std::map &vv = vars->variants (c->cell_index ()); + for (std::map::const_iterator v = vv.begin (); v != vv.end (); ++v) { + + db::Shapes *st; + if (vv.size () == 1) { + st = & c->shapes (res->deep_layer ().layer ()); + } else { + st = & to_commit [c->cell_index ()] [v->first]; + } + + const db::ICplxTrans &tr = v->first; + + for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Texts); ! si.at_end (); ++si) { + db::Text text; + si->text (text); + if (filter.selected (text.transformed (tr))) { + st->insert (*si); + } + } + + } + + } else { + + db::Shapes &st = c->shapes (res->deep_layer ().layer ()); + + for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Texts); ! si.at_end (); ++si) { + db::Text text; + si->text (text); + if (filter.selected (text)) { + st.insert (*si); + } + } + + } + + } + + if (! to_commit.empty () && vars.get ()) { + res->deep_layer ().commit_shapes (*vars, to_commit); + } + + return res.release (); } RegionDelegate *DeepTexts::polygons (db::Coord e) const diff --git a/src/db/db/dbDeepTexts.h b/src/db/db/dbDeepTexts.h index bac1c081b..384febb33 100644 --- a/src/db/db/dbDeepTexts.h +++ b/src/db/db/dbDeepTexts.h @@ -94,6 +94,7 @@ private: DeepLayer m_deep_layer; void init (); + DeepTexts *apply_filter (const TextFilterBase &filter) const; }; } diff --git a/src/db/db/dbFlatTexts.cc b/src/db/db/dbFlatTexts.cc index 4e4152d3a..96668a150 100644 --- a/src/db/db/dbFlatTexts.cc +++ b/src/db/db/dbFlatTexts.cc @@ -207,7 +207,7 @@ FlatTexts::insert (const db::Text &t) void FlatTexts::insert (const db::Shape &shape) { - if (shape.is_edge_pair ()) { + if (shape.is_text ()) { db::Text t; shape.text (t); diff --git a/src/db/db/dbTexts.h b/src/db/db/dbTexts.h index bfba8ac50..173ce1e25 100644 --- a/src/db/db/dbTexts.h +++ b/src/db/db/dbTexts.h @@ -215,6 +215,7 @@ public: virtual bool selected (const db::Text &text) const = 0; virtual const TransformationReducer *vars () const = 0; + virtual bool wants_variants () const = 0; }; /** diff --git a/src/db/db/gsiDeclDbTexts.cc b/src/db/db/gsiDeclDbTexts.cc index c701d2a1a..749bcfbc3 100644 --- a/src/db/db/gsiDeclDbTexts.cc +++ b/src/db/db/gsiDeclDbTexts.cc @@ -159,7 +159,7 @@ static db::Texts with_text (const db::Texts *r, const std::string &text, bool in return r->filtered (f); } -static db::Texts with_pattern (const db::Texts *r, const std::string &pattern, bool inverse) +static db::Texts with_match (const db::Texts *r, const std::string &pattern, bool inverse) { db::TextPatternFilter f (pattern, inverse); return r->filtered (f); @@ -391,7 +391,7 @@ Class decl_Texts ("db", "Texts", "If \"inverse\" is false, this method returns the texts with the given string.\n" "If \"inverse\" is true, this method returns the texts not having the given string.\n" ) + - method_ext ("with_match", with_pattern, gsi::arg ("pattern"), gsi::arg ("inverse"), + method_ext ("with_match", with_match, gsi::arg ("pattern"), gsi::arg ("inverse"), "@brief Filter the text by glob pattern\n" "\"pattern\" is a glob-style pattern (e.g. \"A*\" will select all texts starting with a capital \"A\").\n" "If \"inverse\" is false, this method returns the texts matching the pattern.\n" diff --git a/src/rba/unit_tests/rba.cc b/src/rba/unit_tests/rba.cc index c7ac735e6..924514fc9 100644 --- a/src/rba/unit_tests/rba.cc +++ b/src/rba/unit_tests/rba.cc @@ -127,6 +127,7 @@ RUBYTEST (dbReaders, "dbReaders.rb") RUBYTEST (dbShapesTest, "dbShapesTest.rb") RUBYTEST (dbSimplePolygonTest, "dbSimplePolygonTest.rb") RUBYTEST (dbTextTest, "dbTextTest.rb") +RUBYTEST (dbTextsTest, "dbTextsTest.rb") RUBYTEST (dbTilingProcessorTest, "dbTilingProcessorTest.rb") RUBYTEST (dbTransTest, "dbTransTest.rb") RUBYTEST (dbVectorTest, "dbVectorTest.rb") diff --git a/testdata/ruby/dbTextsTest.rb b/testdata/ruby/dbTextsTest.rb new file mode 100644 index 000000000..9cbb4b82c --- /dev/null +++ b/testdata/ruby/dbTextsTest.rb @@ -0,0 +1,275 @@ +# encoding: UTF-8 + +# KLayout Layout Viewer +# Copyright (C) 2006-2020 Matthias Koefferlein +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +if !$:.member?(File::dirname($0)) + $:.push(File::dirname($0)) +end + +load("test_prologue.rb") + +class DBTexts_TestClass < TestBase + + # Basics + def test_1 + + r = RBA::Texts::new + assert_equal(r.to_s, "") + assert_equal(r.is_empty?, true) + assert_equal(r.size, 0) + assert_equal(r.bbox.to_s, "()") + data_id = r.data_id + + r.insert(RBA::Text::new("abc", RBA::Trans::new(RBA::Vector::new(100, -200)))) + assert_equal(data_id != r.data_id, true) + assert_equal(r.to_s, "('abc',r0 100,-200)") + r.clear + + r.insert(RBA::Text::new("uvw", RBA::Trans::new(RBA::Vector::new(110, 210)))) + assert_equal(r.to_s, "('uvw',r0 110,210)") + assert_equal(r.extents.to_s, "(109,209;109,211;111,211;111,209)") + assert_equal(r.extents(10).to_s, "(100,200;100,220;120,220;120,200)") + assert_equal(r.extents(5, 10).to_s, "(105,200;105,220;115,220;115,200)") + assert_equal(r.edges.to_s, "(110,210;110,210)") + assert_equal(r.is_empty?, false) + assert_equal(r.size, 1) + assert_equal(r[0].to_s, "('uvw',r0 110,210)") + assert_equal(r[1].to_s, "") + assert_equal(r.bbox.to_s, "(110,210;110,210)") + + assert_equal(r.moved(-10, 10).to_s, "('uvw',r0 100,220)") + assert_equal(r.moved(RBA::Point::new(-10, 10)).to_s, "('uvw',r0 100,220)") + rr = r.dup + assert_equal(rr.data_id != r.data_id, true) + rr.move(-10, 10) + assert_equal(rr.to_s, "('uvw',r0 100,220)") + rr = r.dup + rr.move(RBA::Point::new(-10, 10)) + assert_equal(rr.to_s, "('uvw',r0 100,220)") + + assert_equal(r.transformed(RBA::Trans::new(1)).to_s, "('uvw',r90 -210,110)") + assert_equal(r.transformed(RBA::ICplxTrans::new(2.0)).to_s, "('uvw',r0 220,420)") + rr = r.dup + rr.transform(RBA::Trans::new(1)) + assert_equal(rr.to_s, "('uvw',r90 -210,110)") + rr = r.dup + rr.transform(RBA::ICplxTrans::new(2.0)) + assert_equal(rr.to_s, "('uvw',r0 220,420)") + + rr = RBA::Texts::new + rr.swap(r) + assert_equal(rr.to_s, "('uvw',r0 110,210)") + assert_equal(r.to_s, "") + rr.swap(r) + assert_equal(r.to_s, "('uvw',r0 110,210)") + r.clear + + assert_equal(r.to_s, "") + assert_equal(r.is_empty?, true) + assert_equal(r.size, 0) + assert_equal(r.bbox.to_s, "()") + + texts = RBA::Texts::new + t = RBA::Texts::new + t.insert(RBA::Text::new("uvw", RBA::Trans::new(RBA::Vector::new(-110, 210)))) + texts.insert(t) + assert_equal(texts.to_s, "('uvw',r0 -110,210)") + + end + + # Basics + def test_2 + + r1 = RBA::Texts::new + r1.insert(RBA::Text::new("abc", RBA::Trans::new(RBA::Vector::new(100, -200)))) + r1.insert(RBA::Text::new("uvm", RBA::Trans::new(RBA::Vector::new(110, 210)))) + + r2 = RBA::Texts::new + r1.insert(RBA::Text::new("abc", RBA::Trans::new(RBA::Vector::new(101, -201)))) + r1.insert(RBA::Text::new("uvm", RBA::Trans::new(RBA::Vector::new(111, 211)))) + + assert_equal((r1 + r2).to_s, "('abc',r0 100,-200);('uvm',r0 110,210);('abc',r0 101,-201);('uvm',r0 111,211)") + r1 += r2 + assert_equal(r1.to_s, "('abc',r0 100,-200);('uvm',r0 110,210);('abc',r0 101,-201);('uvm',r0 111,211)") + + end + + def test_3 + + text1 = RBA::Text::new("abc", RBA::Trans::new(RBA::Vector::new(100, -200))) + text2 = RBA::Text::new("uvm", RBA::Trans::new(RBA::Vector::new(110, 210))) + text3 = RBA::Text::new("xyz", RBA::Trans::new(RBA::Vector::new(-101, 201))) + + r1 = RBA::Texts::new([ text1, text2 ]) + assert_equal(r1.to_s, "('abc',r0 100,-200);('uvm',r0 110,210)") + assert_equal(r1.with_text("abc", false).to_s, "('abc',r0 100,-200)") + assert_equal(r1.with_text("abc", true).to_s, "('uvm',r0 110,210)") + assert_equal(r1.with_match("*b*", false).to_s, "('abc',r0 100,-200)") + assert_equal(r1.with_match("*b*", true).to_s, "('uvm',r0 110,210)") + + r1 = RBA::Texts::new(text1) + assert_equal(r1.to_s, "('abc',r0 100,-200)") + + s = RBA::Shapes::new + s.insert(text1) + s.insert(text2) + r1 = RBA::Texts::new(s) + assert_equal(r1.to_s, "('abc',r0 100,-200);('uvm',r0 110,210)") + + ly = RBA::Layout::new + l1 = ly.layer("l1") + l2 = ly.layer("l2") + l3 = ly.layer("l3") + c1 = ly.create_cell("C1") + c2 = ly.create_cell("C2") + c1.insert(RBA::CellInstArray::new(c2.cell_index, RBA::Trans::new(0, 0))) + c1.insert(RBA::CellInstArray::new(c2.cell_index, RBA::Trans::new(0, 100))) + c1.insert(RBA::CellInstArray::new(c2.cell_index, RBA::Trans::new(200, 100))) + c2.shapes(l1).insert(text1) + c2.shapes(l2).insert(text2) + c2.shapes(l3).insert(text3) + + r = RBA::Texts::new(ly.begin_shapes(c1.cell_index, l1)) + assert_equal(r.to_s(30), "('abc',r0 100,-200);('abc',r0 100,-100);('abc',r0 300,-100)") + assert_equal(r.to_s(2), "('abc',r0 100,-200);('abc',r0 100,-100)...") + assert_equal(r.is_empty?, false) + assert_equal(r.size, 3) + + assert_equal(r.has_valid_texts?, false) + assert_equal(r.bbox.to_s, "(100,-200;300,-100)") + + assert_equal(r.is_deep?, false) + + r.flatten + assert_equal(r.has_valid_texts?, true) + assert_equal(r[1].to_s, "('abc',r0 100,-100)") + assert_equal(r[100].inspect, "nil") + assert_equal(r.bbox.to_s, "(100,-200;300,-100)") + + dss = RBA::DeepShapeStore::new + r = RBA::Texts::new(ly.begin_shapes(c1.cell_index, l1), dss) + assert_equal(r.to_s(30), "('abc',r0 100,-200);('abc',r0 100,-100);('abc',r0 300,-100)") + assert_equal(r.to_s(2), "('abc',r0 100,-200);('abc',r0 100,-100)...") + assert_equal(r.is_empty?, false) + assert_equal(r.size, 3) + + assert_equal(r.has_valid_texts?, false) + assert_equal(r.bbox.to_s, "(100,-200;300,-100)") + + assert_equal(r.is_deep?, true) + + r.flatten + assert_equal(r.has_valid_texts?, true) + assert_equal(r[1].to_s, "('abc',r0 100,-100)") + assert_equal(r[100].inspect, "nil") + assert_equal(r.bbox.to_s, "(100,-200;300,-100)") + + assert_equal(r.is_deep?, false) + + end + + def test_4 + + # insert_into and insert_into_as_polygons + + text1 = RBA::Text::new("abc", RBA::Trans::new(RBA::Vector::new(100, -200))) + + ly = RBA::Layout::new + l1 = ly.layer("l1") + c1 = ly.create_cell("C1") + c2 = ly.create_cell("C2") + c1.insert(RBA::CellInstArray::new(c2.cell_index, RBA::Trans::new(0, 0))) + c1.insert(RBA::CellInstArray::new(c2.cell_index, RBA::Trans::new(0, 100))) + c1.insert(RBA::CellInstArray::new(c2.cell_index, RBA::Trans::new(200, 100))) + c2.shapes(l1).insert(text1) + + dss = RBA::DeepShapeStore::new + r = RBA::Texts::new(ly.begin_shapes(c1.cell_index, l1), dss) + + target = RBA::Layout::new + target_top = target.add_cell("TOP") + target_li = target.layer + r.insert_into(target, target_top, target_li) + cells = [] + target.each_cell { |c| cells << c.name } + assert_equal(cells.join(","), "TOP,C2") + assert_equal(RBA::Texts::new(target.cell("TOP").shapes(target_li)).to_s, "") + assert_equal(RBA::Texts::new(target.cell("C2").shapes(target_li)).to_s, "('abc',r0 100,-200)") + + target_li = target.layer + r.with_text("abc", false).insert_into(target, target_top, target_li) + cells = [] + target.each_cell { |c| cells << c.name } + assert_equal(cells.join(","), "TOP,C2") + assert_equal(RBA::Texts::new(target.cell("TOP").shapes(target_li)).to_s, "") + assert_equal(RBA::Texts::new(target.cell("C2").shapes(target_li)).to_s, "('abc',r0 100,-200)") + + target_li = target.layer + r.with_text("abd", true).insert_into(target, target_top, target_li) + cells = [] + target.each_cell { |c| cells << c.name } + assert_equal(cells.join(","), "TOP,C2") + assert_equal(RBA::Texts::new(target.cell("TOP").shapes(target_li)).to_s, "") + assert_equal(RBA::Texts::new(target.cell("C2").shapes(target_li)).to_s, "('abc',r0 100,-200)") + + target_li = target.layer + r.with_text("abc", true).insert_into(target, target_top, target_li) + cells = [] + target.each_cell { |c| cells << c.name } + assert_equal(cells.join(","), "TOP,C2") + assert_equal(RBA::Texts::new(target.cell("TOP").shapes(target_li)).to_s, "") + assert_equal(RBA::Texts::new(target.cell("C2").shapes(target_li)).to_s, "") + + target_li = target.layer + r.with_match("*b*", false).insert_into(target, target_top, target_li) + cells = [] + target.each_cell { |c| cells << c.name } + assert_equal(cells.join(","), "TOP,C2") + assert_equal(RBA::Texts::new(target.cell("TOP").shapes(target_li)).to_s, "") + assert_equal(RBA::Texts::new(target.cell("C2").shapes(target_li)).to_s, "('abc',r0 100,-200)") + + target_li = target.layer + r.with_match("*bb*", true).insert_into(target, target_top, target_li) + cells = [] + target.each_cell { |c| cells << c.name } + assert_equal(cells.join(","), "TOP,C2") + assert_equal(RBA::Texts::new(target.cell("TOP").shapes(target_li)).to_s, "") + assert_equal(RBA::Texts::new(target.cell("C2").shapes(target_li)).to_s, "('abc',r0 100,-200)") + + target_li = target.layer + r.with_match("*b*", true).insert_into(target, target_top, target_li) + cells = [] + target.each_cell { |c| cells << c.name } + assert_equal(cells.join(","), "TOP,C2") + assert_equal(RBA::Texts::new(target.cell("TOP").shapes(target_li)).to_s, "") + assert_equal(RBA::Texts::new(target.cell("C2").shapes(target_li)).to_s, "") + + target_li = target.layer + r.insert_into_as_polygons(target, target_top, target_li, 1) + cells = [] + target.each_cell { |c| cells << c.name } + assert_equal(cells.join(","), "TOP,C2") + assert_equal(RBA::Region::new(target.cell("TOP").shapes(target_li)).to_s, "") + assert_equal(RBA::Region::new(target.cell("C2").shapes(target_li)).to_s, "(99,-201;99,-199;101,-199;101,-201)") + + end + +end + + +load("test_epilogue.rb")