mirror of https://github.com/KLayout/klayout.git
commit
236a79dcb1
|
|
@ -44,6 +44,8 @@
|
||||||
namespace db
|
namespace db
|
||||||
{
|
{
|
||||||
|
|
||||||
|
const double fill_factor = 1.5;
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
// Some utilities ..
|
// Some utilities ..
|
||||||
|
|
||||||
|
|
@ -1095,14 +1097,14 @@ EdgeProcessor::clear ()
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
add_hparallel_cutpoints (WorkEdge &e1, WorkEdge &e2, std::vector <CutPoints> &cutpoints)
|
add_hparallel_cutpoints (WorkEdge &e1, WorkEdge &e2, const db::Box &cell, std::vector <CutPoints> &cutpoints)
|
||||||
{
|
{
|
||||||
db::Coord e1_xmin = std::min (e1.x1 (), e1.x2 ());
|
db::Coord e1_xmin = std::min (e1.x1 (), e1.x2 ());
|
||||||
db::Coord e1_xmax = std::max (e1.x1 (), e1.x2 ());
|
db::Coord e1_xmax = std::max (e1.x1 (), e1.x2 ());
|
||||||
if (e2.x1 () > e1_xmin && e2.x1 () < e1_xmax) {
|
if (e2.x1 () > e1_xmin && e2.x1 () < e1_xmax && cell.contains (e2.p1 ())) {
|
||||||
e1.make_cutpoints (cutpoints)->add (e2.p1 (), &cutpoints, false);
|
e1.make_cutpoints (cutpoints)->add (e2.p1 (), &cutpoints, false);
|
||||||
}
|
}
|
||||||
if (e2.x2 () > e1_xmin && e2.x2 () < e1_xmax) {
|
if (e2.x2 () > e1_xmin && e2.x2 () < e1_xmax && cell.contains (e2.p2 ())) {
|
||||||
e1.make_cutpoints (cutpoints)->add (e2.p2 (), &cutpoints, false);
|
e1.make_cutpoints (cutpoints)->add (e2.p2 (), &cutpoints, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1125,14 +1127,28 @@ get_intersections_per_band_90 (std::vector <CutPoints> &cutpoints, std::vector <
|
||||||
std::vector <WorkEdge>::iterator f = current;
|
std::vector <WorkEdge>::iterator f = current;
|
||||||
for (std::vector <WorkEdge>::iterator c = current; c != future; ) {
|
for (std::vector <WorkEdge>::iterator c = current; c != future; ) {
|
||||||
|
|
||||||
while (f != future && edge_xmin (*f) <= x) {
|
size_t n = 0;
|
||||||
++f;
|
db::Coord xx = x;
|
||||||
}
|
|
||||||
|
|
||||||
db::Coord xx = std::numeric_limits <db::Coord>::max ();
|
// fetch as many cells as to fill in roughly 50% more
|
||||||
if (f != future) {
|
// (this is an empirical performance improvement factor)
|
||||||
xx = edge_xmin (*f);
|
do {
|
||||||
}
|
|
||||||
|
while (f != future && edge_xmin (*f) <= xx) {
|
||||||
|
++f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f != future) {
|
||||||
|
xx = edge_xmin (*f);
|
||||||
|
} else {
|
||||||
|
xx = std::numeric_limits <db::Coord>::max ();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n == 0) {
|
||||||
|
n = std::distance (c, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (f != future && std::distance (c, f) < long (n * fill_factor));
|
||||||
|
|
||||||
#ifdef DEBUG_EDGE_PROCESSOR
|
#ifdef DEBUG_EDGE_PROCESSOR
|
||||||
printf ("edges %d..%d:", x, xx);
|
printf ("edges %d..%d:", x, xx);
|
||||||
|
|
@ -1165,15 +1181,15 @@ get_intersections_per_band_90 (std::vector <CutPoints> &cutpoints, std::vector <
|
||||||
|
|
||||||
// parallel horizontal edges: produce the end points of each other edge as cutpoints
|
// parallel horizontal edges: produce the end points of each other edge as cutpoints
|
||||||
if (c1->p1 ().y () == c2->p1 ().y ()) {
|
if (c1->p1 ().y () == c2->p1 ().y ()) {
|
||||||
add_hparallel_cutpoints (*c1, *c2, cutpoints);
|
add_hparallel_cutpoints (*c1, *c2, cell, cutpoints);
|
||||||
add_hparallel_cutpoints (*c2, *c1, cutpoints);
|
add_hparallel_cutpoints (*c2, *c1, cell, cutpoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (c1->p1 () != c2->p1 () && c1->p2 () != c2->p1 () &&
|
} else if (c1->p1 () != c2->p1 () && c1->p2 () != c2->p1 () &&
|
||||||
c1->p1 () != c2->p2 () && c1->p2 () != c2->p2 ()) {
|
c1->p1 () != c2->p2 () && c1->p2 () != c2->p2 ()) {
|
||||||
|
|
||||||
std::pair <bool, db::Point> cp = c1->intersect_point (*c2);
|
std::pair <bool, db::Point> cp = c1->intersect_point (*c2);
|
||||||
if (cp.first) {
|
if (cp.first && cell.contains (cp.second)) {
|
||||||
|
|
||||||
// add a cut point to c1 and c2 (c2 only if necessary)
|
// add a cut point to c1 and c2 (c2 only if necessary)
|
||||||
c1->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, true);
|
c1->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, true);
|
||||||
|
|
@ -1197,7 +1213,7 @@ get_intersections_per_band_90 (std::vector <CutPoints> &cutpoints, std::vector <
|
||||||
c1->p1 () != c2->p2 () && c1->p2 () != c2->p2 ()) {
|
c1->p1 () != c2->p2 () && c1->p2 () != c2->p2 ()) {
|
||||||
|
|
||||||
std::pair <bool, db::Point> cp = c1->intersect_point (*c2);
|
std::pair <bool, db::Point> cp = c1->intersect_point (*c2);
|
||||||
if (cp.first) {
|
if (cp.first && cell.contains (cp.second)) {
|
||||||
|
|
||||||
// add a cut point to c1 and c2
|
// add a cut point to c1 and c2
|
||||||
c2->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, true);
|
c2->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, true);
|
||||||
|
|
@ -1336,10 +1352,9 @@ public:
|
||||||
static void
|
static void
|
||||||
get_intersections_per_band_any (std::vector <CutPoints> &cutpoints, std::vector <WorkEdge>::iterator current, std::vector <WorkEdge>::iterator future, db::Coord y, db::Coord yy, bool with_h)
|
get_intersections_per_band_any (std::vector <CutPoints> &cutpoints, std::vector <WorkEdge>::iterator current, std::vector <WorkEdge>::iterator future, db::Coord y, db::Coord yy, bool with_h)
|
||||||
{
|
{
|
||||||
std::vector <WorkEdge *> p1_weak; // holds weak interactions of edge endpoints with other edges
|
|
||||||
std::vector <WorkEdge *> ip_weak;
|
|
||||||
double dy = y - 0.5;
|
double dy = y - 0.5;
|
||||||
double dyy = yy + 0.5;
|
double dyy = yy + 0.5;
|
||||||
|
std::vector <std::pair<const WorkEdge *, WorkEdge *> > p1_weak; // holds weak interactions of edge endpoints with other edges
|
||||||
|
|
||||||
std::sort (current, future, edge_xmin_at_yinterval_double_compare<db::Coord> (dy, dyy));
|
std::sort (current, future, edge_xmin_at_yinterval_double_compare<db::Coord> (dy, dyy));
|
||||||
|
|
||||||
|
|
@ -1356,14 +1371,28 @@ get_intersections_per_band_any (std::vector <CutPoints> &cutpoints, std::vector
|
||||||
std::vector <WorkEdge>::iterator f = current;
|
std::vector <WorkEdge>::iterator f = current;
|
||||||
for (std::vector <WorkEdge>::iterator c = current; c != future; ) {
|
for (std::vector <WorkEdge>::iterator c = current; c != future; ) {
|
||||||
|
|
||||||
while (f != future && edge_xmin_at_yinterval_double (*f, dy, dyy) <= x) {
|
size_t n = 0;
|
||||||
++f;
|
db::Coord xx = x;
|
||||||
}
|
|
||||||
|
|
||||||
db::Coord xx = std::numeric_limits <db::Coord>::max ();
|
// fetch as many cells as to fill in roughly 50% more
|
||||||
if (f != future) {
|
// (this is an empirical performance improvement factor)
|
||||||
xx = edge_xmin_at_yinterval_double (*f, dy, dyy);
|
do {
|
||||||
}
|
|
||||||
|
while (f != future && edge_xmin_at_yinterval_double (*f, dy, dyy) <= xx) {
|
||||||
|
++f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f != future) {
|
||||||
|
xx = edge_xmin_at_yinterval_double (*f, dy, dyy);
|
||||||
|
} else {
|
||||||
|
xx = std::numeric_limits <db::Coord>::max ();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n == 0) {
|
||||||
|
n = std::distance (c, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (f != future && std::distance (c, f) < long (n * fill_factor));
|
||||||
|
|
||||||
#ifdef DEBUG_EDGE_PROCESSOR
|
#ifdef DEBUG_EDGE_PROCESSOR
|
||||||
printf ("edges %d..%d:", x, xx);
|
printf ("edges %d..%d:", x, xx);
|
||||||
|
|
@ -1377,9 +1406,10 @@ get_intersections_per_band_any (std::vector <CutPoints> &cutpoints, std::vector
|
||||||
|
|
||||||
db::Box cell (x, y, xx, yy);
|
db::Box cell (x, y, xx, yy);
|
||||||
|
|
||||||
for (std::vector <WorkEdge>::iterator c1 = c; c1 != f; ++c1) {
|
std::set<db::Point> weak_points; // holds points that need to go in all other edges
|
||||||
|
p1_weak.clear ();
|
||||||
|
|
||||||
p1_weak.clear ();
|
for (std::vector <WorkEdge>::iterator c1 = c; c1 != f; ++c1) {
|
||||||
|
|
||||||
bool c1p1_in_cell = cell.contains (c1->p1 ());
|
bool c1p1_in_cell = cell.contains (c1->p1 ());
|
||||||
bool c1p2_in_cell = cell.contains (c1->p2 ());
|
bool c1p2_in_cell = cell.contains (c1->p2 ());
|
||||||
|
|
@ -1398,46 +1428,17 @@ get_intersections_per_band_any (std::vector <CutPoints> &cutpoints, std::vector
|
||||||
|
|
||||||
// parallel horizontal edges: produce the end points of each other edge as cutpoints
|
// parallel horizontal edges: produce the end points of each other edge as cutpoints
|
||||||
if (c1->p1 ().y () == c2->p1 ().y ()) {
|
if (c1->p1 ().y () == c2->p1 ().y ()) {
|
||||||
add_hparallel_cutpoints (*c1, *c2, cutpoints);
|
add_hparallel_cutpoints (*c1, *c2, cell, cutpoints);
|
||||||
add_hparallel_cutpoints (*c2, *c1, cutpoints);
|
add_hparallel_cutpoints (*c2, *c1, cell, cutpoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (c1->p1 () != c2->p1 () && c1->p2 () != c2->p1 () &&
|
} else if (c1->p1 () != c2->p1 () && c1->p2 () != c2->p1 () &&
|
||||||
c1->p1 () != c2->p2 () && c1->p2 () != c2->p2 ()) {
|
c1->p1 () != c2->p2 () && c1->p2 () != c2->p2 ()) {
|
||||||
|
|
||||||
std::pair <bool, db::Point> cp = safe_intersect_point (*c1, *c2);
|
std::pair <bool, db::Point> cp = safe_intersect_point (*c1, *c2);
|
||||||
if (cp.first) {
|
if (cp.first && cell.contains (cp.second)) {
|
||||||
|
// Stash the cutpoint as it must be inserted into other edges as well.
|
||||||
bool on_edge1 = is_point_on_exact (*c1, cp.second);
|
weak_points.insert (cp.second);
|
||||||
|
|
||||||
// add a cut point to c1 and c2 (points not on the edge give strong attractors)
|
|
||||||
c1->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, !on_edge1);
|
|
||||||
if (with_h) {
|
|
||||||
c2->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG_EDGE_PROCESSOR
|
|
||||||
if (on_edge1) {
|
|
||||||
printf ("weak intersection point %s between %s and %s.\n", cp.second.to_string ().c_str (), c1->to_string ().c_str (), c2->to_string ().c_str ());
|
|
||||||
} else {
|
|
||||||
printf ("intersection point %s between %s and %s.\n", cp.second.to_string ().c_str (), c1->to_string ().c_str (), c2->to_string ().c_str ());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// The new cutpoint must be inserted into other edges as well.
|
|
||||||
ip_weak.clear ();
|
|
||||||
for (std::vector <WorkEdge>::iterator cc = c; cc != f; ++cc) {
|
|
||||||
if ((with_h || cc->dy () != 0) && cc != c1 && cc != c2 && is_point_on_fuzzy (*cc, cp.second)) {
|
|
||||||
ip_weak.push_back (&*cc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (std::vector <WorkEdge *>::iterator icc = ip_weak.begin (); icc != ip_weak.end (); ++icc) {
|
|
||||||
(*icc)->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, true);
|
|
||||||
#ifdef DEBUG_EDGE_PROCESSOR
|
|
||||||
printf ("intersection point %s gives cutpoint in %s.\n", cp.second.to_string ().c_str (), (*icc)->to_string ().c_str ());
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1478,41 +1479,9 @@ get_intersections_per_band_any (std::vector <CutPoints> &cutpoints, std::vector
|
||||||
c1->p1 () != c2->p2 () && c1->p2 () != c2->p2 ()) {
|
c1->p1 () != c2->p2 () && c1->p2 () != c2->p2 ()) {
|
||||||
|
|
||||||
std::pair <bool, db::Point> cp = safe_intersect_point (*c1, *c2);
|
std::pair <bool, db::Point> cp = safe_intersect_point (*c1, *c2);
|
||||||
if (cp.first) {
|
if (cp.first && cell.contains (cp.second)) {
|
||||||
|
// Stash the cutpoint as it must be inserted into other edges as well.
|
||||||
bool on_edge1 = true;
|
weak_points.insert (cp.second);
|
||||||
bool on_edge2 = is_point_on_exact (*c2, cp.second);
|
|
||||||
|
|
||||||
// add a cut point to c1 and c2
|
|
||||||
if (with_h || c1->dy () != 0) {
|
|
||||||
on_edge1 = is_point_on_exact (*c1, cp.second);
|
|
||||||
c1->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, !on_edge1);
|
|
||||||
}
|
|
||||||
|
|
||||||
c2->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, !on_edge2);
|
|
||||||
|
|
||||||
#ifdef DEBUG_EDGE_PROCESSOR
|
|
||||||
if (!on_edge1 || !on_edge2) {
|
|
||||||
printf ("intersection point %s between %s and %s.\n", cp.second.to_string ().c_str (), c1->to_string ().c_str (), c2->to_string ().c_str ());
|
|
||||||
} else {
|
|
||||||
printf ("weak intersection point %s between %s and %s.\n", cp.second.to_string ().c_str (), c1->to_string ().c_str (), c2->to_string ().c_str ());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// The new cutpoint must be inserted into other edges as well.
|
|
||||||
ip_weak.clear ();
|
|
||||||
for (std::vector <WorkEdge>::iterator cc = c; cc != f; ++cc) {
|
|
||||||
if ((with_h || cc->dy () != 0) && cc != c1 && cc != c2 && is_point_on_fuzzy (*cc, cp.second)) {
|
|
||||||
ip_weak.push_back (&*cc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (std::vector <WorkEdge *>::iterator icc = ip_weak.begin (); icc != ip_weak.end (); ++icc) {
|
|
||||||
(*icc)->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, true);
|
|
||||||
#ifdef DEBUG_EDGE_PROCESSOR
|
|
||||||
printf ("intersection point %s gives cutpoint in %s.\n", cp.second.to_string ().c_str (), (*icc)->to_string ().c_str ());
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1532,7 +1501,7 @@ get_intersections_per_band_any (std::vector <CutPoints> &cutpoints, std::vector
|
||||||
#endif
|
#endif
|
||||||
c2->make_cutpoints (cutpoints)->add (c1->p1 (), &cutpoints, true);
|
c2->make_cutpoints (cutpoints)->add (c1->p1 (), &cutpoints, true);
|
||||||
} else {
|
} else {
|
||||||
p1_weak.push_back (&*c2);
|
p1_weak.push_back (std::make_pair (c1.operator-> (), c2.operator-> ()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1540,39 +1509,71 @@ get_intersections_per_band_any (std::vector <CutPoints> &cutpoints, std::vector
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! p1_weak.empty ()) {
|
}
|
||||||
|
|
||||||
bool strong = false;
|
// insert weak intersection points into all relevant edges - weak into edges
|
||||||
for (std::vector<WorkEdge *>::const_iterator cp = p1_weak.begin (); cp != p1_weak.end () && ! strong; ++cp) {
|
// where the point is on and strong into edges where the point is on in a fuzzy way.
|
||||||
if ((*cp)->data > 0 && cutpoints [(*cp)->data - 1].strong_cutpoints) {
|
|
||||||
strong = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
p1_weak.back ()->make_cutpoints (cutpoints);
|
for (auto wp = weak_points.begin (); wp != weak_points.end (); ++wp) {
|
||||||
size_t n = p1_weak.back ()->data - 1;
|
|
||||||
for (std::vector<WorkEdge *>::const_iterator cp = p1_weak.begin (); cp != p1_weak.end (); ++cp) {
|
|
||||||
|
|
||||||
(*cp)->make_cutpoints (cutpoints);
|
for (std::vector <WorkEdge>::iterator cc = c; cc != f; ++cc) {
|
||||||
size_t nn = (*cp)->data - 1;
|
if ((with_h || cc->dy () != 0) && is_point_on_fuzzy (*cc, *wp)) {
|
||||||
if (strong) {
|
bool on_edge = is_point_on_exact (*cc, *wp);
|
||||||
cutpoints [nn].add (c1->p1 (), &cutpoints);
|
cc->make_cutpoints (cutpoints)->add (*wp, &cutpoints, !on_edge);
|
||||||
#ifdef DEBUG_EDGE_PROCESSOR
|
#ifdef DEBUG_EDGE_PROCESSOR
|
||||||
printf ("Insert strong attractor %s in %s.\n", c1->p1 ().to_string ().c_str (), (*cp)->to_string ().c_str ());
|
if (!on_edge) {
|
||||||
#endif
|
printf ("intersection point %s gives strong cutpoint in %s.\n", wp->to_string ().c_str (), cc->to_string ().c_str ());
|
||||||
} else {
|
} else {
|
||||||
cutpoints [nn].add_attractor (c1->p1 (), n);
|
printf ("intersection point %s gives weak cutpoint in %s.\n", wp->to_string ().c_str (), cc->to_string ().c_str ());
|
||||||
#ifdef DEBUG_EDGE_PROCESSOR
|
|
||||||
printf ("Insert weak attractor %s in %s.\n", c1->p1 ().to_string ().c_str (), (*cp)->to_string ().c_str ());
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
n = nn;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// go through the list of "p1 to other edges" and insert p1 either as cutpoint
|
||||||
|
// (if there are other strong cutpoints already) or weak attractor.
|
||||||
|
|
||||||
|
auto p1w_from = p1_weak.begin ();
|
||||||
|
while (p1w_from != p1_weak.end ()) {
|
||||||
|
|
||||||
|
bool strong = false;
|
||||||
|
auto p1w_to = p1w_from;
|
||||||
|
while (p1w_to != p1_weak.end () && p1w_to->first == p1w_from->first) {
|
||||||
|
if (p1w_to->second->data > 0 && cutpoints [p1w_to->second->data - 1].strong_cutpoints) {
|
||||||
|
strong = true;
|
||||||
|
}
|
||||||
|
++p1w_to;
|
||||||
|
}
|
||||||
|
|
||||||
|
db::Point p1 = p1w_from->first->p1 ();
|
||||||
|
|
||||||
|
p1w_to [-1].second->make_cutpoints (cutpoints);
|
||||||
|
size_t n = p1w_to [-1].second->data - 1;
|
||||||
|
|
||||||
|
for (auto cp = p1w_from; cp != p1w_to; ++cp) {
|
||||||
|
|
||||||
|
cp->second->make_cutpoints (cutpoints);
|
||||||
|
size_t nn = cp->second->data - 1;
|
||||||
|
if (strong) {
|
||||||
|
cutpoints [nn].add (p1, &cutpoints);
|
||||||
|
#ifdef DEBUG_EDGE_PROCESSOR
|
||||||
|
printf ("Insert strong attractor %s in %s.\n", cp->first->p1 ().to_string ().c_str (), cp->second->to_string ().c_str ());
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
cutpoints [nn].add_attractor (p1, n);
|
||||||
|
#ifdef DEBUG_EDGE_PROCESSOR
|
||||||
|
printf ("Insert weak attractor %s in %s.\n", cp->first->p1 ().to_string ().c_str (), cp->second->to_string ().c_str ());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
n = nn;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p1w_from = p1w_to;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -2259,7 +2260,7 @@ EdgeProcessor::redo_or_process (const std::vector<std::pair<db::EdgeSink *, db::
|
||||||
progress->set (size_t (double (todo_next - todo) * p) + todo);
|
progress->set (size_t (double (todo_next - todo) * p) + todo);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t n = std::distance (current, future);
|
size_t n = 0;
|
||||||
db::Coord yy = y;
|
db::Coord yy = y;
|
||||||
|
|
||||||
// Use as many scanlines as to fetch approx. 50% new edges into the scanline (this
|
// Use as many scanlines as to fetch approx. 50% new edges into the scanline (this
|
||||||
|
|
@ -2276,7 +2277,11 @@ EdgeProcessor::redo_or_process (const std::vector<std::pair<db::EdgeSink *, db::
|
||||||
yy = std::numeric_limits <db::Coord>::max ();
|
yy = std::numeric_limits <db::Coord>::max ();
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (future != mp_work_edges->end () && std::distance (current, future) < long (n + n / 2));
|
if (n == 0) {
|
||||||
|
n = std::distance (current, future);
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (future != mp_work_edges->end () && std::distance (current, future) < long (n * fill_factor));
|
||||||
|
|
||||||
bool is90 = true;
|
bool is90 = true;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1044,6 +1044,19 @@ private:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace db
|
||||||
|
|
||||||
|
namespace std
|
||||||
|
{
|
||||||
|
|
||||||
|
// injecting a global std::swap for polygons into the
|
||||||
|
// std namespace
|
||||||
|
template <class C>
|
||||||
|
void swap (db::polygon_contour<C> &a, db::polygon_contour<C> &b)
|
||||||
|
{
|
||||||
|
a.swap (b);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace db
|
namespace db
|
||||||
|
|
@ -2073,21 +2086,17 @@ public:
|
||||||
// add the hole
|
// add the hole
|
||||||
contour_type &h = add_hole ();
|
contour_type &h = add_hole ();
|
||||||
h.assign (start, end, op, true, compress, true /*normalize*/, remove_reflected);
|
h.assign (start, end, op, true, compress, true /*normalize*/, remove_reflected);
|
||||||
|
}
|
||||||
|
|
||||||
// and keep the list sorted by swapping the
|
/**
|
||||||
// elements and move the last one to the right
|
* @brief Sort the holes
|
||||||
// position
|
*
|
||||||
// KLUDGE: this is probably a performance bottleneck from applications
|
* Sorting the holes makes certain algorithms more effective.
|
||||||
// with polygons with may holes ..
|
*/
|
||||||
if (holes () > 1) {
|
void sort_holes ()
|
||||||
typename contour_list_type::iterator ins_pos = std::lower_bound (m_ctrs.begin () + 1, m_ctrs.end () - 1, h);
|
{
|
||||||
typename contour_list_type::iterator p = m_ctrs.end () - 1;
|
if (! m_ctrs.empty ()) {
|
||||||
if (ins_pos != p) {
|
std::sort (m_ctrs.begin () + 1, m_ctrs.end ());
|
||||||
while (p != ins_pos) {
|
|
||||||
p->swap (p [-1]);
|
|
||||||
--p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2884,6 +2893,16 @@ public:
|
||||||
tl_assert (false);
|
tl_assert (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A dummy implementation of "sort_holes" provided for template instantiation
|
||||||
|
*
|
||||||
|
* Asserts, if begin called.
|
||||||
|
*/
|
||||||
|
void sort_holes ()
|
||||||
|
{
|
||||||
|
tl_assert (false);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A dummy implementation of "hole" provided for template instantiation
|
* @brief A dummy implementation of "hole" provided for template instantiation
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -865,6 +865,8 @@ PolygonGenerator::produce_poly (const PGPolyContour &c)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_poly.sort_holes ();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_psink->put (m_poly);
|
mp_psink->put (m_poly);
|
||||||
|
|
|
||||||
|
|
@ -456,6 +456,8 @@ static bool _cut_polygon_internal (const PolygonType &input, const Edge &line, c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hull->sort_holes ();
|
||||||
|
|
||||||
right_of_line->put (*hull);
|
right_of_line->put (*hull);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -859,6 +861,8 @@ smooth (const db::Polygon &polygon, db::Coord d, bool keep_hv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new_poly.sort_holes ();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new_poly;
|
return new_poly;
|
||||||
|
|
@ -1351,6 +1355,8 @@ do_extract_rad (const db::polygon<C> &polygon, double &rinner, double &router, u
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new_polygon->sort_holes ();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (! do_extract_rad_from_contour (polygon.begin_hull (), polygon.end_hull (), rinner, router, n, (std::vector<db::point<C> > *) 0, false)) {
|
if (! do_extract_rad_from_contour (polygon.begin_hull (), polygon.end_hull (), rinner, router, n, (std::vector<db::point<C> > *) 0, false)) {
|
||||||
|
|
@ -1542,6 +1548,8 @@ do_compute_rounded (const db::polygon<C> &polygon, double rinner, double router,
|
||||||
new_poly.insert_hole (new_pts.begin (), new_pts.end (), false /*don't compress*/);
|
new_poly.insert_hole (new_pts.begin (), new_pts.end (), false /*don't compress*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new_poly.sort_holes ();
|
||||||
|
|
||||||
return new_poly;
|
return new_poly;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2882,6 +2890,8 @@ snapped_polygon (const db::Polygon &poly, db::Coord gx, db::Coord gy, std::vecto
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pnew.sort_holes ();
|
||||||
|
|
||||||
return pnew;
|
return pnew;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2921,6 +2931,8 @@ scaled_and_snapped_polygon (const db::Polygon &poly, db::Coord gx, db::Coord mx,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pnew.sort_holes ();
|
||||||
|
|
||||||
return pnew;
|
return pnew;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -926,6 +926,11 @@ struct polygon_defs
|
||||||
return c->insert_hole (&pts[0], &pts[0] + sizeof (pts) / sizeof (pts[0]));
|
return c->insert_hole (&pts[0], &pts[0] + sizeof (pts) / sizeof (pts[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sort_holes (C *c)
|
||||||
|
{
|
||||||
|
c->sort_holes ();
|
||||||
|
}
|
||||||
|
|
||||||
static C *from_string (const char *s)
|
static C *from_string (const char *s)
|
||||||
{
|
{
|
||||||
tl::Extractor ex (s);
|
tl::Extractor ex (s);
|
||||||
|
|
@ -1249,6 +1254,14 @@ struct polygon_defs
|
||||||
"@brief Iterates over the points that make up the nth hole\n"
|
"@brief Iterates over the points that make up the nth hole\n"
|
||||||
"The hole number must be less than the number of holes (see \\holes)"
|
"The hole number must be less than the number of holes (see \\holes)"
|
||||||
) +
|
) +
|
||||||
|
method_ext ("sort_holes", &sort_holes,
|
||||||
|
"@brief Brings the holes in a specific order\n"
|
||||||
|
"This function is normalize the hole order so the comparison of two "
|
||||||
|
"polygons does not depend on the order the holes were inserted. "
|
||||||
|
"Polygons generated by KLayout's alorithms have their holes sorted.\n"
|
||||||
|
"\n"
|
||||||
|
"This method has been introduced in version 0.28.8."
|
||||||
|
) +
|
||||||
method_ext ("size", &size_xy, gsi::arg ("dx"), gsi::arg ("dy"), gsi::arg ("mode"),
|
method_ext ("size", &size_xy, gsi::arg ("dx"), gsi::arg ("dy"), gsi::arg ("mode"),
|
||||||
"@brief Sizes the polygon (biasing)\n"
|
"@brief Sizes the polygon (biasing)\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
|
|
||||||
|
|
@ -2781,3 +2781,40 @@ TEST(135b)
|
||||||
EXPECT_EQ (run_test135b (_this, db::Trans (db::Trans::m90)), "(-78,25;-33,34;-36,33;-37,33)");
|
EXPECT_EQ (run_test135b (_this, db::Trans (db::Trans::m90)), "(-78,25;-33,34;-36,33;-37,33)");
|
||||||
EXPECT_EQ (run_test135b (_this, db::Trans (db::Trans::m135)), "(-26,-78;-35,-33;-33,-36;-33,-37)");
|
EXPECT_EQ (run_test135b (_this, db::Trans (db::Trans::m135)), "(-26,-78;-35,-33;-33,-36;-33,-37)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// issue #1366
|
||||||
|
TEST(136)
|
||||||
|
{
|
||||||
|
db::Layout layout_1;
|
||||||
|
unsigned int l_l20000d0;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::string fn (tl::testdata ());
|
||||||
|
fn += "/bool/";
|
||||||
|
fn += "issue_1366.oas";
|
||||||
|
tl::InputStream stream (fn);
|
||||||
|
db::Reader reader (stream);
|
||||||
|
|
||||||
|
db::LoadLayoutOptions options;
|
||||||
|
reader.read (layout_1, options);
|
||||||
|
|
||||||
|
l_l20000d0 = layout_1.get_layer (db::LayerProperties (20000, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
db::ShapeProcessor proc;
|
||||||
|
|
||||||
|
db::Layout lr;
|
||||||
|
lr.dbu (0.0001);
|
||||||
|
db::Cell *lr_top = &lr.cell (lr.add_cell ("TOP"));
|
||||||
|
|
||||||
|
unsigned int lr_l100d0 = lr.insert_layer (db::LayerProperties (100, 0));
|
||||||
|
|
||||||
|
proc.merge (layout_1, layout_1.cell (*layout_1.begin_top_down ()), l_l20000d0,
|
||||||
|
lr_top->shapes (lr_l100d0), false /*hierarchical*/, 0, true /*resolve holes*/, true /*min coherence*/);
|
||||||
|
|
||||||
|
std::string au_fn (tl::testdata ());
|
||||||
|
au_fn += "/bool/";
|
||||||
|
au_fn += "issue_1366_au.gds";
|
||||||
|
|
||||||
|
db::compare_layouts (_this, lr, au_fn);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,7 @@ TEST(1)
|
||||||
db::Polygon pp;
|
db::Polygon pp;
|
||||||
pp.insert_hole (c3.begin (), c3.end ());
|
pp.insert_hole (c3.begin (), c3.end ());
|
||||||
pp.insert_hole (c2.begin (), c2.end ());
|
pp.insert_hole (c2.begin (), c2.end ());
|
||||||
|
pp.sort_holes ();
|
||||||
pp.assign_hull (c1.begin (), c1.end ());
|
pp.assign_hull (c1.begin (), c1.end ());
|
||||||
EXPECT_EQ (pp.area (), 1000*100-2*380*80);
|
EXPECT_EQ (pp.area (), 1000*100-2*380*80);
|
||||||
EXPECT_EQ (pp.area2 (), 2*(1000*100-2*380*80));
|
EXPECT_EQ (pp.area2 (), 2*(1000*100-2*380*80));
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -122,6 +122,8 @@ class DBPolygonTests(unittest.TestCase):
|
||||||
b.assign_hole(1, [ pya.DPoint( 15, 25 ), pya.DPoint( 25, 25 ), pya.DPoint( 25, 65 ) ])
|
b.assign_hole(1, [ pya.DPoint( 15, 25 ), pya.DPoint( 25, 25 ), pya.DPoint( 25, 65 ) ])
|
||||||
self.assertEqual( str(b), "(0,1;1,5;1,1/10,20;20,20;20,60)" )
|
self.assertEqual( str(b), "(0,1;1,5;1,1/10,20;20,20;20,60)" )
|
||||||
b.insert_hole( [ pya.DPoint( 1, 2 ), pya.DPoint( 2, 2 ), pya.DPoint( 2, 6 ) ] )
|
b.insert_hole( [ pya.DPoint( 1, 2 ), pya.DPoint( 2, 2 ), pya.DPoint( 2, 6 ) ] )
|
||||||
|
self.assertEqual( str(b), "(0,1;1,5;1,1/10,20;20,20;20,60/1,2;2,2;2,6)" )
|
||||||
|
b.sort_holes()
|
||||||
self.assertEqual( str(b), "(0,1;1,5;1,1/1,2;2,2;2,6/10,20;20,20;20,60)" )
|
self.assertEqual( str(b), "(0,1;1,5;1,1/1,2;2,2;2,6/10,20;20,20;20,60)" )
|
||||||
b.assign_hole(0, [ pya.DPoint( 15, 25 ), pya.DPoint( 25, 25 ), pya.DPoint( 25, 65 ) ])
|
b.assign_hole(0, [ pya.DPoint( 15, 25 ), pya.DPoint( 25, 25 ), pya.DPoint( 25, 65 ) ])
|
||||||
self.assertEqual( str(b), "(0,1;1,5;1,1/15,25;25,25;25,65/10,20;20,20;20,60)" )
|
self.assertEqual( str(b), "(0,1;1,5;1,1/15,25;25,25;25,65/10,20;20,20;20,60)" )
|
||||||
|
|
@ -234,6 +236,8 @@ class DBPolygonTests(unittest.TestCase):
|
||||||
b.assign_hole(1, [ pya.Point( 15, 25 ), pya.Point( 25, 25 ), pya.Point( 25, 65 ) ])
|
b.assign_hole(1, [ pya.Point( 15, 25 ), pya.Point( 25, 25 ), pya.Point( 25, 65 ) ])
|
||||||
self.assertEqual( str(b), "(0,1;1,5;1,1/10,20;20,20;20,60)" )
|
self.assertEqual( str(b), "(0,1;1,5;1,1/10,20;20,20;20,60)" )
|
||||||
b.insert_hole( [ pya.Point( 1, 2 ), pya.Point( 2, 2 ), pya.Point( 2, 6 ) ] )
|
b.insert_hole( [ pya.Point( 1, 2 ), pya.Point( 2, 2 ), pya.Point( 2, 6 ) ] )
|
||||||
|
self.assertEqual( str(b), "(0,1;1,5;1,1/10,20;20,20;20,60/1,2;2,2;2,6)" )
|
||||||
|
b.sort_holes()
|
||||||
self.assertEqual( str(b), "(0,1;1,5;1,1/1,2;2,2;2,6/10,20;20,20;20,60)" )
|
self.assertEqual( str(b), "(0,1;1,5;1,1/1,2;2,2;2,6/10,20;20,20;20,60)" )
|
||||||
b.assign_hole(0, [ pya.Point( 15, 25 ), pya.Point( 25, 25 ), pya.Point( 25, 65 ) ])
|
b.assign_hole(0, [ pya.Point( 15, 25 ), pya.Point( 25, 25 ), pya.Point( 25, 65 ) ])
|
||||||
self.assertEqual( str(b), "(0,1;1,5;1,1/15,25;25,25;25,65/10,20;20,20;20,60)" )
|
self.assertEqual( str(b), "(0,1;1,5;1,1/15,25;25,25;25,65/10,20;20,20;20,60)" )
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,8 @@ class DBPolygon_TestClass < TestBase
|
||||||
b.assign_hole(1, [ RBA::DPoint::new( 15, 25 ), RBA::DPoint::new( 25, 25 ), RBA::DPoint::new( 25, 65 ) ])
|
b.assign_hole(1, [ RBA::DPoint::new( 15, 25 ), RBA::DPoint::new( 25, 25 ), RBA::DPoint::new( 25, 65 ) ])
|
||||||
assert_equal( b.to_s, "(0,1;1,5;1,1/10,20;20,20;20,60)" )
|
assert_equal( b.to_s, "(0,1;1,5;1,1/10,20;20,20;20,60)" )
|
||||||
b.insert_hole( [ RBA::DPoint::new( 1, 2 ), RBA::DPoint::new( 2, 2 ), RBA::DPoint::new( 2, 6 ) ] )
|
b.insert_hole( [ RBA::DPoint::new( 1, 2 ), RBA::DPoint::new( 2, 2 ), RBA::DPoint::new( 2, 6 ) ] )
|
||||||
|
assert_equal( b.to_s, "(0,1;1,5;1,1/10,20;20,20;20,60/1,2;2,2;2,6)" )
|
||||||
|
b.sort_holes
|
||||||
assert_equal( b.to_s, "(0,1;1,5;1,1/1,2;2,2;2,6/10,20;20,20;20,60)" )
|
assert_equal( b.to_s, "(0,1;1,5;1,1/1,2;2,2;2,6/10,20;20,20;20,60)" )
|
||||||
b.assign_hole(0, [ RBA::DPoint::new( 15, 25 ), RBA::DPoint::new( 25, 25 ), RBA::DPoint::new( 25, 65 ) ])
|
b.assign_hole(0, [ RBA::DPoint::new( 15, 25 ), RBA::DPoint::new( 25, 25 ), RBA::DPoint::new( 25, 65 ) ])
|
||||||
assert_equal( b.to_s, "(0,1;1,5;1,1/15,25;25,25;25,65/10,20;20,20;20,60)" )
|
assert_equal( b.to_s, "(0,1;1,5;1,1/15,25;25,25;25,65/10,20;20,20;20,60)" )
|
||||||
|
|
@ -251,6 +253,8 @@ class DBPolygon_TestClass < TestBase
|
||||||
b.assign_hole(1, [ RBA::Point::new( 15, 25 ), RBA::Point::new( 25, 25 ), RBA::Point::new( 25, 65 ) ])
|
b.assign_hole(1, [ RBA::Point::new( 15, 25 ), RBA::Point::new( 25, 25 ), RBA::Point::new( 25, 65 ) ])
|
||||||
assert_equal( b.to_s, "(0,1;1,5;1,1/10,20;20,20;20,60)" )
|
assert_equal( b.to_s, "(0,1;1,5;1,1/10,20;20,20;20,60)" )
|
||||||
b.insert_hole( [ RBA::Point::new( 1, 2 ), RBA::Point::new( 2, 2 ), RBA::Point::new( 2, 6 ) ] )
|
b.insert_hole( [ RBA::Point::new( 1, 2 ), RBA::Point::new( 2, 2 ), RBA::Point::new( 2, 6 ) ] )
|
||||||
|
assert_equal( b.to_s, "(0,1;1,5;1,1/10,20;20,20;20,60/1,2;2,2;2,6)" )
|
||||||
|
b.sort_holes
|
||||||
assert_equal( b.to_s, "(0,1;1,5;1,1/1,2;2,2;2,6/10,20;20,20;20,60)" )
|
assert_equal( b.to_s, "(0,1;1,5;1,1/1,2;2,2;2,6/10,20;20,20;20,60)" )
|
||||||
b.assign_hole(0, [ RBA::Point::new( 15, 25 ), RBA::Point::new( 25, 25 ), RBA::Point::new( 25, 65 ) ])
|
b.assign_hole(0, [ RBA::Point::new( 15, 25 ), RBA::Point::new( 25, 25 ), RBA::Point::new( 25, 65 ) ])
|
||||||
assert_equal( b.to_s, "(0,1;1,5;1,1/15,25;25,25;25,65/10,20;20,20;20,60)" )
|
assert_equal( b.to_s, "(0,1;1,5;1,1/15,25;25,25;25,65/10,20;20,20;20,60)" )
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue