mirror of https://github.com/KLayout/klayout.git
commit
236a79dcb1
|
|
@ -44,6 +44,8 @@
|
|||
namespace db
|
||||
{
|
||||
|
||||
const double fill_factor = 1.5;
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// Some utilities ..
|
||||
|
||||
|
|
@ -1095,14 +1097,14 @@ EdgeProcessor::clear ()
|
|||
}
|
||||
|
||||
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_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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
@ -1125,14 +1127,28 @@ get_intersections_per_band_90 (std::vector <CutPoints> &cutpoints, std::vector <
|
|||
std::vector <WorkEdge>::iterator f = current;
|
||||
for (std::vector <WorkEdge>::iterator c = current; c != future; ) {
|
||||
|
||||
while (f != future && edge_xmin (*f) <= x) {
|
||||
++f;
|
||||
}
|
||||
size_t n = 0;
|
||||
db::Coord xx = x;
|
||||
|
||||
db::Coord xx = std::numeric_limits <db::Coord>::max ();
|
||||
if (f != future) {
|
||||
xx = edge_xmin (*f);
|
||||
}
|
||||
// fetch as many cells as to fill in roughly 50% more
|
||||
// (this is an empirical performance improvement factor)
|
||||
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
|
||||
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
|
||||
if (c1->p1 ().y () == c2->p1 ().y ()) {
|
||||
add_hparallel_cutpoints (*c1, *c2, cutpoints);
|
||||
add_hparallel_cutpoints (*c2, *c1, cutpoints);
|
||||
add_hparallel_cutpoints (*c1, *c2, cell, cutpoints);
|
||||
add_hparallel_cutpoints (*c2, *c1, cell, cutpoints);
|
||||
}
|
||||
|
||||
} else if (c1->p1 () != c2->p1 () && c1->p2 () != c2->p1 () &&
|
||||
c1->p1 () != c2->p2 () && c1->p2 () != c2->p2 ()) {
|
||||
|
||||
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)
|
||||
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 ()) {
|
||||
|
||||
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->make_cutpoints (cutpoints)->add (cp.second, &cutpoints, true);
|
||||
|
|
@ -1336,10 +1352,9 @@ public:
|
|||
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)
|
||||
{
|
||||
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 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));
|
||||
|
||||
|
|
@ -1356,14 +1371,28 @@ get_intersections_per_band_any (std::vector <CutPoints> &cutpoints, std::vector
|
|||
std::vector <WorkEdge>::iterator f = current;
|
||||
for (std::vector <WorkEdge>::iterator c = current; c != future; ) {
|
||||
|
||||
while (f != future && edge_xmin_at_yinterval_double (*f, dy, dyy) <= x) {
|
||||
++f;
|
||||
}
|
||||
size_t n = 0;
|
||||
db::Coord xx = x;
|
||||
|
||||
db::Coord xx = std::numeric_limits <db::Coord>::max ();
|
||||
if (f != future) {
|
||||
xx = edge_xmin_at_yinterval_double (*f, dy, dyy);
|
||||
}
|
||||
// fetch as many cells as to fill in roughly 50% more
|
||||
// (this is an empirical performance improvement factor)
|
||||
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
|
||||
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);
|
||||
|
||||
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 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
|
||||
if (c1->p1 ().y () == c2->p1 ().y ()) {
|
||||
add_hparallel_cutpoints (*c1, *c2, cutpoints);
|
||||
add_hparallel_cutpoints (*c2, *c1, cutpoints);
|
||||
add_hparallel_cutpoints (*c1, *c2, cell, cutpoints);
|
||||
add_hparallel_cutpoints (*c2, *c1, cell, cutpoints);
|
||||
}
|
||||
|
||||
} else if (c1->p1 () != c2->p1 () && c1->p2 () != c2->p1 () &&
|
||||
c1->p1 () != c2->p2 () && c1->p2 () != c2->p2 ()) {
|
||||
|
||||
std::pair <bool, db::Point> cp = safe_intersect_point (*c1, *c2);
|
||||
if (cp.first) {
|
||||
|
||||
bool on_edge1 = is_point_on_exact (*c1, 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
|
||||
}
|
||||
|
||||
if (cp.first && cell.contains (cp.second)) {
|
||||
// Stash the cutpoint as it must be inserted into other edges as well.
|
||||
weak_points.insert (cp.second);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1478,41 +1479,9 @@ get_intersections_per_band_any (std::vector <CutPoints> &cutpoints, std::vector
|
|||
c1->p1 () != c2->p2 () && c1->p2 () != c2->p2 ()) {
|
||||
|
||||
std::pair <bool, db::Point> cp = safe_intersect_point (*c1, *c2);
|
||||
if (cp.first) {
|
||||
|
||||
bool on_edge1 = true;
|
||||
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
|
||||
}
|
||||
|
||||
if (cp.first && cell.contains (cp.second)) {
|
||||
// Stash the cutpoint as it must be inserted into other edges as well.
|
||||
weak_points.insert (cp.second);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1532,7 +1501,7 @@ get_intersections_per_band_any (std::vector <CutPoints> &cutpoints, std::vector
|
|||
#endif
|
||||
c2->make_cutpoints (cutpoints)->add (c1->p1 (), &cutpoints, true);
|
||||
} 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;
|
||||
for (std::vector<WorkEdge *>::const_iterator cp = p1_weak.begin (); cp != p1_weak.end () && ! strong; ++cp) {
|
||||
if ((*cp)->data > 0 && cutpoints [(*cp)->data - 1].strong_cutpoints) {
|
||||
strong = true;
|
||||
}
|
||||
}
|
||||
// insert weak intersection points into all relevant edges - weak into edges
|
||||
// where the point is on and strong into edges where the point is on in a fuzzy way.
|
||||
|
||||
p1_weak.back ()->make_cutpoints (cutpoints);
|
||||
size_t n = p1_weak.back ()->data - 1;
|
||||
for (std::vector<WorkEdge *>::const_iterator cp = p1_weak.begin (); cp != p1_weak.end (); ++cp) {
|
||||
for (auto wp = weak_points.begin (); wp != weak_points.end (); ++wp) {
|
||||
|
||||
(*cp)->make_cutpoints (cutpoints);
|
||||
size_t nn = (*cp)->data - 1;
|
||||
if (strong) {
|
||||
cutpoints [nn].add (c1->p1 (), &cutpoints);
|
||||
for (std::vector <WorkEdge>::iterator cc = c; cc != f; ++cc) {
|
||||
if ((with_h || cc->dy () != 0) && is_point_on_fuzzy (*cc, *wp)) {
|
||||
bool on_edge = is_point_on_exact (*cc, *wp);
|
||||
cc->make_cutpoints (cutpoints)->add (*wp, &cutpoints, !on_edge);
|
||||
#ifdef DEBUG_EDGE_PROCESSOR
|
||||
printf ("Insert strong attractor %s in %s.\n", c1->p1 ().to_string ().c_str (), (*cp)->to_string ().c_str ());
|
||||
#endif
|
||||
if (!on_edge) {
|
||||
printf ("intersection point %s gives strong cutpoint in %s.\n", wp->to_string ().c_str (), cc->to_string ().c_str ());
|
||||
} else {
|
||||
cutpoints [nn].add_attractor (c1->p1 (), n);
|
||||
#ifdef DEBUG_EDGE_PROCESSOR
|
||||
printf ("Insert weak attractor %s in %s.\n", c1->p1 ().to_string ().c_str (), (*cp)->to_string ().c_str ());
|
||||
#endif
|
||||
printf ("intersection point %s gives weak cutpoint in %s.\n", wp->to_string ().c_str (), cc->to_string ().c_str ());
|
||||
}
|
||||
|
||||
n = nn;
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
size_t n = std::distance (current, future);
|
||||
size_t n = 0;
|
||||
db::Coord yy = y;
|
||||
|
||||
// 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 ();
|
||||
}
|
||||
|
||||
} 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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -2047,7 +2060,7 @@ public:
|
|||
* @param remove_reflected True, if reflecting spikes shall be removed on compression
|
||||
*/
|
||||
template <class I>
|
||||
void insert_hole (I start, I end, bool compress = default_compression<C> (), bool remove_reflected = false)
|
||||
void insert_hole (I start, I end, bool compress = default_compression<C> (), bool remove_reflected = false)
|
||||
{
|
||||
insert_hole (start, end, db::unit_trans<C> (), compress, remove_reflected);
|
||||
}
|
||||
|
|
@ -2073,21 +2086,17 @@ public:
|
|||
// add the hole
|
||||
contour_type &h = add_hole ();
|
||||
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
|
||||
// position
|
||||
// KLUDGE: this is probably a performance bottleneck from applications
|
||||
// with polygons with may holes ..
|
||||
if (holes () > 1) {
|
||||
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 (ins_pos != p) {
|
||||
while (p != ins_pos) {
|
||||
p->swap (p [-1]);
|
||||
--p;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief Sort the holes
|
||||
*
|
||||
* Sorting the holes makes certain algorithms more effective.
|
||||
*/
|
||||
void sort_holes ()
|
||||
{
|
||||
if (! m_ctrs.empty ()) {
|
||||
std::sort (m_ctrs.begin () + 1, m_ctrs.end ());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2884,6 +2893,16 @@ public:
|
|||
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
|
||||
*
|
||||
|
|
@ -3530,7 +3549,7 @@ inline void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int
|
|||
namespace std
|
||||
{
|
||||
|
||||
// injecting a global std::swap for polygons into the
|
||||
// injecting a global std::swap for polygons into the
|
||||
// std namespace
|
||||
template <class C>
|
||||
void swap (db::polygon<C> &a, db::polygon<C> &b)
|
||||
|
|
|
|||
|
|
@ -865,6 +865,8 @@ PolygonGenerator::produce_poly (const PGPolyContour &c)
|
|||
|
||||
}
|
||||
|
||||
m_poly.sort_holes ();
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
|
@ -859,6 +861,8 @@ smooth (const db::Polygon &polygon, db::Coord d, bool keep_hv)
|
|||
}
|
||||
}
|
||||
|
||||
new_poly.sort_holes ();
|
||||
|
||||
}
|
||||
|
||||
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 {
|
||||
|
||||
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.sort_holes ();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -2921,6 +2931,8 @@ scaled_and_snapped_polygon (const db::Polygon &poly, db::Coord gx, db::Coord mx,
|
|||
|
||||
}
|
||||
|
||||
pnew.sort_holes ();
|
||||
|
||||
return pnew;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -926,6 +926,11 @@ struct polygon_defs
|
|||
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)
|
||||
{
|
||||
tl::Extractor ex (s);
|
||||
|
|
@ -1249,6 +1254,14 @@ struct polygon_defs
|
|||
"@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)"
|
||||
) +
|
||||
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"),
|
||||
"@brief Sizes the polygon (biasing)\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::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;
|
||||
pp.insert_hole (c3.begin (), c3.end ());
|
||||
pp.insert_hole (c2.begin (), c2.end ());
|
||||
pp.sort_holes ();
|
||||
pp.assign_hull (c1.begin (), c1.end ());
|
||||
EXPECT_EQ (pp.area (), 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 ) ])
|
||||
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 ) ] )
|
||||
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)" )
|
||||
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)" )
|
||||
|
|
@ -234,6 +236,8 @@ class DBPolygonTests(unittest.TestCase):
|
|||
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)" )
|
||||
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)" )
|
||||
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)" )
|
||||
|
|
|
|||
|
|
@ -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 ) ])
|
||||
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 ) ] )
|
||||
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)" )
|
||||
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)" )
|
||||
|
|
@ -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 ) ])
|
||||
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 ) ] )
|
||||
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)" )
|
||||
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)" )
|
||||
|
|
|
|||
Loading…
Reference in New Issue