Bugfix: in-place filter not working for region, edges. Implemented hierarchical filter for texts. Added Ruby tests for Texts.

This commit is contained in:
Matthias Koefferlein 2020-05-12 23:01:54 +02:00
parent c1b1ce6951
commit 08026e8b35
12 changed files with 382 additions and 9 deletions

View File

@ -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 ();

View File

@ -178,6 +178,8 @@ private:
virtual RegionDelegate *pull_generic (const Region &region) const;
virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, bool invert) const;
virtual EdgesDelegate *selected_interacting_generic (const Region &region, bool invert) const;
DeepEdges *apply_filter (const EdgeFilterBase &filter) const;
template <class Result, class OutputContainer> OutputContainer *processed_impl (const edge_processor<Result> &filter) const;
};

View File

@ -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 ();

View File

@ -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 <class Result, class OutputContainer> OutputContainer *processed_impl (const polygon_processor<Result> &filter) const;
};

View File

@ -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))));
}
}

View File

@ -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<VariantsCollectorBase> vars;
if (filter.vars ()) {
vars.reset (new db::VariantsCollectorBase (filter.vars ()));
vars->collect (texts.layout (), texts.initial_cell ());
if (filter.wants_variants ()) {
const_cast<db::DeepLayer &> (texts).separate_variants (*vars);
}
}
db::Layout &layout = const_cast<db::Layout &> (texts.layout ());
std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> > to_commit;
std::auto_ptr<db::DeepTexts> 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<db::ICplxTrans, size_t> &vv = vars->variants (c->cell_index ());
for (std::map<db::ICplxTrans, size_t>::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

View File

@ -94,6 +94,7 @@ private:
DeepLayer m_deep_layer;
void init ();
DeepTexts *apply_filter (const TextFilterBase &filter) const;
};
}

View File

@ -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);

View File

@ -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;
};
/**

View File

@ -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<db::Texts> 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"

View File

@ -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")

275
testdata/ruby/dbTextsTest.rb vendored Normal file
View File

@ -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")