Added DRC test suite and "smoothed" function for DRC

This commit is contained in:
Matthias Koefferlein 2017-07-06 23:02:11 +02:00
parent 14e1c0d5bd
commit 801f83f09c
11 changed files with 668 additions and 26 deletions

View File

@ -261,6 +261,16 @@ Region::rounded_corners (double rinner, double router, unsigned int n) const
return r;
}
Region
Region::smoothed (coord_type d) const
{
Region r;
for (const_iterator p = begin_merged (); ! p.at_end (); ++p) {
r.insert (db::smooth (*p, d));
}
return r;
}
Region
Region::in (const Region &other, bool invert) const
{

View File

@ -1445,7 +1445,8 @@ public:
*/
void round_corners (double rinner, double router, unsigned int n)
{
*this = rounded_corners (rinner, router, n);
Region r = rounded_corners (rinner, router, n);
swap (r);
}
/**
@ -1453,6 +1454,22 @@ public:
*/
Region rounded_corners (double rinner, double router, unsigned int n) const;
/**
* @brief Returns the smoothed region
*
* @param d The smoothing accuracy
*/
Region smoothed (coord_type d) const;
/**
* @brief Smoothes the region (in-place)
*/
void smooth (coord_type d)
{
Region r = smoothed (d);
swap (r);
}
/**
* @brief Returns the nth polygon
*

View File

@ -132,16 +132,6 @@ static void insert_si2 (db::Region *r, db::RecursiveShapeIterator si, db::ICplxT
}
}
static db::Region &smooth (db::Region *r, db::Coord d)
{
db::Region o;
for (db::Region::const_iterator p = r->begin_merged (); ! p.at_end (); ++p) {
o.insert (db::smooth (*p, d));
}
r->swap (o);
return *r;
}
static db::Region minkowsky_sum_pe (const db::Region *r, const db::Edge &e)
{
db::Region o;
@ -1004,6 +994,26 @@ Class<db::Region> decl_Region ("Region",
"See \\round_corners for a description of this method. This version returns a new region instead of "
"modifying self (out-of-place)."
) +
method ("smooth", &db::Region::smooth,
"@brief Smoothing\n"
"@args d\n"
"@param d The smoothing tolerance (in database units)\n"
"\n"
"This method will simplify the merged polygons of the region by removing vertexes if the "
"resulting polygon stays equivalent with the original polygon. Equivalence is measured "
"in terms of a deviation which is guaranteed to not become larger than \\d."
"\n"
"This method modifies the region. \\smoothed is a method that does the same but returns a new "
"region without modifying self. Merged semantics applies for this method.\n"
) +
method ("smoothed", &db::Region::smoothed,
"@brief Smoothing\n"
"@args d\n"
"@param d The smoothing tolerance (in database units)\n"
"\n"
"See \\smooth for a description of this method. This version returns a new region instead of "
"modifying self (out-of-place). It has been introduced in version 0.25."
) +
method ("size", (db::Region & (db::Region::*) (db::Coord, db::Coord, unsigned int)) &db::Region::size,
"@brief Anisotropic sizing (biasing)\n"
"\n"
@ -1346,21 +1356,6 @@ Class<db::Region> decl_Region ("Region",
"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_ext ("smooth", &smooth,
"@brief Smooth the region\n"
"@args d\n"
"\n"
"Remove vertices that deviate by more than the distance d from the average contours.\n"
"The value d is basically the roughness which is removed.\n"
"This method will apply smoothing to all polygons in the region.\n"
"This method will modify the region it is called on.\n"
"\n"
"Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n"
"\n"
"@param d The smoothing \"roughness\".\n"
"\n"
"@return The smoothed region (self).\n"
) +
method ("holes", &db::Region::holes,
"@brief Returns the holes of the region\n"
"This method returns all holes as filled polygons.\n"

View File

@ -765,6 +765,9 @@ CODE
#
# This method return a layer wit the modified polygons. Merged semantics applies for this
# method (see \raw and \clean).
# If used with tiling, the rounded_corners function may render invalid results because
# in tiling mode, not the whole merged region may be captured. In that case, inner
# edges may appear as outer ones and their corners will receive rounding.
#
# The following image shows the effect of the "rounded_corners" method. The upper ends of
# the vertical bars are rounded with a smaller radius automatically because their width does not allow
@ -781,6 +784,23 @@ CODE
DRCLayer::new(@engine, @engine._tcmd(@data, 0, RBA::Region, :rounded_corners, prep_value(inner), prep_value(outer), n))
end
# %DRC%
# @name smoothed
# @brief Smoothes the polygons of the region
# @synopsis layer.smoothed(d)
#
# "Smoothing" returns a simplified version of the polygons. Simplification is
# achieved by removing vertices unless the resulting polygon deviates by more
# than the given distance d from the original polygon.
#
# This method return a layer wit the modified polygons. Merged semantics applies for this
# method (see \raw and \clean).
def smoothed(d)
requires_region("smoothed")
DRCLayer::new(@engine, @engine._tcmd(@data, 0, RBA::Region, :smoothed, prep_value(d)))
end
# %DRC%
# @name odd_polygons
# @brief Checks for odd polygons (self-overlapping, non-orientable)

564
testdata/drc/drctest.drc vendored Normal file
View File

@ -0,0 +1,564 @@
verbose(true)
source(File.dirname(__FILE__) + "/drctest.gds", "TOPTOP")
big_tests = false # @@@ set to true to enable all tests
0.1.um.to_s == "0.1" || raise("unexpected value")
0.1.micron.to_s == "0.1" || raise("unexpected value")
0.1.um2.to_s == "0.1" || raise("unexpected value")
0.1.mm2.to_s == "100000.0" || raise("unexpected value")
120.dbu.to_s == "0.12" || raise("unexpected value")
(0.1.um + 120.dbu).to_s == "0.22" || raise("unexpected value")
0.1.mm.to_s == "100.0" || raise("unexpected value")
1e-6.m.to_s == "1.0" || raise("unexpected value")
1.um.to_s == "1.0" || raise("unexpected value")
1.micron.to_s == "1.0" || raise("unexpected value")
1.um2.to_s == "1.0" || raise("unexpected value")
1.mm2.to_s == "1000000.0" || raise("unexpected value")
(1.um + 120.dbu).to_s == "1.12" || raise("unexpected value")
1.mm.to_s == "1000.0" || raise("unexpected value")
def run_testsuite(dm, ic, tiled = false)
lb = 100
a = input(1)
b = input(2)
c = input(3)
x = input(10)
y = input(11)
c.is_merged? == false || raise("unexpected value")
puts "--- general #{lb}"
l1 = a&b
l1.output(lb, dm)
l1.is_empty? && raise("must not be empty")
a.and(b).xor(l1).is_empty? || raise("xor not empty")
tiled || (a.and(b).is_merged? == true || raise("unexpected value"))
a.xor(b).output(lb + 1, dm)
a.xor(b).xor(a ^ b).is_empty? || raise("xor not empty")
a.not(b).output(lb + 2, dm)
a.not(b).xor(a - b).is_empty? || raise("xor not empty")
a.or(b).output(lb + 3, dm)
a.or(b).xor(a | b).is_empty? || raise("xor not empty")
a.join(b).output(lb + 4, dm)
a.join(b).xor(a + b).is_empty? || raise("xor not empty")
if !tiled
a.join(b).data.size == 16 * ic || raise("unexpected shape count")
end
c.raw.is_clean? == false || raise("unexpected value")
# c.raw switched the semantics
c.is_clean? == false || raise("unexpected value")
(c.area / ic).to_s == "10.0" || raise("unexpected value")
(c.edges.length / ic).to_s == "18.0" || raise("unexpected value")
(c.perimeter / ic).to_s == "18.0" || raise("unexpected value")
c.clean
c.is_clean? == true || raise("unexpected value")
(c.area / ic).to_s == "9.0" || raise("unexpected value")
(c.edges.length / ic).to_s == "14.0" || raise("unexpected value")
(c.perimeter / ic).to_s == "14.0" || raise("unexpected value")
(c.dup.area / ic).to_s == "9.0" || raise("unexpected value")
(c.raw.clean.area / ic).to_s == "9.0" || raise("unexpected value")
(c.area / ic).to_s == "9.0" || raise("unexpected value")
(c.raw.area / ic).to_s == "10.0" || raise("unexpected value")
c.clean
if ic == 1
c.bbox.to_s == "(-4,-5;0,-2)" || raise("unexpected value")
end
lb += 10
puts "--- centers, start_segments, end_segments #{lb}"
a.edges.centers(0.1).extended_out(0.01).output(lb, dm)
a.edges.centers(0, 0.5).extended_out(0.01).output(lb + 1, dm)
a.edges.centers(0.5, 0.5).extended_out(0.01).output(lb + 2, dm)
a.edges.start_segments(0.1).extended_out(0.01).output(lb + 3, dm)
a.edges.start_segments(0, 0.5).extended_out(0.01).output(lb + 4, dm)
a.edges.start_segments(0.5, 0.5).extended_out(0.01).output(lb + 5, dm)
a.edges.end_segments(0.1).extended_out(0.01).output(lb + 6, dm)
a.edges.end_segments(0, 0.5).extended_out(0.01).output(lb + 7, dm)
a.edges.end_segments(0.5, 0.5).extended_out(0.01).output(lb + 8, dm)
a.polygons? == true || raise("unexpected value")
a.edges? == false || raise("unexpected value")
a.edge_pairs? == false || raise("unexpected value")
a.edges.edge_pairs? == false || raise("unexpected value")
a.edges.polygons? == false || raise("unexpected value")
a.edges.edges? == true || raise("unexpected value")
a.space(0.5).edge_pairs? == true || raise("unexpected value")
a.space(0.5).polygons? == false || raise("unexpected value")
a.space(0.5).edges? == false || raise("unexpected value")
lb += 10
puts "--- extended #{lb}"
a.edges.with_length(0.6).extended(begin: 0.1, end: 0.15, out: 0.1, in: -0.05).output(lb, dm)
a.edges.with_length(0.6).extended(out: 0.1, in: -0.05).output(lb + 1, dm)
a.edges.with_length(0..0.7).extended(out: 0.1, in: -0.05).output(lb + 2, dm)
a.edges.with_length(0..0.7).extended(out: 0.1, in: -0.05, joined: true).output(lb + 3, dm)
a.edges.with_length(0..0.7).extended(begin: 0.1, end: 0.15, out: 0.1, in: 0.05, joined: true).output(lb + 4, dm)
a.edges.with_length(0..0.7).extended(0.1, 0.15, 0.1, 0.05).output(lb + 5, dm)
a.edges.with_length(0..0.7).extended(0.1, 0.15, 0.1, 0.05, true).output(lb + 6, dm)
a.edges.with_length(0..0.7).extended_out(0.1).output(lb + 7, dm)
a.edges.with_length(0..0.7).extended_in(0.1).output(lb + 8, dm)
lb += 10
puts "--- extents #{lb}"
b.extents.output(lb, dm)
lb += 10
puts "--- first_edges, second_edges, edges #{lb}"
a.enclosing(b, 0.5, whole_edges).first_edges.extended_out(0.01).output(lb, dm)
a.enclosing(b, 0.5, whole_edges).second_edges.extended_out(0.01).output(lb + 1, dm)
a.enclosing(b, 0.5, whole_edges).edges.extended_out(0.01).output(lb + 2, dm)
lb += 10
puts "--- hulls, holes #{lb}"
c.xor(b).holes.output(lb, dm)
c.xor(b).hulls.output(lb + 1, dm)
c.xor(b).xor(c.xor(b).hulls - c.xor(b).holes).is_empty? || raise("xor not empty")
lb += 10
puts "--- interacting, in, not_in #{lb}"
b.interacting(a).output(lb, dm)
b.interacting(a).in(b).output(lb + 1, dm)
(b|a).not_in(b).output(lb + 2, dm)
x.in(b).output(lb + 3, dm)
b.sized(0.1).in(b).is_empty? == true || raise("unexpected value")
lb += 10
puts "--- inside, outside, overlapping, interacting #{lb}"
b.inside(c).output(lb, dm)
b.outside(c).output(lb + 1, dm)
b.overlapping(c).output(lb + 2, dm)
b.interacting(c).output(lb + 3, dm)
bdup = b.dup
bdup.select_inside(c)
bdup.xor(b.inside(c)).output(lb + 4, dm)
bdup = b.dup
bdup.select_outside(c)
bdup.xor(b.outside(c)).output(lb + 5, dm)
bdup = b.dup
bdup.select_overlapping(c)
bdup.xor(b.overlapping(c)).output(lb + 6, dm)
bdup = b.dup
bdup.select_interacting(c)
bdup.xor(b.interacting(c)).output(lb + 7, dm)
lb += 10
puts "--- merge #{lb}"
c.raw
if !tiled
c.merged.is_merged? == true || raise("unexpected value")
end
c.merged.output(lb, dm)
c.merged(2).output(lb + 1, dm)
c.merged(3).output(lb + 2, dm)
c.clean
cdup = c.dup
cdup.merge.xor(c.merged).output(lb + 3, dm)
cdup.xor(c.merged).output(lb + 4, dm)
cdup = c.dup
cdup.merge(2).xor(c.merged(2)).output(lb + 5, dm)
cdup.xor(c.merged(2)).output(lb + 6, dm)
lb += 10
puts "--- move, transform, rotate, scale #{lb}"
c.moved(0.2, -0.1).output(lb, dm)
cdup = c.dup
cdup.move(0.2, -0.1)
cdup.xor(c.moved(0.2, -0.1)).is_empty? == true || raise("xor not empty")
t = RBA::DCplxTrans::new(0.5)
c.transformed(t).output(lb + 1, dm)
cdup = c.dup
cdup.transform(t)
cdup.xor(c.transformed(t)).is_empty? == true || raise("xor not empty")
c.scaled(0.5).output(lb + 2, dm)
cdup = c.dup
cdup.scale(0.5)
cdup.xor(c.scaled(0.5)).is_empty? == true || raise("xor not empty")
c.rotated(45).output(lb + 3, dm)
cdup = c.dup
cdup.rotate(45)
cdup.xor(c.rotated(45)).is_empty? == true || raise("xor not empty")
lb += 10
puts "--- rectangles, rectilinear #{lb}"
a.rectangles.output(lb, dm)
a.non_rectangles.output(lb + 1, dm)
a.rectilinear.output(lb + 2, dm)
a.non_rectilinear.output(lb + 3, dm)
c.raw
c.non_rectangles.output(lb + 4, dm)
c.clean
c.rectangles.output(lb + 5, dm)
lb += 10
puts "--- enclosing #{lb}"
a.enclosing(b, 0.5).polygons.output(lb, dm)
a.enclosing(b, 0.5).polygons.xor(a.enc(b, 0.5).polygons).is_empty? == true || raise("xor not empty")
a.enclosing(b, 0.5, euclidian).polygons.output(lb + 1, dm)
a.enclosing(b, 0.5, square).polygons.output(lb + 2, dm)
a.enclosing(b, 0.5, projection).polygons.output(lb + 3, dm)
a.enclosing(b, 0.5, euclidian, whole_edges).polygons.output(lb + 4, dm)
a.enclosing(b, 0.5, euclidian, projection_limits(0.4, nil)).polygons.output(lb + 5, dm)
a.enclosing(b, 0.5, euclidian, projection_limits(nil, 0.4)).polygons.output(lb + 6, dm)
a.enclosing(b, 0.5, euclidian, projection_limits(0..0.4)).polygons.output(lb + 7, dm)
lb += 10
puts "--- enclosing (edges) #{lb}"
ae = a.edges
be = b.edges
ae.enclosing(be, 0.5).polygons.output(lb, dm)
ae.enclosing(be, 0.5).polygons.xor(ae.enc(be, 0.5).polygons).is_empty? == true || raise("xor not empty")
ae.enclosing(be, 0.5, euclidian).polygons.output(lb + 1, dm)
ae.enclosing(be, 0.5, square).polygons.output(lb + 2, dm)
ae.enclosing(be, 0.5, projection).polygons.output(lb + 3, dm)
ae.enclosing(be, 0.5, euclidian, whole_edges).polygons.output(lb + 4, dm)
ae.enclosing(be, 0.5, euclidian, projection_limits(0.4, nil)).polygons.output(lb + 5, dm)
ae.enclosing(be, 0.5, euclidian, projection_limits(nil, 0.4)).polygons.output(lb + 6, dm)
ae.enclosing(be, 0.5, euclidian, projection_limits(0..0.4)).polygons.output(lb + 7, dm)
lb += 10
puts "--- isolated #{lb}"
b.isolated(0.4).polygons.output(lb, dm)
b.isolated(0.4).polygons.xor(b.iso(0.4).polygons).is_empty? == true || raise("xor not empty")
b.isolated(0.4, euclidian).polygons.output(lb + 1, dm)
b.isolated(0.4, square).polygons.output(lb + 2, dm)
b.isolated(0.4, projection).polygons.output(lb + 3, dm)
b.isolated(0.4, euclidian, whole_edges).polygons.output(lb + 4, dm)
b.isolated(0.4, euclidian, projection_limits(0.4, nil)).polygons.output(lb + 5, dm)
b.isolated(0.4, euclidian, projection_limits(nil, 0.4)).polygons.output(lb + 6, dm)
b.isolated(0.4, euclidian, projection_limits(0..0.4)).polygons.output(lb + 7, dm)
lb += 10
puts "--- notch #{lb}"
b.notch(0.4).polygons.output(lb, dm)
b.notch(0.4, euclidian).polygons.output(lb + 1, dm)
b.notch(0.4, square).polygons.output(lb + 2, dm)
b.notch(0.4, projection).polygons.output(lb + 3, dm)
b.notch(0.4, euclidian, whole_edges).polygons.output(lb + 4, dm)
b.notch(0.4, euclidian, projection_limits(0.4, nil)).polygons.output(lb + 5, dm)
b.notch(0.4, euclidian, projection_limits(nil, 0.4)).polygons.output(lb + 6, dm)
b.notch(0.4, euclidian, projection_limits(0..0.4)).polygons.output(lb + 7, dm)
lb += 10
puts "--- overlap #{lb}"
a.overlap(b, 0.5).polygons.output(lb, dm)
a.overlap(b, 0.5, euclidian).polygons.output(lb + 1, dm)
a.overlap(b, 0.5, square).polygons.output(lb + 2, dm)
a.overlap(b, 0.5, projection).polygons.output(lb + 3, dm)
a.overlap(b, 0.5, euclidian, whole_edges).polygons.output(lb + 4, dm)
a.overlap(b, 0.5, euclidian, projection_limits(0.4, nil)).polygons.output(lb + 5, dm)
a.overlap(b, 0.5, euclidian, projection_limits(nil, 0.4)).polygons.output(lb + 6, dm)
a.overlap(b, 0.5, euclidian, projection_limits(0..0.4)).polygons.output(lb + 7, dm)
lb += 10
puts "--- overlap (edges) #{lb}"
ae = a.edges
be = b.edges
ae.overlap(be, 0.5).polygons.output(lb, dm)
ae.overlap(be, 0.5, euclidian).polygons.output(lb + 1, dm)
ae.overlap(be, 0.5, square).polygons.output(lb + 2, dm)
ae.overlap(be, 0.5, projection).polygons.output(lb + 3, dm)
ae.overlap(be, 0.5, euclidian, whole_edges).polygons.output(lb + 4, dm)
ae.overlap(be, 0.5, euclidian, projection_limits(0.4, nil)).polygons.output(lb + 5, dm)
ae.overlap(be, 0.5, euclidian, projection_limits(nil, 0.4)).polygons.output(lb + 6, dm)
ae.overlap(be, 0.5, euclidian, projection_limits(0..0.4)).polygons.output(lb + 7, dm)
lb += 10
puts "--- separation #{lb}"
a.separation(b, 0.4).polygons.output(lb, dm)
a.separation(b, 0.4).polygons.xor(a.sep(b, 0.4).polygons).is_empty? == true || raise("xor not empty")
a.separation(b, 0.4, euclidian).polygons.output(lb + 1, dm)
a.separation(b, 0.4, square).polygons.output(lb + 2, dm)
a.separation(b, 0.4, projection).polygons.output(lb + 3, dm)
a.separation(b, 0.4, euclidian, whole_edges).polygons.output(lb + 4, dm)
a.separation(b, 0.4, euclidian, projection_limits(0.4, nil)).polygons.output(lb + 5, dm)
a.separation(b, 0.4, euclidian, projection_limits(nil, 0.4)).polygons.output(lb + 6, dm)
a.separation(b, 0.4, euclidian, projection_limits(0..0.4)).polygons.output(lb + 7, dm)
lb += 10
puts "--- sized #{lb}"
x.sized(0.1).output(lb, dm)
x.sized(0.1, 0).output(lb + 1, dm)
x.sized(0.1, diamond_limit).output(lb + 2, dm)
x.sized(0.1, octagon_limit).output(lb + 3, dm)
x.sized(0.1, square_limit).output(lb + 4, dm)
x.sized(0.1, acute_limit).output(lb + 5, dm)
x.sized(0.1, no_limit).output(lb + 6, dm)
xdup = x.dup
xdup.size(0.1, 0)
xdup.xor(x.sized(0.1, 0)).is_empty? == true || raise("xor not empty")
a.sized(4.0, no_limit).output(lb + 7, dm)
lb += 10
puts "--- space #{lb}"
b.space(0.4).polygons.output(lb, dm)
b.space(0.4, euclidian).polygons.output(lb + 1, dm)
b.space(0.4, square).polygons.output(lb + 2, dm)
b.space(0.4, projection).polygons.output(lb + 3, dm)
b.space(0.4, euclidian, whole_edges).polygons.output(lb + 4, dm)
b.space(0.4, euclidian, projection_limits(0.4, nil)).polygons.output(lb + 5, dm)
b.space(0.4, euclidian, projection_limits(nil, 0.4)).polygons.output(lb + 6, dm)
b.space(0.4, euclidian, projection_limits(0..0.4)).polygons.output(lb + 7, dm)
lb += 10
puts "--- space (edges) #{lb}"
be = b.edges
be.space(0.4).polygons.output(lb, dm)
be.space(0.4, euclidian).polygons.output(lb + 1, dm)
be.space(0.4, square).polygons.output(lb + 2, dm)
be.space(0.4, projection).polygons.output(lb + 3, dm)
be.space(0.4, euclidian, whole_edges).polygons.output(lb + 4, dm)
be.space(0.4, euclidian, projection_limits(0.4, nil)).polygons.output(lb + 5, dm)
be.space(0.4, euclidian, projection_limits(nil, 0.4)).polygons.output(lb + 6, dm)
be.space(0.4, euclidian, projection_limits(0..0.4)).polygons.output(lb + 7, dm)
lb += 10
puts "--- width #{lb}"
b.width(0.4).polygons.output(lb, dm)
b.width(0.4, euclidian).polygons.output(lb + 1, dm)
b.width(0.4, square).polygons.output(lb + 2, dm)
b.width(0.4, projection).polygons.output(lb + 3, dm)
b.width(0.4, euclidian, whole_edges).polygons.output(lb + 4, dm)
b.width(0.4, euclidian, projection_limits(0.4, nil)).polygons.output(lb + 5, dm)
b.width(0.4, euclidian, projection_limits(nil, 0.4)).polygons.output(lb + 6, dm)
b.width(0.4, euclidian, projection_limits(0..0.4)).polygons.output(lb + 7, dm)
lb += 10
puts "--- width (edges) #{lb}"
be = b.edges
be.width(0.4).polygons.output(lb, dm)
be.width(0.4, euclidian).polygons.output(lb + 1, dm)
be.width(0.4, square).polygons.output(lb + 2, dm)
be.width(0.4, projection).polygons.output(lb + 3, dm)
be.width(0.4, euclidian, whole_edges).polygons.output(lb + 4, dm)
be.width(0.4, euclidian, projection_limits(0.4, nil)).polygons.output(lb + 5, dm)
be.width(0.4, euclidian, projection_limits(nil, 0.4)).polygons.output(lb + 6, dm)
be.width(0.4, euclidian, projection_limits(0..0.4)).polygons.output(lb + 7, dm)
lb += 10
puts "--- with_angle #{lb}"
a.edges.with_angle(90.degree).extended_out(0.01).output(lb, dm)
a.edges.with_angle(45 .. 90.1).extended_out(0.01).output(lb + 1, dm)
a.edges.with_angle(0, 45.1).extended_out(0.01).output(lb + 2, dm)
a.edges.without_angle(90.degree).extended_out(0.01).output(lb + 3, dm)
a.edges.without_angle(45 .. 90.1).extended_out(0.01).output(lb + 4, dm)
a.edges.without_angle(0, 45.1).extended_out(0.01).output(lb + 5, dm)
a.with_angle(135).polygons.output(lb + 6, dm)
lb += 10
puts "--- with_area #{lb}"
b.with_area(0.49.um2).output(lb, dm)
b.with_area(0 .. 0.5).output(lb + 1, dm)
b.with_area(0.5, nil).output(lb + 2, dm)
b.without_area(0.49.um2).output(lb + 3, dm)
b.without_area(nil, 0.5).output(lb + 4, dm)
b.without_area(0.5, nil).output(lb + 5, dm)
lb += 10
puts "--- with_perimeter #{lb}"
b.with_perimeter(2.8.um).output(lb, dm)
b.with_perimeter(0 .. 3.um).output(lb + 1, dm)
b.with_perimeter(3.um, nil).output(lb + 2, dm)
b.without_perimeter(2.8.um).output(lb + 3, dm)
b.without_perimeter(nil, 3.um).output(lb + 4, dm)
b.without_perimeter(3.um, nil).output(lb + 5, dm)
lb += 10
puts "--- with_bbox_height #{lb}"
b.with_bbox_height(0.7.um).output(lb, dm)
b.with_bbox_height(0 .. 0.7.um+1.dbu).output(lb + 1, dm)
b.with_bbox_height(0.7.um, nil).output(lb + 2, dm)
b.without_bbox_height(0.7.um).output(lb + 3, dm)
b.without_bbox_height(nil, 0.7.um+1.dbu).output(lb + 4, dm)
b.without_bbox_height(0.7.um, nil).output(lb + 5, dm)
lb += 10
puts "--- with_bbox_width #{lb}"
b.with_bbox_width(0.7.um).output(lb, dm)
b.with_bbox_width(0 .. 0.7.um+1.dbu).output(lb + 1, dm)
b.with_bbox_width(0.7.um, nil).output(lb + 2, dm)
b.without_bbox_width(0.7.um).output(lb + 3, dm)
b.without_bbox_width(nil, 0.7.um+1.dbu).output(lb + 4, dm)
b.without_bbox_width(0.7.um, nil).output(lb + 5, dm)
lb += 10
puts "--- with_bbox_min #{lb}"
b.with_bbox_min(0.7.um).output(lb, dm)
b.with_bbox_min(0 .. 0.7.um+1.dbu).output(lb + 1, dm)
b.with_bbox_min(0.7.um, nil).output(lb + 2, dm)
b.without_bbox_min(0.7.um).output(lb + 3, dm)
b.without_bbox_min(nil, 0.7.um+1.dbu).output(lb + 4, dm)
b.without_bbox_min(0.7.um, nil).output(lb + 5, dm)
lb += 10
puts "--- with_bbox_max #{lb}"
b.with_bbox_max(0.7.um).output(lb, dm)
b.with_bbox_max(0 .. 0.7.um+1.dbu).output(lb + 1, dm)
b.with_bbox_max(0.7.um, nil).output(lb + 2, dm)
b.without_bbox_max(0.7.um).output(lb + 3, dm)
b.without_bbox_max(nil, 0.7.um+1.dbu).output(lb + 4, dm)
b.without_bbox_max(0.7.um, nil).output(lb + 5, dm)
lb += 10
puts "--- with_length #{lb}"
a.edges.with_length(0.6.um).extended_out(0.01).output(lb, dm)
a.edges.with_length(0 .. 0.6.um+1.dbu).extended_out(0.01).output(lb + 1, dm)
a.edges.with_length(0.6, nil).extended_out(0.01).output(lb + 2, dm)
a.edges.without_length(0.6.um).extended_out(0.01).output(lb + 3, dm)
a.edges.without_length(0 .. 0.6.um+1.dbu).extended_out(0.01).output(lb + 4, dm)
a.edges.without_length(0.6, nil).extended_out(0.01).output(lb + 5, dm)
lb += 10
puts "--- ongrid, snap #{lb}"
a.ongrid(0.2).polygons(1.dbu).output(lb, dm)
a.ongrid(0, 0.1).polygons(1.dbu).output(lb + 1, dm)
a.snapped(0.2).output(lb + 2, dm)
a.snapped(0, 0.1).output(lb + 3, dm)
adup = a.dup
adup.snap(0.2)
adup.xor(a.snapped(0.2)).output(lb + 4, dm)
lb += 10
puts "--- odd polygon check #{lb}"
y.odd_polygons.output(lb, dm)
end
cell("TOP")
x = polygon_layer
x.is_empty? == true || raise("unexpected value")
x.is_box? == false || raise("unexpected value")
x.insert(box(4.0, 0, 4.7, 0.7))
x.is_empty? == false || raise("unexpected value")
x.is_box? == true || raise("unexpected value")
x.insert(polygon([ p(0, 0), p(2.0, 0), p(1.0, 1.0) ]))
x.insert(polygon([ p(0, -5.0), p(2.0, -5.0), p(1.0, -6.0) ]))
x.insert(path([ p(0, -2), p(2.0, -2) ], 0.2))
x.is_box? == false || raise("unexpected value")
x.output(10, 0)
y = polygon_layer
y.insert(polygon([ p(0, 0), p(0, 1.0), p(2.0, 1.0), p(2.0, 2.0), p(1.0, 2.0), p(1.0, 0) ]))
y.output(11, 0)
a1 = input(1)
b1 = input(2)
c1 = input(3)
puts "=== Simple tests ==="
cell("TOP")
c1.rounded_corners(0.5, 0.5, 16).output(1010, 0)
c1.smoothed(1.5).output(1011, 0)
puts "=== Single-cell testsuite ==="
run_testsuite(0, 1)
output_cell("NEW")
puts "=== Foreign-cell test ==="
a1.and(b1).output(1000, 0)
cell("TOPTOP")
a1.and(b1).output(1001, 0)
if big_tests
puts "=== Multi-cell testsuite ==="
run_testsuite(1, 900)
puts "=== Multi-cell testsuite (tiled) ==="
tiles(4.1, 5.2)
# must be that big ...
tile_borders(1.um, 1.um)
threads(4)
run_testsuite(2, 900, true)
puts "=== Multi-cell testsuite (pseudo-tiled) ==="
tiles(10000.0, 10000.0)
tile_borders(0, 0)
threads(4)
run_testsuite(3, 900, true)
flat
threads(1)
puts "=== XOR ==="
(100..900).each do |lo|
a = input(lo, 0)
b = input(lo, 1)
if !a.is_empty? || !b.is_empty?
a.xor(b).output(lo, 10)
end
a = input(lo, 1)
b = input(lo, 2)
if !a.is_empty? || !b.is_empty?
a.xor(b).output(lo, 11)
end
a = input(lo, 1)
b = input(lo, 3)
if !a.is_empty? || !b.is_empty?
a.xor(b).output(lo, 12)
end
end
end
source.layout.write("drctest_out.gds")

BIN
testdata/drc/drctest.gds vendored Normal file

Binary file not shown.

14
testdata/drc/drctest2.drc vendored Normal file
View File

@ -0,0 +1,14 @@
verbose(true)
layout = RBA::Layout::new
layout.read(File.dirname(__FILE__) + "/drctest.gds")
source(layout, "TOPTOP")
layout2 = RBA::Layout::new
target(layout2)
input(3, 0).output(100, 0)
layout2.write("drctest2_out.gds")

BIN
testdata/drc/drctest2_au.oas.gz vendored Normal file

Binary file not shown.

BIN
testdata/drc/drctest_au.oas.gz vendored Normal file

Binary file not shown.

21
testdata/drc/run_drc_test.sh vendored Executable file
View File

@ -0,0 +1,21 @@
#!/bin/sh -e
# Must be run in the build directory where klayout and strcmp are located.
inst=$(dirname $0)
export LD_LIBRARY_PATH=.
make klayout
for t in drctest drctest2; do
echo "-----------------------------------------------"
echo "Run drctest.drc ..."
./klayout -zz -r $inst/$t.drc
strmcmp ${t}_out.gds $inst/${t}_au.oas.gz
done

View File

@ -260,6 +260,7 @@ class DBRegion_TestClass < TestBase
assert_equal(rr.to_s, "(0,0;0,200;11,200;12,201;14,202;16,202;18,201;19,200;100,200;100,0)")
rr.smooth(1)
assert_equal(rr.to_s, "(0,0;0,200;11,200;14,202;18,201;100,200;100,0)")
assert_equal(rr.smoothed(5).to_s, "(0,0;0,200;100,200;100,0)")
rr.smooth(5)
assert_equal(rr.to_s, "(0,0;0,200;100,200;100,0)")