mirror of https://github.com/KLayout/klayout.git
Merge pull request #2089 from KLayout/bugfix/issue-2087
Bugfix/issue 2087
This commit is contained in:
commit
ff7d7f20ee
|
|
@ -77,14 +77,16 @@ public:
|
|||
}
|
||||
|
||||
// because the rasterizer can't handle overlapping cells we need to multiply the row and columns steps
|
||||
// with an integer until the effective rasterizer pitch get big enough.
|
||||
// with an integer until the effective rasterizer pitch gets big enough.
|
||||
m_row_steps *= (m_dim.x () - 1) / (m_row_steps * m_row_step.x ()) + 1;
|
||||
m_column_steps *= (m_dim.y () - 1) / (m_column_steps * m_column_step.y ()) + 1;
|
||||
|
||||
db::Box fp_bbox = fp.box ();
|
||||
|
||||
// compensate for distortion by sheared kernel
|
||||
fp_bbox.enlarge (db::Vector (db::coord_traits<db::Coord>::rounded (double (fp_bbox.height ()) * std::abs (m_column_step.x ()) / dy), db::coord_traits<db::Coord>::rounded (double (fp_bbox.width ()) * std::abs (m_row_step.y ()) / dx)));
|
||||
db::Coord ex = std::max (std::abs (db::Coord (m_column_step.x () * m_column_steps)), std::abs (db::Coord (m_row_step.x () * m_row_steps)));
|
||||
db::Coord ey = std::max (std::abs (db::Coord (m_column_step.y () * m_column_steps)), std::abs (db::Coord (m_row_step.y () * m_row_steps)));
|
||||
fp_bbox.enlarge (db::Vector (ex, ey));
|
||||
|
||||
int columns_per_rows = (int (m_row_steps) * m_row_step.y ()) / dy;
|
||||
int rows_per_columns = (int (m_column_steps) * m_column_step.x ()) / dx;
|
||||
|
|
@ -167,6 +169,11 @@ public:
|
|||
return m_area_maps [i];
|
||||
}
|
||||
|
||||
db::AreaMap &area_map (unsigned int i)
|
||||
{
|
||||
return m_area_maps [i];
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<db::AreaMap> m_area_maps;
|
||||
db::Vector m_row_step, m_column_step;
|
||||
|
|
@ -246,7 +253,7 @@ fill_polygon_impl (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type f
|
|||
|
||||
for (unsigned int i = 0; i < am.area_maps (); ++i) {
|
||||
|
||||
const db::AreaMap &am1 = am.area_map (i);
|
||||
db::AreaMap &am1 = am.area_map (i);
|
||||
|
||||
size_t nx = am1.nx ();
|
||||
size_t ny = am1.ny ();
|
||||
|
|
@ -263,31 +270,54 @@ fill_polygon_impl (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type f
|
|||
++jj;
|
||||
}
|
||||
|
||||
ninsts += (jj - j);
|
||||
|
||||
db::Vector p0 = (am1.p0 () - db::Point ()) - kernel_origin;
|
||||
p0 += db::Vector (i * am1.d ().x (), j * am1.d ().y ());
|
||||
|
||||
db::CellInstArray array;
|
||||
|
||||
if (jj > j + 1) {
|
||||
array = db::CellInstArray (db::CellInst (fill_cell_index), db::Trans (p0), db::Vector (0, am1.d ().y ()), db::Vector (), (unsigned long) (jj - j), 1);
|
||||
// try to expand the array in x direction
|
||||
size_t ii = i + 1;
|
||||
for ( ; ii < nx; ++ii) {
|
||||
bool all = true;
|
||||
for (size_t k = j; k < jj && all; ++k) {
|
||||
all = am1.get (ii, k) == am1.pixel_area ();
|
||||
}
|
||||
if (all) {
|
||||
for (size_t k = j; k < jj; ++k) {
|
||||
// disable pixel, so we do not see it again in the following columns
|
||||
am1.get (ii, k) = 0;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ninsts += (jj - j) * (ii - i);
|
||||
|
||||
if (jj > j + 1 || ii > i + 1) {
|
||||
array = db::CellInstArray (db::CellInst (fill_cell_index), db::Trans (p0), db::Vector (0, am1.d ().y ()), db::Vector (am1.d ().x (), 0), (unsigned long) (jj - j), (unsigned long) (ii - i));
|
||||
} else {
|
||||
array = db::CellInstArray (db::CellInst (fill_cell_index), db::Trans (p0));
|
||||
}
|
||||
|
||||
{
|
||||
// In case we run this from a tiling processor we need to lock against multithread races
|
||||
tl::MutexLocker locker (&db::TilingProcessor::output_lock ());
|
||||
tl_assert (cell->layout () != 0);
|
||||
tl::MutexLocker locker (&cell->layout ()->lock ());
|
||||
cell->insert (array);
|
||||
}
|
||||
|
||||
if (remaining_parts) {
|
||||
if (am1.d ().y () == am1.p ().y ()) {
|
||||
filled_regions.push_back (db::Polygon (db::Box (db::Point (), db::Point (am1.p ().x (), am1.p ().y () * db::Coord (jj - j))).moved (kernel_origin + p0)));
|
||||
if (am1.d ().y () == am1.p ().y () && am1.d ().x () == am1.p ().x ()) {
|
||||
db::Box fill_box (db::Point (), db::Point (am1.p ().x () * db::Coord (ii - i), am1.p ().y () * db::Coord (jj - j)));
|
||||
filled_regions.push_back (db::Polygon (fill_box.enlarged (fill_margin).moved (kernel_origin + p0)));
|
||||
} else {
|
||||
db::Box fill_box (db::Point (), db::Point () + am1.p ());
|
||||
fill_box.enlarge (fill_margin);
|
||||
for (size_t k = 0; k < jj - j; ++k) {
|
||||
filled_regions.push_back (db::Polygon (db::Box (db::Point (), db::Point () + am1.p ()).moved (kernel_origin + p0 + db::Vector (0, am1.d ().y () * db::Coord (k)))));
|
||||
for (size_t l = 0; l < ii - i; ++l) {
|
||||
filled_regions.push_back (db::Polygon (fill_box.moved (kernel_origin + p0 + db::Vector (am1.d ().x () * db::Coord (l), am1.d ().y () * db::Coord (k)))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -314,19 +344,9 @@ fill_polygon_impl (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type f
|
|||
if (any_fill) {
|
||||
|
||||
if (remaining_parts) {
|
||||
|
||||
std::vector <db::Polygon> fp1;
|
||||
|
||||
if (fill_margin != db::Vector ()) {
|
||||
ep.size (filled_regions, fill_margin.x (), fill_margin.y (), fp1, 3 /*mode*/, false /*=don't resolve holes*/);
|
||||
filled_regions.swap (fp1);
|
||||
fp1.clear ();
|
||||
}
|
||||
|
||||
fp1.push_back (fp0);
|
||||
ep.boolean (fp1, filled_regions, *remaining_parts, db::BooleanOp::ANotB, false /*=don't resolve holes*/);
|
||||
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -1918,7 +1918,7 @@ rasterize_impl (const db::polygon<C> &polygon, db::area_map<C> &am)
|
|||
|
||||
area_type aa = a;
|
||||
|
||||
if (dx == py) {
|
||||
if (dx == px) {
|
||||
|
||||
box_type cell (x, y, xx, yy);
|
||||
|
||||
|
|
|
|||
|
|
@ -500,15 +500,21 @@ RecursiveShapeIterator::validate (RecursiveShapeReceiver *receiver) const
|
|||
}
|
||||
|
||||
if (mp_shapes) {
|
||||
|
||||
// Ensures the trees are built properly - this is important in MT contexts (i.e. TilingProcessor)
|
||||
// TODO: get rid of that const cast
|
||||
(const_cast <db::Shapes *> (mp_shapes))->update ();
|
||||
|
||||
start_shapes ();
|
||||
|
||||
} else if (mp_layout && (! m_has_layers || m_current_layer < m_layers.size ())) {
|
||||
|
||||
// Ensures the trees are built properly - this is important in MT contexts (i.e. TilingProcessor)
|
||||
mp_layout->update ();
|
||||
|
||||
new_cell (receiver);
|
||||
next_shape (receiver);
|
||||
|
||||
}
|
||||
|
||||
if (mp_layout && ! at_end ()) {
|
||||
|
|
|
|||
|
|
@ -1127,10 +1127,20 @@ void Shapes::reset_bbox_dirty ()
|
|||
|
||||
void Shapes::update ()
|
||||
{
|
||||
std::unique_ptr<tl::MutexLocker> locker;
|
||||
|
||||
// If not in a layout context, we should lock here against multiple calls from different threads.
|
||||
// In a layout context, the Layout object will do that for us.
|
||||
if (layout () == 0) {
|
||||
static tl::Mutex lock;
|
||||
locker.reset (new tl::MutexLocker (&lock));
|
||||
}
|
||||
|
||||
for (tl::vector<LayerBase *>::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) {
|
||||
(*l)->sort ();
|
||||
(*l)->update_bbox ();
|
||||
}
|
||||
|
||||
set_dirty (false);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -345,3 +345,35 @@ TEST(5)
|
|||
CHECKPOINT();
|
||||
db::compare_layouts (_this, ly, tl::testdata () + "/algo/fill_tool_au5.oas", db::WriteOAS);
|
||||
}
|
||||
|
||||
// issue #2087
|
||||
TEST(6)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testdata ());
|
||||
fn += "/algo/fill_tool6.gds";
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (ly);
|
||||
}
|
||||
|
||||
db::cell_index_type fill_cell = ly.cell_by_name ("FILL_CELL").second;
|
||||
db::cell_index_type top_cell = ly.cell_by_name ("TOP").second;
|
||||
unsigned int fill_layer = ly.get_layer (db::LayerProperties (1, 0));
|
||||
|
||||
db::Region fill_region (db::RecursiveShapeIterator (ly, ly.cell (top_cell), fill_layer));
|
||||
|
||||
db::Region remaining_polygons;
|
||||
|
||||
db::Vector rs (2500, 0);
|
||||
db::Vector cs (650, 2500);
|
||||
db::Box fc_box = ly.cell (fill_cell).bbox ();
|
||||
db::fill_region (&ly.cell (top_cell), fill_region, fill_cell, fc_box, rs, cs, db::Point (), false, &remaining_polygons);
|
||||
|
||||
unsigned int l100 = ly.insert_layer (db::LayerProperties (100, 0));
|
||||
remaining_polygons.insert_into (&ly, top_cell, l100);
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, ly, tl::testdata () + "/algo/fill_tool_au6.oas", db::WriteOAS);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5460,8 +5460,17 @@ CODE
|
|||
# as the reference point. The reference point will also defined the footprint of the fill cell - more precisely
|
||||
# the lower left corner. When step vectors are given, the fill cell's footprint is taken to be a rectangle
|
||||
# having the horizontal and vertical step pitch for width and height respectively. This way the fill cells
|
||||
# will be arrange seamlessly. However, the cell's dimensions can be changed, so that the fill cells
|
||||
# will be arrange seamlessly.
|
||||
#
|
||||
# However, the cell's dimensions can be changed, so that the fill cells
|
||||
# can overlap or there is a space between the cells. To change the dimensions use the "dim" method.
|
||||
# This example will use a fill cell footprint of 1x1 micrometers, regardless of the step pitch:
|
||||
#
|
||||
# @code
|
||||
# p = fill_pattern("FILL_CELL")
|
||||
# p.shape(1, 0, box(0.0, 0.0, 1.0, 1.0))
|
||||
# p.dim(1.0, 1.0)
|
||||
# @/code
|
||||
#
|
||||
# The following example specifies a fill cell with an active area of -0.5 .. 1.5 in both directions
|
||||
# (2 micron width and height). With these dimensions the fill cell's footprint is independent of the
|
||||
|
|
@ -5474,6 +5483,18 @@ CODE
|
|||
# p.dim(2.0, 2.0)
|
||||
# @/code
|
||||
#
|
||||
# Finally, the fill cell can be given a margin: this is a space around the fill cell which needs
|
||||
# to be inside the fill region. Hence, the margin can be used to implement a distance, the fill
|
||||
# cells (more precisely: their footprints) will maintain to the outside border of the fill region.
|
||||
# The following example implements a margin of 200 nm in horizontal and 250 nm in vertical direction:
|
||||
#
|
||||
# @code
|
||||
# p = fill_pattern("FILL_CELL")
|
||||
# p.shape(1, 0, box(0.0, 0.0, 1.0, 1.0))
|
||||
# p.dim(1.0, 1.0)
|
||||
# p.margin(0.2, 0.25)
|
||||
# @/code
|
||||
#
|
||||
# With these ingredients will can use the fill function. The first example fills the polygons
|
||||
# of "to_fill" with an orthogonal pattern of 1x1 micron rectangles with a pitch of 2 microns:
|
||||
#
|
||||
|
|
@ -5574,6 +5595,7 @@ CODE
|
|||
fill_cell = pattern.create_cell(@engine._output_layout, @engine)
|
||||
top_cell = @engine._output_cell
|
||||
fc_box = dbu_trans * pattern.cell_box(row_step.x, column_step.y)
|
||||
fill_margin = dbu_trans * pattern.fill_margin
|
||||
rs = dbu_trans * row_step
|
||||
cs = dbu_trans * column_step
|
||||
origin = origin ? dbu_trans * origin : nil
|
||||
|
|
@ -5604,6 +5626,7 @@ CODE
|
|||
tp.var("rs", rs)
|
||||
tp.var("cs", cs)
|
||||
tp.var("origin", origin)
|
||||
tp.var("fill_margin", fill_margin)
|
||||
tp.var("fc_index", fc_index)
|
||||
tp.var("repeat", repeat)
|
||||
tp.var("with_left", with_left)
|
||||
|
|
@ -5616,8 +5639,8 @@ CODE
|
|||
tile_box = tile_box & tc_box;
|
||||
var left = with_left ? Region.new : nil;
|
||||
repeat ?
|
||||
(region & tile_box).fill_multi(top_cell, fc_index, fc_box, rs, cs, Vector.new, left, _tile.bbox) :
|
||||
(region & tile_box).fill(top_cell, fc_index, fc_box, rs, cs, origin, left, Vector.new, left, _tile.bbox);
|
||||
(region & tile_box).fill_multi(top_cell, fc_index, fc_box, rs, cs, fill_margin, left, _tile.bbox) :
|
||||
(region & tile_box).fill(top_cell, fc_index, fc_box, rs, cs, origin, left, fill_margin, left, _tile.bbox);
|
||||
with_left && _output(#{result_arg}, left)
|
||||
)
|
||||
END
|
||||
|
|
@ -5639,9 +5662,9 @@ END
|
|||
|
||||
@engine.run_timed("\"#{m}\" in: #{@engine.src_line}", self.data) do
|
||||
if repeat
|
||||
self.data.fill_multi(top_cell, fc_index, fc_box, rs, cs, RBA::Vector::new, result)
|
||||
self.data.fill_multi(top_cell, fc_index, fc_box, rs, cs, fill_margin, result)
|
||||
else
|
||||
self.data.fill(top_cell, fc_index, fc_box, rs, cs, origin, result, RBA::Vector::new, result)
|
||||
self.data.fill(top_cell, fc_index, fc_box, rs, cs, origin, result, fill_margin, result)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -335,6 +335,7 @@ module DRC
|
|||
@shapes = []
|
||||
@origin = nil
|
||||
@dim = nil
|
||||
@margin = RBA::DVector::new
|
||||
end
|
||||
|
||||
def create_cell(layout, engine)
|
||||
|
|
@ -350,7 +351,11 @@ module DRC
|
|||
def cell_box(def_w, def_h)
|
||||
o = @origin || self._computed_origin
|
||||
d = @dim || RBA::DVector::new(def_w, def_h)
|
||||
RBA::DBox::new(o, o + d)
|
||||
RBA::DBox::new(o, o + d).enlarged(@margin)
|
||||
end
|
||||
|
||||
def fill_margin
|
||||
-@margin
|
||||
end
|
||||
|
||||
def default_xpitch
|
||||
|
|
@ -454,6 +459,20 @@ module DRC
|
|||
|
||||
end
|
||||
|
||||
def margin(w, h)
|
||||
|
||||
if !w.is_a?(1.class) && !w.is_a?(1.0.class)
|
||||
raise("w argument not numeric FillCell#dim")
|
||||
end
|
||||
if !h.is_a?(1.class) && !h.is_a?(1.0.class)
|
||||
raise("h argument not numeric FillCell#dim")
|
||||
end
|
||||
@margin = RBA::DVector::new(w, h)
|
||||
|
||||
self
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# A wrapper for the fill step definition
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2025 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 "dbReader.h"
|
||||
#include "dbTestSupport.h"
|
||||
#include "lymMacro.h"
|
||||
|
||||
TEST(1_IHPMetal1Fill)
|
||||
{
|
||||
test_is_long_runner ();
|
||||
|
||||
std::string rs = tl::testdata ();
|
||||
rs += "/drc/drcFullTest_1.drc";
|
||||
|
||||
std::string input = tl::testdata ();
|
||||
input += "/drc/drcFullTest_1.oas";
|
||||
|
||||
std::string au = tl::testdata ();
|
||||
au += "/drc/drcFullTest_au1.oas";
|
||||
|
||||
std::string output = this->tmp_file ("tmp.oas");
|
||||
|
||||
{
|
||||
// Set some variables
|
||||
lym::Macro config;
|
||||
config.set_text (tl::sprintf (
|
||||
"$drc_force_gc = true\n"
|
||||
"$drc_test_source = '%s'\n"
|
||||
"$drc_test_target = '%s'\n"
|
||||
, input, output)
|
||||
);
|
||||
config.set_interpreter (lym::Macro::Ruby);
|
||||
EXPECT_EQ (config.run (), 0);
|
||||
}
|
||||
|
||||
lym::Macro drc;
|
||||
drc.load_from (rs);
|
||||
EXPECT_EQ (drc.run (), 0);
|
||||
|
||||
db::Layout layout;
|
||||
|
||||
{
|
||||
tl::InputStream stream (output);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (_this, layout, au, db::NoNormalization);
|
||||
}
|
||||
|
||||
|
|
@ -10,6 +10,7 @@ SOURCES = \
|
|||
drcBasicTests.cc \
|
||||
drcGenericTests.cc \
|
||||
drcSimpleTests.cc \
|
||||
drcFullTests.cc \
|
||||
drcSuiteTests.cc \
|
||||
|
||||
INCLUDEPATH += $$DRC_INC $$TL_INC $$RDB_INC $$DB_INC $$GSI_INC $$LYM_INC
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,58 @@
|
|||
|
||||
source($drc_test_source)
|
||||
target($drc_test_target)
|
||||
|
||||
verbose
|
||||
|
||||
ncpu = 4
|
||||
|
||||
chip = input(189, 4)
|
||||
chip.output(189, 4)
|
||||
|
||||
# NOTE: this must not happen in tiled mode as the sealring
|
||||
# is only visible as a whole in flat mode
|
||||
sealring = source.cell("sealring")
|
||||
|
||||
metal1_seal = sealring.input(8, 0)
|
||||
metal1_seal_inner = metal1_seal.holes
|
||||
# NOTE: metal1_seal_outer is empty if there is no sealring ->
|
||||
# the full chip will be filled
|
||||
metal1_seal_outer = chip.interacting(metal1_seal_inner) - metal1_seal_inner
|
||||
|
||||
# Everything else can be done in tiled mode
|
||||
|
||||
tiles(500)
|
||||
tile_borders(2.0)
|
||||
threads(ncpu)
|
||||
|
||||
metal1 = input(8, 0)
|
||||
metal1.output(8, 0)
|
||||
metal1_fill = input(8, 22)
|
||||
metal1_nofill = input(8, 23) + metal1_seal_outer
|
||||
|
||||
metal1_dist = 0.42
|
||||
min_space_to_fill = 1.0
|
||||
|
||||
pattern = fill_pattern("METAL1_FILL1")
|
||||
pattern.shape(8, 22, box(0.0, 0.0, 5.0, 5.0))
|
||||
pattern.dim(5.0, 5.0)
|
||||
pattern.margin(metal1_dist, metal1_dist)
|
||||
|
||||
to_fill = chip - metal1_nofill - metal1
|
||||
|
||||
to_fill = to_fill.fill_with_left(pattern, hstep(7.0, 0), vstep(1.5, 7.0), multi_origin)
|
||||
|
||||
pattern = fill_pattern("METAL1_FILL2")
|
||||
pattern.shape(8, 22, box(0.0, 0.0, 2.0, 2.0))
|
||||
pattern.dim(2.0, 2.0)
|
||||
pattern.margin(metal1_dist, metal1_dist)
|
||||
|
||||
to_fill = to_fill.fill_with_left(pattern, hstep(2.42, 0), vstep(0.65, 2.42), multi_origin)
|
||||
|
||||
pattern = fill_pattern("METAL1_FILL3")
|
||||
pattern.shape(8, 22, box(0.0, 0.0, 1.2, 1.2))
|
||||
pattern.dim(1.2, 1.2)
|
||||
pattern.margin(metal1_dist, metal1_dist)
|
||||
|
||||
to_fill = to_fill.fill_with_left(pattern, hstep(1.62, 0), vstep(0.3, 1.62), multi_origin)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -14,18 +14,22 @@ f2 = extent - l1.sized(1.0)
|
|||
p1 = fill_pattern("PAT1").shape(100, 0, box(0, 0, 1.um, 1.um)).origin(-0.5.um, -0.5.um)
|
||||
p2 = fill_pattern("PAT2").shape(100, 1, box(0, 0, 1.um, 1.um)).origin(-0.5.um, -0.5.um)
|
||||
p3 = fill_pattern("PAT3").shape(100, 2, box(0, 0, 1.um, 1.um)).shape(1000, 0, box(-0.5.um, -0.5.um, 1.5.um, 1.5.um))
|
||||
p4 = fill_pattern("PAT4").shape(100, 3, box(0, 0, 1.um, 1.um)).dim(1.um, 1.um).margin(2.um, 4.um)
|
||||
|
||||
p11 = fill_pattern("PAT11").shape(101, 0, box(0, 0, 1.um, 1.um)).origin(-0.5.um, -0.5.um)
|
||||
p12 = fill_pattern("PAT12").shape(101, 1, box(0, 0, 1.um, 1.um)).origin(-0.5.um, -0.5.um)
|
||||
p13 = fill_pattern("PAT13").shape(101, 2, box(0, 0, 1.um, 1.um)).shape(1000, 0, box(-0.5.um, -0.5.um, 1.5.um, 1.5.um))
|
||||
p14 = fill_pattern("PAT14").shape(101, 3, box(0, 0, 1.um, 1.um)).dim(1.um, 1.um).margin(2.um, 4.um)
|
||||
|
||||
f1.fill(p1, hstep(2.0, 1.0), vstep(-1.0, 2.0))
|
||||
f1.fill(p2, hstep(2.0, 1.0), vstep(-1.0, 2.0), auto_origin)
|
||||
f1.fill(p3)
|
||||
f1.fill(p4, hstep(2.0, 0), vstep(0, 2.0))
|
||||
|
||||
f2.fill(p11, hstep(2.0, 1.0), vstep(-1.0, 2.0))
|
||||
f2.fill(p12, hstep(2.0, 1.0), vstep(-1.0, 2.0), auto_origin)
|
||||
f2.fill(p13)
|
||||
f2.fill(p14, hstep(2.0, 0), vstep(0, 2.0))
|
||||
|
||||
l1.output(1, 0)
|
||||
f1.output(10, 0)
|
||||
|
|
|
|||
|
|
@ -11,8 +11,12 @@ 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)
|
||||
p2 = fill_pattern("PAT1").shape(100, 1, box(0, 0, 1.um, 1.um)).dim(1.um, 1.um)
|
||||
p3 = fill_pattern("PAT1").shape(100, 2, box(0, 0, 1.um, 1.um)).dim(1.um, 1.um).margin(1.um, 2.um)
|
||||
|
||||
f1.fill_with_left(p1, hstep(2.0, 1.0), vstep(-1.0, 2.0)).output(100, 0)
|
||||
f1.fill_with_left(p1, hstep(2.0, 1.0), vstep(-1.0, 2.0)).output(101, 0)
|
||||
f1.fill_with_left(p2, hstep(2.0, 1.0), vstep(-1.0, 2.0)).output(101, 1)
|
||||
f1.fill_with_left(p3, hstep(2.0, 1.0), vstep(-1.0, 2.0)).output(101, 2)
|
||||
|
||||
l1.output(1, 0)
|
||||
f1.output(10, 0)
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue