Skip to content

Commit

Permalink
Merge pull request #1855 from KLayout/issue-1853
Browse files Browse the repository at this point in the history
Issue 1853 (slow Cell#write any Layout#write with huge polygons)
  • Loading branch information
klayoutmatthias authored Sep 16, 2024
2 parents b58e137 + 97dcf0a commit ff70818
Show file tree
Hide file tree
Showing 5 changed files with 422 additions and 140 deletions.
145 changes: 116 additions & 29 deletions src/db/db/dbPolygonGenerators.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@


#include "dbPolygonGenerators.h"
#include "tlTimer.h"

#include <vector>
#include <deque>
Expand Down Expand Up @@ -51,18 +52,18 @@ struct PGPoint
class PGPolyContour
{
public:
typedef std::deque <db::Point> contour_type;
typedef std::list <db::Point> contour_type;
typedef contour_type::const_iterator const_iterator;
typedef contour_type::iterator iterator;

PGPolyContour ()
: m_is_hole (false), m_next (-1), m_last (-1)
: m_is_hole (false), m_next (-1), m_last (-1), m_size (0)
{
// ...
}

PGPolyContour (const PGPolyContour &d)
: m_contour (d.m_contour), m_is_hole (d.m_is_hole), m_next (d.m_next), m_last (d.m_last)
: m_contour (d.m_contour), m_is_hole (d.m_is_hole), m_next (d.m_next), m_last (d.m_last), m_size (d.m_size)
{
// ...
}
Expand All @@ -74,6 +75,7 @@ class PGPolyContour
m_is_hole = d.m_is_hole;
m_next = d.m_next;
m_last = d.m_last;
m_size = d.m_size;
}
return *this;
}
Expand All @@ -86,14 +88,45 @@ class PGPolyContour
db::Point &front () { return m_contour.front (); }
const db::Point &back () const { return m_contour.back (); }
db::Point &back () { return m_contour.back (); }
void push_back (const db::Point &p) { m_contour.push_back (p); }
void push_front (const db::Point &p) { m_contour.push_front (p); }
void pop_back () { m_contour.pop_back (); }
void pop_front () { m_contour.pop_front (); }
iterator erase (iterator i) { return m_contour.erase (i); }
iterator insert (iterator i, const db::Point &p) { return m_contour.insert (i, p); }

void push_back (const db::Point &p)
{
m_contour.push_back (p);
++m_size;
}

void push_front (const db::Point &p)
{
m_contour.push_front (p);
++m_size;
}

void pop_back ()
{
m_contour.pop_back ();
--m_size;
}

void pop_front ()
{
m_contour.pop_front ();
--m_size;
}

iterator erase (iterator i)
{
--m_size;
return m_contour.erase (i);
}

iterator insert (iterator i, const db::Point &p)
{
++m_size;
return m_contour.insert (i, p);
}

bool empty () const { return m_contour.empty (); }
size_t size () const { return m_contour.size (); }
size_t size () const { return m_size; }

void last (long n)
{
Expand Down Expand Up @@ -127,34 +160,84 @@ class PGPolyContour

void clear ()
{
m_size = 0;
m_next = -1;
m_last = -1;
m_contour.clear ();
}

void erase (iterator from, iterator to)
void erase (iterator from, iterator to)
{
m_size -= std::distance (from, to);
m_contour.erase (from, to);
}

void splice (iterator at, PGPolyContour &contour)
{
m_size += contour.size ();
contour.m_size = 0;
m_contour.splice (at, contour.m_contour);
}

template <class I>
iterator insert (iterator at, I from, I to)
{
m_size += std::distance (from, to);
#if 0
// NOTE: in some STL m_contour.insert already returns the new iterator
size_t index_at = at - m_contour.begin ();
m_contour.insert (at, from, to);
return m_contour.begin () + index_at;
#else
return m_contour.insert (at, from, to);
#endif
}

private:
contour_type m_contour;
bool m_is_hole;
long m_next;
long m_last;
size_t m_size;
};

static inline
PGPolyContour::const_iterator operator+ (PGPolyContour::const_iterator i, int n)
{
while (n-- > 0) {
++i;
}
return i;
}

static inline
PGPolyContour::iterator operator+ (PGPolyContour::iterator i, int n)
{
while (n-- > 0) {
++i;
}
return i;
}

static inline
PGPolyContour::const_iterator operator- (PGPolyContour::const_iterator i, int n)
{
while (n-- > 0) {
--i;
}
return i;
}

static inline
PGPolyContour::iterator operator- (PGPolyContour::iterator i, int n)
{
while (n-- > 0) {
--i;
}
return i;
}

class PGContourList
class PGContourList
{
public:
PGContourList ()
Expand Down Expand Up @@ -487,7 +570,7 @@ void PolygonGenerator::eliminate_hole ()
tl_assert (cprev.size () >= 2);

// Compute intersection point with next edge
db::Edge eprev (cprev.end ()[-2], cprev.back ());
db::Edge eprev (*(cprev.end () - 2), cprev.back ());
db::Coord xprev = db::coord_traits<db::Coord>::rounded (edge_xaty (eprev, m_y));
db::Point pprev (xprev, m_y);

Expand All @@ -497,7 +580,7 @@ void PolygonGenerator::eliminate_hole ()

cc.is_hole (false);
cc.push_back (c.front ());
cc.push_back (c.begin ()[1]);
cc.push_back (*(c.begin () + 1));
if (pprev != cc.back ()) {
cc.push_back (pprev);
}
Expand All @@ -506,7 +589,7 @@ void PolygonGenerator::eliminate_hole ()
}

cprev.back () = pprev;
while (cprev.size () > 2 && cprev.back ().y () == m_y && cprev.end ()[-2].y () == m_y && cprev.back ().x () <= cprev.end ()[-2].x ()) {
while (cprev.size () > 2 && cprev.back ().y () == m_y && (cprev.end () - 2)->y () == m_y && cprev.back ().x () <= (cprev.end () - 2)->x ()) {
cprev.pop_back ();
}
cprev.insert (cprev.end (), c.end () - 2, c.end ());
Expand Down Expand Up @@ -597,21 +680,21 @@ PolygonGenerator::join_contours (db::Coord x)
tl_assert (cprev.size () >= 2);

// compute intersection point with next edge
db::Edge eprev (cprev.end ()[-2], cprev.back ());
db::Edge eprev (*(cprev.end () - 2), cprev.back ());
db::Coord xprev = db::coord_traits<db::Coord>::rounded (edge_xaty (eprev, m_y));
db::Point pprev (xprev, m_y);

tl_assert (c1.size () >= 2);
tl_assert (c2.size () >= 2);

cprev.back () = pprev;
while (cprev.size () > 2 && cprev.back ().y () == m_y && cprev.end ()[-2].y () == m_y && cprev.back ().x () <= cprev.end ()[-2].x ()) {
while (cprev.size () > 2 && cprev.back ().y () == m_y && (cprev.end () - 2)->y () == m_y && cprev.back ().x () <= (cprev.end () - 2)->x ()) {
cprev.pop_back ();
}

if (iprev == i1) {

if (cprev.begin ()->y () == m_y && cprev.begin ()[1].y () == m_y && cprev.front ().x () >= cprev.begin ()[1].x ()) {
if (cprev.front ().y () == m_y && (cprev.begin () + 1)->y () == m_y && cprev.front ().x () >= (cprev.begin () + 1)->x ()) {
cprev.front () = cprev.back ();
} else {
cprev.push_front (cprev.back ());
Expand All @@ -621,7 +704,7 @@ PolygonGenerator::join_contours (db::Coord x)

} else {

cprev.insert (cprev.end (), c1.begin (), c1.end ());
cprev.splice (cprev.end (), c1);
cprev.is_hole (false);

mp_contours->join (iprev, i1);
Expand Down Expand Up @@ -666,9 +749,11 @@ PolygonGenerator::join_contours (db::Coord x)

// remove c1 from list of contours, join with c2
if (c2.is_hole ()) {
c2.insert (c2.end (), c1.begin () + 1, c1.end ());
c1.pop_front ();
c2.splice (c2.end (), c1);
} else {
c2.insert (c2.begin (), c1.begin (), c1.end () - 1);
c1.pop_back ();
c2.splice (c2.begin (), c1);
}

mp_contours->join (i2, i1);
Expand All @@ -685,9 +770,11 @@ PolygonGenerator::join_contours (db::Coord x)

// remove c1 from list of contours, join with c2
if (c2.is_hole ()) { // yes! c2 is correct!
c1.insert (c1.end (), c2.begin () + 1, c2.end ());
c2.pop_front ();
c1.splice (c1.end (), c2);
} else {
c1.insert (c1.begin (), c2.begin (), c2.end () - 1);
c2.pop_back ();
c1.splice (c1.begin (), c2);
}

mp_contours->join (i1, i2);
Expand Down Expand Up @@ -740,8 +827,8 @@ PolygonGenerator::join_contours (db::Coord x)
// shallow analysis: insert the cutline at the end of the sequence - this may
// cut lines collinear with contour edges

eprev = db::Edge (ins[-2], ins[-1]);
xprev = db::coord_traits<db::Coord>::rounded (edge_xaty (db::Edge (ins[-2], ins[-1]), m_y));
eprev = db::Edge (*(ins - 2), *(ins - 1));
xprev = db::coord_traits<db::Coord>::rounded (edge_xaty (db::Edge (*(ins - 2), *(ins - 1)), m_y));
#else
// deep analysis: determine insertion point: pick the one where the cutline is shortest
Expand All @@ -763,17 +850,17 @@ PolygonGenerator::join_contours (db::Coord x)
db::Point pprev (xprev, m_y);

// remove collinear edges along the cut line
ins[-1] = pprev;
while (ins - cprev.begin () > 1 && ins[-2].y () == m_y && ins[-1].y () == m_y) {
*(ins - 1) = pprev;
while (ins - 1 != cprev.begin () && (ins - 2)->y () == m_y && (ins - 1)->y () == m_y) {
ins = cprev.erase (ins - 1);
}

if ((c1.begin () + 1)->y () == m_y) {
ins = cprev.insert (ins, c1.begin () + 1, c1.end ());
ins += c1.size () - 1;
ins = ins + (c1.size () - 1);
} else {
ins = cprev.insert (ins, c1.begin (), c1.end ());
ins += c1.size ();
ins = ins + c1.size ();
}

ins = cprev.insert (ins, pprev);
Expand Down
Loading

0 comments on commit ff70818

Please sign in to comment.