mirror of https://github.com/KLayout/klayout.git
Reduce risk of DRC polygon split artefacts in deep mode (#722)
* Fixed a segfault with simple 'klayout -v' * is_halfmanhattan polygon predicate, confine polygon splitting to halfmanhattan Splitting any-angle polygons for area reduction in the deep processor creates a risk of introducing grid-snap artefacts. Hence we avoid this.
This commit is contained in:
parent
c837b306be
commit
e31d7afb64
|
|
@ -601,7 +601,9 @@ ReducingHierarchyBuilderShapeReceiver::reduce (const db::Polygon &poly, const db
|
|||
}
|
||||
}
|
||||
|
||||
if ((m_max_vertex_count >= 4 && poly.vertices () > m_max_vertex_count) || (m_area_ratio > 2.0 && poly.area_ratio () > m_area_ratio)) {
|
||||
// NOTE: only halfmanhattan polygons are guaranteed not to generate grid snap artefacts when splitting.
|
||||
// This is important to maintain the connection integrity of shape clusters.
|
||||
if (poly.is_halfmanhattan () && ((m_max_vertex_count >= 4 && poly.vertices () > m_max_vertex_count) || (m_area_ratio > 2.0 && poly.area_ratio () > m_area_ratio))) {
|
||||
|
||||
std::vector <db::Polygon> split_polygons;
|
||||
db::split_polygon (poly, split_polygons);
|
||||
|
|
|
|||
|
|
@ -743,7 +743,29 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief returns true if the contour is a half-manhattan contour (multiples of 45 degree)
|
||||
*/
|
||||
bool is_halfmanhattan () const
|
||||
{
|
||||
if (((size_t) mp_points & 1) != 0) {
|
||||
return true;
|
||||
}
|
||||
if (m_size < 2) {
|
||||
return false;
|
||||
}
|
||||
point_type pl = mp_points [m_size - 1];
|
||||
for (size_t i = 0; i < m_size; ++i) {
|
||||
point_type p = mp_points [i];
|
||||
if (! coord_traits::equals (p.x (), pl.x ()) && ! coord_traits::equals (p.y (), pl.y ()) && ! coord_traits::equals (std::abs (p.x () - pl.x ()), std::abs (p.y () - pl.y ()))) {
|
||||
return false;
|
||||
}
|
||||
pl = p;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true if the contour is a hole
|
||||
*
|
||||
* Since this method employs the orientation property the results are only valid for
|
||||
|
|
@ -1671,6 +1693,19 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true, if the polygon is halfmanhattan
|
||||
*/
|
||||
bool is_halfmanhattan () const
|
||||
{
|
||||
for (size_t i = 0; i < m_ctrs.size (); ++i) {
|
||||
if (! m_ctrs [i].is_halfmanhattan ()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of points in the polygon
|
||||
*/
|
||||
|
|
@ -2801,6 +2836,14 @@ public:
|
|||
return m_hull.is_rectilinear ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true, if the polygon is halfmanhattan
|
||||
*/
|
||||
bool is_halfmanhattan () const
|
||||
{
|
||||
return m_hull.is_halfmanhattan ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The number of holes
|
||||
*
|
||||
|
|
|
|||
|
|
@ -75,11 +75,6 @@ struct simple_polygon_defs
|
|||
return c->hull ().size ();
|
||||
}
|
||||
|
||||
static bool is_rectilinear (C *c)
|
||||
{
|
||||
return c->hull ().is_rectilinear ();
|
||||
}
|
||||
|
||||
static bool is_empty (C *c)
|
||||
{
|
||||
return c->hull ().size () == 0;
|
||||
|
|
@ -349,9 +344,16 @@ struct simple_polygon_defs
|
|||
method_ext ("is_empty?", &is_empty,
|
||||
"@brief Returns a value indicating whether the polygon is empty\n"
|
||||
) +
|
||||
method_ext ("is_rectilinear?", &is_rectilinear,
|
||||
method ("is_rectilinear?", &C::is_rectilinear,
|
||||
"@brief Returns a value indicating whether the polygon is rectilinear\n"
|
||||
) +
|
||||
method ("is_halfmanhattan?", &C::is_halfmanhattan,
|
||||
"@brief Returns a value indicating whether the polygon is half-manhattan\n"
|
||||
"Half-manhattan polygons have edges which are multiples of 45 degree. These polygons can be clipped at a rectangle without "
|
||||
"potential grid snapping.\n"
|
||||
"\n"
|
||||
"This predicate was introduced in version 0.27.\n"
|
||||
) +
|
||||
method_ext ("inside?", &inside, gsi::arg ("p"),
|
||||
"@brief Gets a value indicating whether the given point is inside the polygon\n"
|
||||
"If the given point is inside or on the edge the polygon, true is returned. "
|
||||
|
|
@ -871,11 +873,6 @@ struct polygon_defs
|
|||
return c->vertices ();
|
||||
}
|
||||
|
||||
static bool is_rectilinear (C *c)
|
||||
{
|
||||
return c->is_rectilinear ();
|
||||
}
|
||||
|
||||
static bool is_empty (C *c)
|
||||
{
|
||||
return c->vertices () == 0;
|
||||
|
|
@ -1151,9 +1148,16 @@ struct polygon_defs
|
|||
method_ext ("is_empty?", &is_empty,
|
||||
"@brief Returns a value indicating whether the polygon is empty\n"
|
||||
) +
|
||||
method_ext ("is_rectilinear?", &is_rectilinear,
|
||||
method ("is_rectilinear?", &C::is_rectilinear,
|
||||
"@brief Returns a value indicating whether the polygon is rectilinear\n"
|
||||
) +
|
||||
method ("is_halfmanhattan?", &C::is_halfmanhattan,
|
||||
"@brief Returns a value indicating whether the polygon is half-manhattan\n"
|
||||
"Half-manhattan polygons have edges which are multiples of 45 degree. These polygons can be clipped at a rectangle without "
|
||||
"potential grid snapping.\n"
|
||||
"\n"
|
||||
"This predicate was introduced in version 0.27.\n"
|
||||
) +
|
||||
method_ext ("hash", &hash_value,
|
||||
"@brief Computes a hash value\n"
|
||||
"Returns a hash value for the given polygon. This method enables polygons as hash keys.\n"
|
||||
|
|
|
|||
|
|
@ -83,6 +83,8 @@ TEST(1)
|
|||
EXPECT_EQ (tl::to_string (p.area_ratio ()), "1");
|
||||
EXPECT_EQ (p.perimeter (), db::Polygon::perimeter_type (2200));
|
||||
EXPECT_EQ (p.is_box (), true);
|
||||
EXPECT_EQ (p.is_rectilinear (), true);
|
||||
EXPECT_EQ (p.is_halfmanhattan (), true);
|
||||
|
||||
c2.push_back (db::Point (10, 10));
|
||||
c2.push_back (db::Point (10, 390));
|
||||
|
|
@ -96,6 +98,9 @@ TEST(1)
|
|||
c3.push_back (db::Point (90, 510));
|
||||
p.insert_hole (c3.begin (), c3.end ());
|
||||
EXPECT_EQ (p.holes (), size_t (2));
|
||||
EXPECT_EQ (p.is_box (), false);
|
||||
EXPECT_EQ (p.is_rectilinear (), true);
|
||||
EXPECT_EQ (p.is_halfmanhattan (), true);
|
||||
|
||||
EXPECT_EQ (p.to_string (), std::string ("(0,0;0,1000;100,1000;100,0/10,10;90,10;90,390;10,390/10,510;90,510;90,890;10,890)"));
|
||||
db::DPolygon dp (p, db::cast_op<db::DPoint, db::Point> ());
|
||||
|
|
@ -148,6 +153,27 @@ TEST(1)
|
|||
|
||||
p.clear ();
|
||||
EXPECT_EQ (p, empty);
|
||||
|
||||
c1.clear ();
|
||||
c1.push_back (db::Point (0, 0));
|
||||
c1.push_back (db::Point (0, 1000));
|
||||
c1.push_back (db::Point (100, 1100));
|
||||
c1.push_back (db::Point (100, 0));
|
||||
p.assign_hull (c1.begin (), c1.end ());
|
||||
EXPECT_EQ (p.is_box (), false);
|
||||
EXPECT_EQ (p.is_rectilinear (), false);
|
||||
EXPECT_EQ (p.is_halfmanhattan (), true);
|
||||
|
||||
|
||||
c1.clear ();
|
||||
c1.push_back (db::Point (0, 0));
|
||||
c1.push_back (db::Point (0, 1000));
|
||||
c1.push_back (db::Point (100, 1101));
|
||||
c1.push_back (db::Point (100, 0));
|
||||
p.assign_hull (c1.begin (), c1.end ());
|
||||
EXPECT_EQ (p.is_box (), false);
|
||||
EXPECT_EQ (p.is_rectilinear (), false);
|
||||
EXPECT_EQ (p.is_halfmanhattan (), false);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -172,6 +198,8 @@ TEST(2)
|
|||
EXPECT_EQ (tl::to_string (p.area_ratio ()), "1");
|
||||
EXPECT_EQ (p.perimeter (), db::SimplePolygon::perimeter_type (2000+200));
|
||||
EXPECT_EQ (p.is_box (), true);
|
||||
EXPECT_EQ (p.is_rectilinear (), true);
|
||||
EXPECT_EQ (p.is_halfmanhattan (), true);
|
||||
|
||||
EXPECT_EQ (p.to_string (), "(0,0;0,1000;100,1000;100,0)");
|
||||
db::DSimplePolygon dp (p, db::cast_op<db::DPoint, db::Point> ());
|
||||
|
|
@ -213,6 +241,24 @@ TEST(2)
|
|||
|
||||
p.clear ();
|
||||
EXPECT_EQ (p, empty);
|
||||
|
||||
c1.clear ();
|
||||
c1.push_back (db::Point (0, 0));
|
||||
c1.push_back (db::Point (0, 1000));
|
||||
c1.push_back (db::Point (100, 1100));
|
||||
c1.push_back (db::Point (100, 0));
|
||||
p.assign_hull (c1.begin (), c1.end ());
|
||||
EXPECT_EQ (p.is_rectilinear (), false);
|
||||
EXPECT_EQ (p.is_halfmanhattan (), true);
|
||||
|
||||
c1.clear ();
|
||||
c1.push_back (db::Point (0, 0));
|
||||
c1.push_back (db::Point (0, 1000));
|
||||
c1.push_back (db::Point (100, 1101));
|
||||
c1.push_back (db::Point (100, 0));
|
||||
p.assign_hull (c1.begin (), c1.end ());
|
||||
EXPECT_EQ (p.is_rectilinear (), false);
|
||||
EXPECT_EQ (p.is_halfmanhattan (), false);
|
||||
}
|
||||
|
||||
TEST(3)
|
||||
|
|
|
|||
|
|
@ -1147,3 +1147,8 @@ TEST(27d_advancedShielding)
|
|||
{
|
||||
run_test (_this, "27", true);
|
||||
}
|
||||
|
||||
TEST(28_inputFragmentation)
|
||||
{
|
||||
run_test (_this, "28", true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1474,7 +1474,7 @@ GuiApplication::start_recording ()
|
|||
lay::Dispatcher *
|
||||
GuiApplication::dispatcher () const
|
||||
{
|
||||
return mp_mw->dispatcher ();
|
||||
return mp_mw ? mp_mw->dispatcher () : 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
|
||||
source $drc_test_source
|
||||
target $drc_test_target
|
||||
|
||||
if $drc_test_deep
|
||||
deep
|
||||
end
|
||||
|
||||
l1 = input(1, 0)
|
||||
l2 = input(2, 0)
|
||||
l3 = input(3, 0)
|
||||
|
||||
l1.output(1, 0)
|
||||
l2.output(2, 0)
|
||||
l3.output(3, 0)
|
||||
|
||||
l1.width(4.995.um, projection, angle_limit(50)).output(100, 0)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -34,6 +34,7 @@ class DBPolygon_TestClass < TestBase
|
|||
assert_equal( a.is_box?, false )
|
||||
assert_equal( a.is_empty?, true )
|
||||
assert_equal( a.is_rectilinear?, false )
|
||||
assert_equal( a.is_halfmanhattan?, false )
|
||||
|
||||
b = a.dup
|
||||
a = RBA::DPolygon::new( [ RBA::DPoint::new( 0, 1 ), RBA::DPoint::new( 1, 5 ), RBA::DPoint::new( 5, 5 ) ] )
|
||||
|
|
@ -44,6 +45,7 @@ class DBPolygon_TestClass < TestBase
|
|||
assert_equal( a.num_points_hull, 3 )
|
||||
assert_equal( a.is_empty?, false )
|
||||
assert_equal( a.is_rectilinear?, false )
|
||||
assert_equal( a.is_halfmanhattan?, false )
|
||||
c = a.dup
|
||||
|
||||
assert_equal( a == b, false )
|
||||
|
|
@ -55,6 +57,7 @@ class DBPolygon_TestClass < TestBase
|
|||
assert_equal( a.is_box?, true )
|
||||
assert_equal( a.is_empty?, false )
|
||||
assert_equal( a.is_rectilinear?, true )
|
||||
assert_equal( a.is_halfmanhattan?, true )
|
||||
assert_equal( a.to_s, "(5,-10;5,15;20,15;20,-10)" )
|
||||
assert_equal( RBA::Polygon::new(a).to_s, "(5,-10;5,15;20,15;20,-10)" )
|
||||
assert_equal( a.num_points_hull, 4 )
|
||||
|
|
@ -148,6 +151,17 @@ class DBPolygon_TestClass < TestBase
|
|||
p = RBA::DPolygon::ellipse( RBA::DBox::new(-10000, -20000, 30000, 40000), 4 )
|
||||
assert_equal(p.to_s, "(10000,-20000;-10000,10000;10000,40000;30000,10000)")
|
||||
|
||||
# halfmanhattan variants
|
||||
p = RBA::DPolygon::new([ RBA::DPoint::new( 0, 0 ), RBA::DPoint::new( 0, 100 ), RBA::DPoint::new( 100, 100 ) ])
|
||||
assert_equal(p.is_halfmanhattan?, true)
|
||||
assert_equal(p.is_rectilinear?, false)
|
||||
p = RBA::DPolygon::new([ RBA::DPoint::new( 0, 0 ), RBA::DPoint::new( 0, 100 ), RBA::DPoint::new( 100, 101 ) ])
|
||||
assert_equal(p.is_halfmanhattan?, false)
|
||||
assert_equal(p.is_rectilinear?, false)
|
||||
p = RBA::DPolygon::new([ RBA::DPoint::new( 0, 0 ), RBA::DPoint::new( 0, 100 ), RBA::DPoint::new( 100, 100 ), RBA::DPoint::new( 100, 0) ])
|
||||
assert_equal(p.is_halfmanhattan?, true)
|
||||
assert_equal(p.is_rectilinear?, true)
|
||||
|
||||
end
|
||||
|
||||
# Polygon basics
|
||||
|
|
@ -300,6 +314,17 @@ class DBPolygon_TestClass < TestBase
|
|||
p = RBA::Polygon::ellipse( RBA::Box::new(-10000, -20000, 30000, 40000), 4 )
|
||||
assert_equal(p.to_s, "(10000,-20000;-10000,10000;10000,40000;30000,10000)")
|
||||
|
||||
# halfmanhattan variants
|
||||
p = RBA::Polygon::new([ RBA::Point::new( 0, 0 ), RBA::Point::new( 0, 100 ), RBA::Point::new( 100, 100 ) ])
|
||||
assert_equal(p.is_halfmanhattan?, true)
|
||||
assert_equal(p.is_rectilinear?, false)
|
||||
p = RBA::Polygon::new([ RBA::Point::new( 0, 0 ), RBA::Point::new( 0, 100 ), RBA::Point::new( 100, 101 ) ])
|
||||
assert_equal(p.is_halfmanhattan?, false)
|
||||
assert_equal(p.is_rectilinear?, false)
|
||||
p = RBA::Polygon::new([ RBA::Point::new( 0, 0 ), RBA::Point::new( 0, 100 ), RBA::Point::new( 100, 100 ), RBA::Point::new( 100, 0) ])
|
||||
assert_equal(p.is_halfmanhattan?, true)
|
||||
assert_equal(p.is_rectilinear?, true)
|
||||
|
||||
end
|
||||
|
||||
# Polygon parametrized edge iterator
|
||||
|
|
@ -367,6 +392,7 @@ class DBPolygon_TestClass < TestBase
|
|||
assert_equal(p.to_s, "()")
|
||||
assert_equal(p.is_empty?, true)
|
||||
assert_equal(p.is_rectilinear?, false)
|
||||
assert_equal(p.is_halfmanhattan?, false)
|
||||
|
||||
pts = [ RBA::Point::new(0, 0) ]
|
||||
p = RBA::Polygon::new(pts)
|
||||
|
|
|
|||
|
|
@ -119,6 +119,17 @@ class DBSimplePolygon_TestClass < TestBase
|
|||
p = RBA::DSimplePolygon::ellipse( RBA::DBox::new(-10000, -20000, 30000, 40000), 4 )
|
||||
assert_equal(p.to_s, "(10000,-20000;-10000,10000;10000,40000;30000,10000)")
|
||||
|
||||
# halfmanhattan variants
|
||||
p = RBA::DSimplePolygon::new([ RBA::DPoint::new( 0, 0 ), RBA::DPoint::new( 0, 100 ), RBA::DPoint::new( 100, 100 ) ])
|
||||
assert_equal(p.is_halfmanhattan?, true)
|
||||
assert_equal(p.is_rectilinear?, false)
|
||||
p = RBA::DSimplePolygon::new([ RBA::DPoint::new( 0, 0 ), RBA::DPoint::new( 0, 100 ), RBA::DPoint::new( 100, 101 ) ])
|
||||
assert_equal(p.is_halfmanhattan?, false)
|
||||
assert_equal(p.is_rectilinear?, false)
|
||||
p = RBA::DSimplePolygon::new([ RBA::DPoint::new( 0, 0 ), RBA::DPoint::new( 0, 100 ), RBA::DPoint::new( 100, 100 ), RBA::DPoint::new( 100, 0) ])
|
||||
assert_equal(p.is_halfmanhattan?, true)
|
||||
assert_equal(p.is_rectilinear?, true)
|
||||
|
||||
end
|
||||
|
||||
# SimplePolygon basics
|
||||
|
|
@ -245,6 +256,17 @@ class DBSimplePolygon_TestClass < TestBase
|
|||
p = RBA::SimplePolygon::ellipse( RBA::Box::new(-10000, -20000, 30000, 40000), 4 )
|
||||
assert_equal(p.to_s, "(10000,-20000;-10000,10000;10000,40000;30000,10000)")
|
||||
|
||||
# halfmanhattan variants
|
||||
p = RBA::SimplePolygon::new([ RBA::Point::new( 0, 0 ), RBA::Point::new( 0, 100 ), RBA::Point::new( 100, 100 ) ])
|
||||
assert_equal(p.is_halfmanhattan?, true)
|
||||
assert_equal(p.is_rectilinear?, false)
|
||||
p = RBA::SimplePolygon::new([ RBA::Point::new( 0, 0 ), RBA::Point::new( 0, 100 ), RBA::Point::new( 100, 101 ) ])
|
||||
assert_equal(p.is_halfmanhattan?, false)
|
||||
assert_equal(p.is_rectilinear?, false)
|
||||
p = RBA::SimplePolygon::new([ RBA::Point::new( 0, 0 ), RBA::Point::new( 0, 100 ), RBA::Point::new( 100, 100 ), RBA::Point::new( 100, 0) ])
|
||||
assert_equal(p.is_halfmanhattan?, true)
|
||||
assert_equal(p.is_rectilinear?, true)
|
||||
|
||||
end
|
||||
|
||||
# raw mode polygons
|
||||
|
|
|
|||
Loading…
Reference in New Issue