Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
171 changes: 120 additions & 51 deletions src/db/db/dbEdgePairRelations.cc
Original file line number Diff line number Diff line change
Expand Up @@ -93,16 +93,22 @@ static bool include_zero_flag (zero_distance_mode zd_mode, const db::Edge &a, co
*/
bool euclidian_near_part_of_edge (zero_distance_mode zd_mode, db::coord_traits<db::Coord>::distance_type d, const db::Edge &e, const db::Edge &other, db::Edge *output)
{
// Handle the case of point-like basic edge: cannot determine
// orientation
db::Edge g (other);

// s1 = side of g.p1 wrt e
// s2 = side of g.p2 wrt e
int s1, s2;
if (e.is_degenerate ()) {
return false;
if (g.contains (e.p1 ())) {
s1 = s2 = 0;
} else {
s1 = s2 = -1;
}
} else {
s1 = e.side_of (g.p1 ());
s2 = e.side_of (g.p2 ());
}

db::Edge g (other);
int s1 = e.side_of (g.p1 ());
int s2 = e.side_of (g.p2 ());

bool include_zero = include_zero_flag (zd_mode, e, g);
int thr = include_zero ? 0 : -1;

Expand All @@ -115,33 +121,49 @@ bool euclidian_near_part_of_edge (zero_distance_mode zd_mode, db::coord_traits<d
g = db::Edge (g.cut_point (e).second, g.p2 ());
}

// Handle the case of point vs. edge
// Handle the case of point vs. edge/point

if (g.is_degenerate ()) {

db::Point o = g.p1 ();

if (e.side_of (o) > thr) {
return false;
}

double a = e.double_sq_length ();
double b = db::sprod (db::Vector (e.p1 () - o), e.d ()) / a;
double c = (e.p1 ().sq_double_distance (o) - double (d) * double (d)) / a;
if (e.is_degenerate ()) {

double s = b * b - c;
if (s >= -db::epsilon) {
double l1 = std::max (0.0, (-b - sqrt (s)));
double l2 = std::min (1.0, (-b + sqrt (s)));
if (l1 <= l2) {
// point vs. point
if (e.p1 ().distance (g.p1 ()) < double (d)) {
if (output) {
*output = g;
}
return true;
}
}

return false;
return false;

} else {

db::Point o = g.p1 ();

if (e.side_of (o) > thr) {
return false;
}

double a = e.double_sq_length ();
double b = db::sprod (db::Vector (e.p1 () - o), e.d ()) / a;
double c = (e.p1 ().sq_double_distance (o) - double (d) * double (d)) / a;

double s = b * b - c;
if (s >= -db::epsilon) {
double l1 = std::max (0.0, (-b - sqrt (s)));
double l2 = std::min (1.0, (-b + sqrt (s)));
if (l1 <= l2) {
if (output) {
*output = g;
}
return true;
}
}

return false;

}

}

Expand All @@ -150,10 +172,13 @@ bool euclidian_near_part_of_edge (zero_distance_mode zd_mode, db::coord_traits<d
double l1 = std::numeric_limits<double>::max (), l2 = -std::numeric_limits<double>::max ();

// handle the parallel case
// NOTE: a point is "parallel" to an edge.
if (e.parallel (g)) {

if (std::abs (double (e.distance (g.p1 ()))) >= double (d)) {
return false;
}

} else {

double ef = 1.0 / e.double_length ();
Expand Down Expand Up @@ -233,17 +258,22 @@ bool euclidian_near_part_of_edge (zero_distance_mode zd_mode, db::coord_traits<d
*/
static bool var_near_part_of_edge (zero_distance_mode zd_mode, db::coord_traits<db::Coord>::distance_type d, db::coord_traits<db::Coord>::distance_type dd, const db::Edge &e, const db::Edge &other, db::Edge *output)
{
// Handle the case of point-like basic edge: cannot determine
// orientation
db::Edge g (other);

// s1 = side of g.p1 wrt e
// s2 = side of g.p2 wrt e
int s1, s2;
if (e.is_degenerate ()) {
return false;
if (g.contains (e.p1 ())) {
s1 = s2 = 0;
} else {
s1 = s2 = -1;
}
} else {
s1 = e.side_of (g.p1 ());
s2 = e.side_of (g.p2 ());
}

db::Edge g (other);
int s1 = e.side_of (g.p1 ());
int s2 = e.side_of (g.p2 ());

bool include_zero = include_zero_flag (zd_mode, e, g);
int thr = include_zero ? 0 : -1;

Expand All @@ -259,37 +289,54 @@ static bool var_near_part_of_edge (zero_distance_mode zd_mode, db::coord_traits<
// Handle the case of point vs. edge

if (g.is_degenerate ()) {
if (e.side_of (g.p1 ()) > thr) {
return false;
}
if (double (e.distance (g.p1 ())) <= -double (d)) {
return false;
}
if (db::sprod (db::Vector (g.p1 () - e.p1 ()), e.d ()) < -(dd * e.double_length ())) {
return false;
}
if (db::sprod (db::Vector (e.p2 () - g.p1 ()), e.d ()) < -(dd * e.double_length ())) {
return false;

if (! e.is_degenerate ()) {
if (e.side_of (g.p1 ()) > thr) {
return false;
}
if (db::sprod (db::Vector (g.p1 () - e.p1 ()), e.d ()) < -(dd * e.double_length ())) {
return false;
}
if (db::sprod (db::Vector (e.p2 () - g.p1 ()), e.d ()) < -(dd * e.double_length ())) {
return false;
}
if (double (e.distance (g.p1 ())) <= -double (d)) {
return false;
}
} else {
// point to point
if (e.p1 ().distance (g.p1 ()) >= double (d)) {
return false;
}
}

if (output) {
*output = g;
}
return true;

}

// Determine body interactions (projected mode)

double l1 = std::numeric_limits<double>::min (), l2 = std::numeric_limits<double>::max ();
double l1 = std::numeric_limits<double>::lowest (), l2 = std::numeric_limits<double>::max ();

double ef = 1.0 / e.double_length ();
db::DVector ep = db::DVector (ef * e.dx (), ef * e.dy ());
db::DVector en = db::DVector (ef * e.dy (), -ef * e.dx ());
db::DVector ep, en;
double ef = 0.0;
if (! e.is_degenerate ()) {
ef = 1.0 / e.double_length ();
ep = db::DVector (ef * e.dx (), ef * e.dy ());
en = db::DVector (ef * e.dy (), -ef * e.dx ());
}

// handle the parallel case
// NOTE: a point is "parallel" to an edge
if (e.parallel (g)) {

if (std::abs (double (e.distance (g.p1 ()))) >= double (d)) {
return false;
}

} else {

db::DPoint e1d = db::DPoint (e.p1 ()) + en * double (d);
Expand All @@ -306,11 +353,26 @@ static bool var_near_part_of_edge (zero_distance_mode zd_mode, db::coord_traits<

}

bool allow_zero_projection = false;

if (db::sprod_sign (e, g) == 0) {
if (db::sprod (db::Vector (g.p1 () - e.p1 ()), e.d ()) < -(dd * e.double_length ()) ||
db::sprod (db::Vector (e.p2 () - g.p1 ()), e.d ()) < -(dd * e.double_length ())) {
return false;

if (! g.is_degenerate ()) {

if (db::sprod (db::Vector (g.p1 () - e.p1 ()), e.d ()) < -(dd * e.double_length ()) ||
db::sprod (db::Vector (e.p2 () - g.p1 ()), e.d ()) < -(dd * e.double_length ())) {
return false;
}

double l = db::sprod (db::DVector (e.p1 () - g.p1 ()), db::DVector (g.d ())) / g.double_sq_length ();
double dl = double (dd) / g.double_length ();
l1 = l - dl;
l2 = l + dl;

allow_zero_projection = true;

}

} else {

double det = db::vprod (db::DVector (g.d ()), en);
Expand All @@ -330,7 +392,7 @@ static bool var_near_part_of_edge (zero_distance_mode zd_mode, db::coord_traits<
l1 = std::max (0.0, l1);
l2 = std::min (1.0, l2);

if (l1 >= l2) {
if (allow_zero_projection ? l1 > l2 + db::epsilon : l1 > l2 - db::epsilon) {
return false;
} else {
if (output) {
Expand Down Expand Up @@ -410,7 +472,14 @@ EdgeRelationFilter::check (const db::Edge &a, const db::Edge &b, db::EdgePair *o

// Check whether the edges have an angle less than the ignore_angle parameter

if (m_ignore_angle == 90.0) {
if (a.is_degenerate () || b.is_degenerate ()) {
// accept dots as "always good", expect if they are identical and the zero distance mode does not include this case
if (a == b && (m_zero_distance_mode == NeverIncludeZeroDistance ||
m_zero_distance_mode == IncludeZeroDistanceWhenCollinearAndTouching ||
m_zero_distance_mode == IncludeZeroDistanceWhenOverlapping)) {
return false;
}
} else if (m_ignore_angle == 90.0) {
if (db::sprod_sign (aa, b) >= 0) {
return false;
}
Expand Down
8 changes: 5 additions & 3 deletions src/db/db/dbRegionCheckUtils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -463,8 +463,10 @@ void
poly2poly_check<PolygonType>::enter (const PolygonType &o, size_t p)
{
for (typename PolygonType::polygon_edge_iterator e = o.begin_edge (); ! e.at_end (); ++e) {
m_edge_heap.push_back (*e);
m_scanner.insert (& m_edge_heap.back (), p);
if (! (*e).is_degenerate ()) {
m_edge_heap.push_back (*e);
m_scanner.insert (& m_edge_heap.back (), p);
}
}
}

Expand Down Expand Up @@ -497,7 +499,7 @@ poly2poly_check<PolygonType>::enter (const PolygonType &o, size_t p, const poly2
}

for (typename PolygonType::polygon_edge_iterator e = o.begin_edge (); ! e.at_end (); ++e) {
if (interact (box, *e)) {
if (! (*e).is_degenerate () && interact (box, *e)) {
m_edge_heap.push_back (*e);
m_scanner.insert (& m_edge_heap.back (), p);
}
Expand Down
10 changes: 6 additions & 4 deletions src/db/unit_tests/dbEdgePairRelationsTests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,8 @@ TEST(3)
EXPECT_EQ (output.to_string (), "(80,0;-60,-100)");
EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-100, 200), db::Point (-100, -200)), &output), true);
EXPECT_EQ (output.to_string (), "(-100,0;-100,-100)");
EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (), db::Edge (db::Point (-100, 200), db::Point (-100, -200)), &output), false);
EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (), db::Edge (db::Point (-100, 200), db::Point (-100, -200)), &output), true);
EXPECT_EQ (output.to_string (), "(-100,100;-100,-100)"); // dot vs. line (issue #2141)
EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, 50), db::Point (100, 50)), &output), false);
EXPECT_EQ (square_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, -50), db::Point (100, -50)), &output), true);
EXPECT_EQ (output.to_string (), "(100,-50;100,-50)");
Expand Down Expand Up @@ -170,14 +171,15 @@ TEST(4)
EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 200), db::Point (200, -200)), &output), false);
EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (120, 200), db::Point (120, -200)), &output), false);
EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, 200), db::Point (100, -200)), &output), true);
EXPECT_EQ (output.to_string (), "(100,0;100,-100)");
EXPECT_EQ (output.to_string (), "(100,0;100,0)");
EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (80, 200), db::Point (80, -200)), &output), true);
EXPECT_EQ (output.to_string (), "(80,0;80,-100)");
EXPECT_EQ (output.to_string (), "(80,0;80,0)");
EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-80, 200), db::Point (-80, -200)), &output), false);
EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (80, 0), db::Point (-200, -200)), &output), true);
EXPECT_EQ (output.to_string (), "(80,0;0,-57)");
EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (-100, 200), db::Point (-100, -200)), &output), false);
EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (), db::Edge (db::Point (-100, 200), db::Point (-100, -200)), &output), false);
EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (), db::Edge (db::Point (-100, 200), db::Point (-100, -200)), &output), true);
EXPECT_EQ (output.to_string (), "(-100,0;-100,0)"); // dot vs. line (issue #2141)
EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, 50), db::Point (100, 50)), &output), false);
EXPECT_EQ (projected_near_part_of_edge (db::AlwaysIncludeZeroDistance, 100, db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, -50), db::Point (100, -50)), &output), true);
EXPECT_EQ (output.to_string (), "(100,-50;100,-50)");
Expand Down
17 changes: 15 additions & 2 deletions src/drc/drc/built-in-macros/_drc_layer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5079,6 +5079,7 @@ def #{f}(*args)
#
# This method works both on edge or polygon layers. Edge merging forms
# single, continuous edges from coincident and connected individual edges.
# The overlap count is only available on polygon layers.
#
# A version that modifies the input layer is \merge.
#
Expand Down Expand Up @@ -5106,15 +5107,27 @@ def #{f}(*args)
def merged(overlap_count = 1)
@engine._context("merged") do
requires_edges_or_region
aa = [ @engine._prep_value(overlap_count) ]
oc = @engine._prep_value(overlap_count)
if self.data.is_a?(RBA::Edges)
oc == 1 || raise("'overlap_count' (merged) is only available on polygon layers")
aa = []
else
aa = [ oc ]
end
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :merged, *aa))
end
end

def merge(overlap_count = 1)
@engine._context("merge") do
requires_edges_or_region
aa = [ @engine._prep_value(overlap_count) ]
oc = @engine._prep_value(overlap_count)
if self.data.is_a?(RBA::Edges)
oc == 1 || raise("'overlap_count' (merged) is only available on polygon layers")
aa = []
else
aa = [ oc ]
end
if @engine.is_tiled?
# in tiled mode, no modifying versions are available
self.data = @engine._tcmd(self.data, 0, self.data.class, :merged, *aa)
Expand Down
22 changes: 22 additions & 0 deletions src/drc/unit_tests/drcSimpleTests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2044,3 +2044,25 @@ TEST(144d_combined_antennas)
run_test (_this, "144", true);
}

// issue 2134
TEST(145_edges_merge)
{
run_test (_this, "145", false);
}

TEST(145d_edges_merge)
{
run_test (_this, "145", true);
}

// issue 2141
TEST(146_edges_and_corners)
{
run_test (_this, "146", false);
}

TEST(146d_edges_and_corners)
{
run_test (_this, "146", true);
}

Loading
Loading