mirror of https://github.com/KLayout/klayout.git
Merge pull request #282 from KLayout/issue-281
Fixed #281 (proper reporting of width/space violations in the kissing…
This commit is contained in:
commit
2ef403e0ac
|
|
@ -450,7 +450,7 @@ AsIfFlatEdges::run_check (db::edge_relation_type rel, const Edges *other, db::Co
|
|||
}
|
||||
|
||||
EdgeRelationFilter check (rel, d, metrics);
|
||||
check.set_include_zero (other != 0);
|
||||
check.set_include_zero (false);
|
||||
check.set_whole_edges (whole_edges);
|
||||
check.set_ignore_angle (ignore_angle);
|
||||
check.set_min_projection (min_projection);
|
||||
|
|
|
|||
|
|
@ -642,7 +642,7 @@ AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons,
|
|||
}
|
||||
|
||||
EdgeRelationFilter check (rel, d, metrics);
|
||||
check.set_include_zero (other != 0);
|
||||
check.set_include_zero (false);
|
||||
check.set_whole_edges (whole_edges);
|
||||
check.set_ignore_angle (ignore_angle);
|
||||
check.set_min_projection (min_projection);
|
||||
|
|
@ -664,6 +664,7 @@ AsIfFlatRegion::run_single_polygon_check (db::edge_relation_type rel, db::Coord
|
|||
std::auto_ptr<FlatEdgePairs> result (new FlatEdgePairs ());
|
||||
|
||||
EdgeRelationFilter check (rel, d, metrics);
|
||||
check.set_include_zero (false);
|
||||
check.set_whole_edges (whole_edges);
|
||||
check.set_ignore_angle (ignore_angle);
|
||||
check.set_min_projection (min_projection);
|
||||
|
|
|
|||
|
|
@ -1404,6 +1404,7 @@ DeepEdges::run_check (db::edge_relation_type rel, const Edges *other, db::Coord
|
|||
ensure_merged_edges_valid ();
|
||||
|
||||
EdgeRelationFilter check (rel, d, metrics);
|
||||
check.set_include_zero (false);
|
||||
check.set_whole_edges (whole_edges);
|
||||
check.set_ignore_angle (ignore_angle);
|
||||
check.set_min_projection (min_projection);
|
||||
|
|
|
|||
|
|
@ -1466,6 +1466,7 @@ DeepRegion::run_check (db::edge_relation_type rel, bool different_polygons, cons
|
|||
ensure_merged_polygons_valid ();
|
||||
|
||||
EdgeRelationFilter check (rel, d, metrics);
|
||||
check.set_include_zero (false);
|
||||
check.set_whole_edges (whole_edges);
|
||||
check.set_ignore_angle (ignore_angle);
|
||||
check.set_min_projection (min_projection);
|
||||
|
|
@ -1494,6 +1495,7 @@ DeepRegion::run_single_polygon_check (db::edge_relation_type rel, db::Coord d, b
|
|||
ensure_merged_polygons_valid ();
|
||||
|
||||
EdgeRelationFilter check (rel, d, metrics);
|
||||
check.set_include_zero (false);
|
||||
check.set_whole_edges (whole_edges);
|
||||
check.set_ignore_angle (ignore_angle);
|
||||
check.set_min_projection (min_projection);
|
||||
|
|
|
|||
|
|
@ -66,6 +66,12 @@ bool euclidian_near_part_of_edge (bool include_zero, db::Coord d, const db::Edge
|
|||
db::Edge g (other);
|
||||
int s1 = e.side_of (g.p1 ());
|
||||
int s2 = e.side_of (g.p2 ());
|
||||
|
||||
// "kissing corner" issue: force include zero if the edges are collinear and overlap.
|
||||
if (! include_zero && s1 == 0 && s2 == 0 && e.intersect (g)) {
|
||||
include_zero = true;
|
||||
}
|
||||
|
||||
int thr = include_zero ? 0 : -1;
|
||||
|
||||
// keep only part of other which is on the "inside" side of e
|
||||
|
|
@ -203,6 +209,12 @@ static bool var_near_part_of_edge (bool include_zero, db::Coord d, db::Coord dd,
|
|||
db::Edge g (other);
|
||||
int s1 = e.side_of (g.p1 ());
|
||||
int s2 = e.side_of (g.p2 ());
|
||||
|
||||
// "kissing corner" issue: force include zero if the edges are collinear and overlap
|
||||
if (! include_zero && s1 == 0 && s2 == 0 && e.intersect (g)) {
|
||||
include_zero = true;
|
||||
}
|
||||
|
||||
int thr = include_zero ? 0 : -1;
|
||||
|
||||
// keep only part of other which is on the "inside" side of e
|
||||
|
|
|
|||
|
|
@ -66,6 +66,21 @@ Edge2EdgeCheckBase::prepare_next_pass ()
|
|||
return false;
|
||||
}
|
||||
|
||||
static inline bool shields (const db::EdgePair &ep, const db::Edge &q)
|
||||
{
|
||||
db::Edge pe1 (ep.first ().p1 (), ep.second ().p2 ());
|
||||
db::Edge pe2 (ep.second ().p1 (), ep.first ().p2 ());
|
||||
|
||||
std::pair<bool, db::Point> ip1 = pe1.intersect_point (q);
|
||||
std::pair<bool, db::Point> ip2 = pe2.intersect_point (q);
|
||||
|
||||
if (ip1.first && ip2.first) {
|
||||
return ip1.second != ip2.second || (ip1.second != q.p1 () && ip2.second != q.p2 ());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Edge2EdgeCheckBase::add (const db::Edge *o1, size_t p1, const db::Edge *o2, size_t p2)
|
||||
{
|
||||
|
|
@ -128,8 +143,7 @@ Edge2EdgeCheckBase::add (const db::Edge *o1, size_t p1, const db::Edge *o2, size
|
|||
for (std::vector<size_t>::const_iterator i = nn.begin (); i != nn.end (); ++i) {
|
||||
if (! m_ep_discarded [*i]) {
|
||||
db::EdgePair ep = m_ep [*i].normalized ();
|
||||
if (db::Edge (ep.first ().p1 (), ep.second ().p2 ()).intersect (*o2) &&
|
||||
db::Edge (ep.second ().p1 (), ep.first ().p2 ()).intersect (*o2)) {
|
||||
if (shields (ep, *o2)) {
|
||||
m_ep_discarded [*i] = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -346,7 +346,7 @@ TEST(7)
|
|||
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 10)), db::Edge (db::Point (-1, 30), db::Point (-1, -20)), &output);
|
||||
EXPECT_EQ (res, false);
|
||||
f.set_include_zero (false);
|
||||
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 10)), db::Edge (db::Point (0, 30), db::Point (0, -20)), &output);
|
||||
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 10)), db::Edge (db::Point (0, 30), db::Point (0, 11)), &output);
|
||||
EXPECT_EQ (res, false);
|
||||
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 10)), db::Edge (db::Point (1, 30), db::Point (1, -20)), &output);
|
||||
EXPECT_EQ (res, true);
|
||||
|
|
@ -355,3 +355,50 @@ TEST(7)
|
|||
EXPECT_EQ (res, false);
|
||||
}
|
||||
|
||||
TEST(8_KissingCornerProblem)
|
||||
{
|
||||
// The kissing corner problem is solved by allowing distance-0 width and space relations and checking them
|
||||
// if the projection is >0.
|
||||
|
||||
db::EdgeRelationFilter f (db::WidthRelation, 10);
|
||||
f.set_include_zero (false);
|
||||
db::EdgePair output;
|
||||
bool res;
|
||||
|
||||
f.set_metrics (db::Euclidian);
|
||||
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 100)), db::Edge (db::Point (0, 201), db::Point (0, 101)), &output);
|
||||
EXPECT_EQ (res, false);
|
||||
res = f.check (db::Edge (db::Point (1, 0), db::Point (1, 100)), db::Edge (db::Point (0, 201), db::Point (0, 0)), &output);
|
||||
EXPECT_EQ (res, false);
|
||||
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 100)), db::Edge (db::Point (0, 200), db::Point (0, 100)), &output);
|
||||
EXPECT_EQ (res, true);
|
||||
EXPECT_EQ (output.first ().to_string () + ":" + output.second ().to_string (), "(0,90;0,100):(0,110;0,100)");
|
||||
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 100)), db::Edge (db::Point (0, 200), db::Point (0, 50)), &output);
|
||||
EXPECT_EQ (res, true);
|
||||
EXPECT_EQ (output.first ().to_string () + ":" + output.second ().to_string (), "(0,40;0,100):(0,110;0,50)");
|
||||
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 100)), db::Edge (db::Point (0, 0), db::Point (0, -100)), &output);
|
||||
EXPECT_EQ (res, true);
|
||||
EXPECT_EQ (output.first ().to_string () + ":" + output.second ().to_string (), "(0,0;0,10):(0,0;0,-10)");
|
||||
res = f.check (db::Edge (db::Point (0, 0), db::Point (0, 100)), db::Edge (db::Point (0, -1), db::Point (0, -100)), &output);
|
||||
EXPECT_EQ (res, false);
|
||||
|
||||
f = db::EdgeRelationFilter (db::SpaceRelation, 10);
|
||||
f.set_include_zero (false);
|
||||
|
||||
f.set_metrics (db::Euclidian);
|
||||
res = f.check (db::Edge (db::Point (0, 100), db::Point (0, 0)), db::Edge (db::Point (0, 101), db::Point (0, 201)), &output);
|
||||
EXPECT_EQ (res, false);
|
||||
res = f.check (db::Edge (db::Point (1, 100), db::Point (1, 0)), db::Edge (db::Point (0, 0), db::Point (0, 200)), &output);
|
||||
EXPECT_EQ (res, false);
|
||||
res = f.check (db::Edge (db::Point (0, 100), db::Point (0, 0)), db::Edge (db::Point (0, 100), db::Point (0, 200)), &output);
|
||||
EXPECT_EQ (res, true);
|
||||
EXPECT_EQ (output.first ().to_string () + ":" + output.second ().to_string (), "(0,100;0,90):(0,100;0,110)");
|
||||
res = f.check (db::Edge (db::Point (0, 100), db::Point (0, 0)), db::Edge (db::Point (0, 50), db::Point (0, 200)), &output);
|
||||
EXPECT_EQ (res, true);
|
||||
EXPECT_EQ (output.first ().to_string () + ":" + output.second ().to_string (), "(0,100;0,40):(0,50;0,110)");
|
||||
res = f.check (db::Edge (db::Point (0, 100), db::Point (0, 0)), db::Edge (db::Point (0, -100), db::Point (0, 0)), &output);
|
||||
EXPECT_EQ (res, true);
|
||||
EXPECT_EQ (output.first ().to_string () + ":" + output.second ().to_string (), "(0,10;0,0):(0,-10;0,0)");
|
||||
res = f.check (db::Edge (db::Point (0, 100), db::Point (0, 0)), db::Edge (db::Point (0, -100), db::Point (0, -1)), &output);
|
||||
EXPECT_EQ (res, false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -740,7 +740,7 @@ TEST(20)
|
|||
EXPECT_EQ (r1.has_valid_edges (), false);
|
||||
db::Edges r2 (db::RecursiveShapeIterator (ly, ly.cell (top), l2), false);
|
||||
EXPECT_EQ (r2.has_valid_edges (), false);
|
||||
EXPECT_EQ (r1.separation_check (r2, 20).to_string (), "(50,0;50,30)/(40,40;40,10);(63,30;80,30)/(97,40;80,40);(80,30;80,20)/(80,40;80,50);(50,40;50,57)/(40,40;40,23);(80,70;80,40)/(80,40;80,70);(60,40;50,40)/(30,40;40,40)");
|
||||
EXPECT_EQ (r1.separation_check (r2, 20).to_string (), "(50,0;50,30)/(40,40;40,10);(63,30;80,30)/(97,40;80,40);(50,40;50,57)/(40,40;40,23);(80,70;80,40)/(80,40;80,70)");
|
||||
EXPECT_EQ (r1.separation_check (r2, 20, false, db::Projection).to_string (), "(50,10;50,30)/(40,30;40,10);(80,70;80,40)/(80,40;80,70)");
|
||||
EXPECT_EQ (r1.separation_check (r2, 20, false, db::Euclidian, 90, 1).to_string (), "(50,0;50,30)/(40,40;40,10);(80,70;80,40)/(80,40;80,70)");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -533,3 +533,89 @@ TEST(12_NetlistJoinLabels)
|
|||
CHECKPOINT ();
|
||||
compare_netlists (_this, output, au);
|
||||
}
|
||||
|
||||
TEST(13a_KissingCorners)
|
||||
{
|
||||
std::string rs = tl::testsrc ();
|
||||
rs += "/testdata/drc/drcSimpleTests_13a.drc";
|
||||
|
||||
std::string input = tl::testsrc ();
|
||||
input += "/testdata/drc/kissing_corners.gds";
|
||||
|
||||
std::string au = tl::testsrc ();
|
||||
au += "/testdata/drc/drcSimpleTests_au13a.gds";
|
||||
|
||||
std::string output = this->tmp_file ("tmp.gds");
|
||||
|
||||
{
|
||||
// Set some variables
|
||||
lym::Macro config;
|
||||
config.set_text (tl::sprintf (
|
||||
"$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);
|
||||
|
||||
// verify
|
||||
|
||||
db::Layout layout;
|
||||
|
||||
{
|
||||
tl::InputStream stream (output);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout);
|
||||
}
|
||||
|
||||
CHECKPOINT ();
|
||||
db::compare_layouts (_this, layout, au, db::NoNormalization);
|
||||
}
|
||||
|
||||
TEST(13b_KissingCornersDeep)
|
||||
{
|
||||
std::string rs = tl::testsrc ();
|
||||
rs += "/testdata/drc/drcSimpleTests_13b.drc";
|
||||
|
||||
std::string input = tl::testsrc ();
|
||||
input += "/testdata/drc/kissing_corners.gds";
|
||||
|
||||
std::string au = tl::testsrc ();
|
||||
au += "/testdata/drc/drcSimpleTests_au13b.gds";
|
||||
|
||||
std::string output = this->tmp_file ("tmp.gds");
|
||||
|
||||
{
|
||||
// Set some variables
|
||||
lym::Macro config;
|
||||
config.set_text (tl::sprintf (
|
||||
"$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);
|
||||
|
||||
// verify
|
||||
|
||||
db::Layout layout;
|
||||
|
||||
{
|
||||
tl::InputStream stream (output);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout);
|
||||
}
|
||||
|
||||
CHECKPOINT ();
|
||||
db::compare_layouts (_this, layout, au, db::NoNormalization);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
source($drc_test_source)
|
||||
target($drc_test_target, "TOP")
|
||||
|
||||
l1 = input(1, 0)
|
||||
l2 = input(2, 0)
|
||||
l3 = input(3, 0)
|
||||
|
||||
l1.output(1, 0)
|
||||
l2.output(2, 0)
|
||||
l3.output(3, 0)
|
||||
|
||||
l1.width(100.nm).output(100, 0)
|
||||
l1.space(100.nm).output(101, 0)
|
||||
l1.notch(100.nm).output(102, 0)
|
||||
l2.separation(l3, 100.nm).output(103, 0)
|
||||
l2.overlap(l3, 100.nm).output(104, 0)
|
||||
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
source($drc_test_source)
|
||||
target($drc_test_target, "TOP")
|
||||
|
||||
deep
|
||||
|
||||
l1 = input(1, 0)
|
||||
l2 = input(2, 0)
|
||||
l3 = input(3, 0)
|
||||
|
||||
l1.output(1, 0)
|
||||
l2.output(2, 0)
|
||||
l3.output(3, 0)
|
||||
|
||||
l1.width(100.nm).output(100, 0)
|
||||
l1.space(100.nm).output(101, 0)
|
||||
l1.notch(100.nm).output(102, 0)
|
||||
l2.separation(l3, 100.nm).output(103, 0)
|
||||
l2.overlap(l3, 100.nm).output(104, 0)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue