mirror of https://github.com/KLayout/klayout.git
fill_with_left, implementation + tests
This commit is contained in:
parent
f0386b616a
commit
b725f5fb0f
|
|
@ -4302,13 +4302,38 @@ CODE
|
|||
# pattern = fill_pattern("FILL_CELL").shape(1, 0, box(0.0, 0.0, 1.0, 1.0)).origin(-0.5, -0.5)
|
||||
# to_fill.fill(pattern, hstep(2.0, 1.0), vstep(-1.0, 2.0), auto_origin)
|
||||
# @/code
|
||||
#
|
||||
# The fill function can only work with a target layout for output.
|
||||
# It will not work for report output.
|
||||
#
|
||||
# The layers generated by the fill cells is only available for input later in the
|
||||
# script if the output layout is identical to the input layouts.
|
||||
# If you need the area missed by the fill function, try \fill_with_left.
|
||||
|
||||
def fill(*args)
|
||||
self._fill(false, *args)
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name fill
|
||||
# @brief Fills the region with regular pattern of shapes
|
||||
# @synopsis layer.fill_with_left([ options ])
|
||||
#
|
||||
# This method has the same call syntax and functionality than \fill. Other than this method
|
||||
# it will return the area not covered by fill cells as a DRC layer.
|
||||
|
||||
def fill_with_left(*args)
|
||||
self._fill(true, *args)
|
||||
end
|
||||
|
||||
def _fill(with_left, *args)
|
||||
|
||||
m = with_left ? "fill_with_left" : "fill"
|
||||
|
||||
# generation of new cells not tested in deep mode
|
||||
@deep && raise("fill command not supported in deep mode currently")
|
||||
@deep && raise("#{m} command not supported in deep mode currently")
|
||||
|
||||
m = "fill"
|
||||
(@engine._output_layout && @engine._output_cell) || raise("#{m} command needs an output layout and output cell")
|
||||
|
||||
source = @engine.source
|
||||
row_step = nil
|
||||
|
|
@ -4359,6 +4384,8 @@ CODE
|
|||
|
||||
dbu_trans = RBA::VCplxTrans::new(1.0 / @engine.dbu)
|
||||
|
||||
result = nil
|
||||
|
||||
fill_cell = pattern.create_cell(@engine._output_layout, @engine)
|
||||
top_cell = @engine._output_cell
|
||||
ko = dbu_trans * pattern.cell_origin
|
||||
|
|
@ -4379,6 +4406,13 @@ CODE
|
|||
tp.tile_border(bx, by)
|
||||
tp.threads = (@engine.threads || 1)
|
||||
|
||||
result_arg = "nil"
|
||||
if with_left
|
||||
result = RBA::Region::new
|
||||
result_arg = "result"
|
||||
tp.output(result_arg, result)
|
||||
end
|
||||
|
||||
tp.input("region", self.data)
|
||||
tp.var("top_cell", top_cell)
|
||||
tp.var("ko", ko)
|
||||
|
|
@ -4387,16 +4421,30 @@ CODE
|
|||
tp.var("origin", origin)
|
||||
tp.var("fc_index", fc_index)
|
||||
|
||||
tp.queue(<<"END")
|
||||
var tc_box = _frame.bbox;
|
||||
var tile_box = _tile ? (tc_box & _tile.bbox) : tc_box;
|
||||
!tile_box.empty && (
|
||||
tile_box.right = tile_box.right + rs.x - 1;
|
||||
tile_box.top = tile_box.top + cs.y - 1;
|
||||
tile_box = tile_box & tc_box;
|
||||
(region & tile_box).fill(top_cell, fc_index, ko, rs, cs, origin, nil, Vector.new, nil, _tile.bbox)
|
||||
)
|
||||
if with_left
|
||||
tp.queue(<<"END")
|
||||
var tc_box = _frame.bbox;
|
||||
var tile_box = _tile ? (tc_box & _tile.bbox) : tc_box;
|
||||
!tile_box.empty && (
|
||||
tile_box = tile_box.enlarged(Vector.new(rs.x, cs.y));
|
||||
tile_box = tile_box & tc_box;
|
||||
var left = Region.new;
|
||||
(region & tile_box).fill(top_cell, fc_index, ko, rs, cs, origin, left, Vector.new, left, _tile.bbox);
|
||||
_output(#{result_arg}, left)
|
||||
)
|
||||
END
|
||||
else
|
||||
tp.queue(<<"END")
|
||||
var tc_box = _frame.bbox;
|
||||
var tile_box = _tile ? (tc_box & _tile.bbox) : tc_box;
|
||||
!tile_box.empty && (
|
||||
tile_box.right = tile_box.right + rs.x - 1;
|
||||
tile_box.top = tile_box.top + cs.y - 1;
|
||||
tile_box = tile_box & tc_box;
|
||||
(region & tile_box).fill(top_cell, fc_index, ko, rs, cs, origin, nil, Vector.new, nil, _tile.bbox)
|
||||
)
|
||||
END
|
||||
end
|
||||
|
||||
begin
|
||||
@engine._output_layout.start_changes
|
||||
|
|
@ -4409,14 +4457,20 @@ END
|
|||
|
||||
else
|
||||
|
||||
if with_left
|
||||
result = RBA::Region::new
|
||||
end
|
||||
|
||||
@engine.run_timed("\"#{m}\" in: #{@engine.src_line}", self.data) do
|
||||
self.data.fill(top_cell, fc_index, ko, rs, cs, origin)
|
||||
self.data.fill(top_cell, fc_index, ko, rs, cs, origin, result, RBA::Vector::new, result)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self.data.disable_progress
|
||||
|
||||
return result ? DRCLayer::new(@engine, result) : nil
|
||||
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ module DRC
|
|||
def initialize(name)
|
||||
@cell_name = name
|
||||
@shapes = []
|
||||
@origin = RBA::DVector::new
|
||||
@origin = nil
|
||||
end
|
||||
|
||||
def create_cell(layout, engine)
|
||||
|
|
@ -201,7 +201,12 @@ module DRC
|
|||
end
|
||||
|
||||
def cell_origin
|
||||
@origin
|
||||
@origin || self._computed_origin
|
||||
end
|
||||
|
||||
def _computed_origin
|
||||
b = self.bbox
|
||||
return b.empty? ? RBA::DVector::new : (b.p1 - RBA::DPoint::new)
|
||||
end
|
||||
|
||||
def bbox
|
||||
|
|
|
|||
|
|
@ -1203,3 +1203,13 @@ TEST(41_fillTiled)
|
|||
run_test (_this, "41", false);
|
||||
}
|
||||
|
||||
TEST(42_fillWithLeft)
|
||||
{
|
||||
run_test (_this, "42", false);
|
||||
}
|
||||
|
||||
TEST(43_fillWithLeftTiled)
|
||||
{
|
||||
run_test (_this, "43", false);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1504,9 +1504,14 @@ VariantUserClassImpl::execute_gsi (const tl::ExpressionParserContext & /*context
|
|||
tl::Heap heap;
|
||||
size_t narg = 0;
|
||||
for (gsi::MethodBase::argument_iterator a = meth->begin_arguments (); a != meth->end_arguments () && narg < args.size (); ++a, ++narg) {
|
||||
// Note: this const_cast is ugly, but it will basically enable "out" parameters
|
||||
// TODO: clean this up.
|
||||
gsi::do_on_type<writer> () (a->type (), &arglist, const_cast<tl::Variant *> (&args [narg]), *a, &heap);
|
||||
try {
|
||||
// Note: this const_cast is ugly, but it will basically enable "out" parameters
|
||||
// TODO: clean this up.
|
||||
gsi::do_on_type<writer> () (a->type (), &arglist, const_cast<tl::Variant *> (&args [narg]), *a, &heap);
|
||||
} catch (tl::Exception &ex) {
|
||||
std::string msg = ex.msg () + tl::sprintf (tl::to_string (tr (" (argument '%s')")), a->spec ()->name ());
|
||||
throw tl::Exception (msg);
|
||||
}
|
||||
}
|
||||
|
||||
SerialArgs retlist (meth->retsize ());
|
||||
|
|
@ -1518,7 +1523,12 @@ VariantUserClassImpl::execute_gsi (const tl::ExpressionParserContext & /*context
|
|||
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Iterators not supported yet (method %s, class %s)")), method.c_str (), mp_cls->name ()));
|
||||
} else {
|
||||
out = tl::Variant ();
|
||||
gsi::do_on_type<reader> () (meth->ret_type ().type (), &out, &retlist, meth->ret_type (), &heap);
|
||||
try {
|
||||
gsi::do_on_type<reader> () (meth->ret_type ().type (), &out, &retlist, meth->ret_type (), &heap);
|
||||
} catch (tl::Exception &ex) {
|
||||
std::string msg = ex.msg () + tl::to_string (tr (" (return value)"));
|
||||
throw tl::Exception (msg);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
|
||||
source $drc_test_source
|
||||
target $drc_test_target
|
||||
|
||||
if $drc_test_deep
|
||||
deep
|
||||
end
|
||||
|
||||
l1 = input(1, 0)
|
||||
|
||||
f1 = l1
|
||||
|
||||
p1 = fill_pattern("PAT1").shape(100, 0, box(0, 0, 1.um, 1.um)).origin(-0.5.um, -0.5.um)
|
||||
|
||||
f1.fill_with_left(p1, hstep(2.0, 1.0), vstep(-1.0, 2.0)).output(100, 0)
|
||||
|
||||
l1.output(1, 0)
|
||||
f1.output(10, 0)
|
||||
|
||||
Binary file not shown.
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
source $drc_test_source
|
||||
target $drc_test_target
|
||||
|
||||
if $drc_test_deep
|
||||
deep
|
||||
end
|
||||
|
||||
tiles(5, 5)
|
||||
|
||||
l1 = input(1, 0)
|
||||
|
||||
f1 = l1
|
||||
|
||||
p1 = fill_pattern("PAT1").shape(100, 0, box(0, 0, 1.um, 1.um)).origin(-0.5.um, -0.5.um)
|
||||
|
||||
f1.fill_with_left(p1, hstep(2.0, 1.0), vstep(-1.0, 2.0)).output(100, 0)
|
||||
|
||||
l1.output(1, 0)
|
||||
f1.output(10, 0)
|
||||
|
||||
Binary file not shown.
Loading…
Reference in New Issue