Fixing a performance issue on hole insertion for polygons with many holes

This commit is contained in:
Matthias Koefferlein 2023-05-19 00:48:36 +02:00
parent bd33640471
commit 331bb5aed4
7 changed files with 71 additions and 16 deletions

View File

@ -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)

View File

@ -865,6 +865,8 @@ PolygonGenerator::produce_poly (const PGPolyContour &c)
}
m_poly.sort_holes ();
}
mp_psink->put (m_poly);

View File

@ -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;
}

View File

@ -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"

View File

@ -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));

View File

@ -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)" )

View File

@ -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)" )