Merge branch 'master' of github.com:KLayout/klayout

This commit is contained in:
Matthias Koefferlein 2021-02-05 23:29:05 +01:00
commit 9d349239b5
13 changed files with 230 additions and 19 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -1147,3 +1147,8 @@ TEST(27d_advancedShielding)
{
run_test (_this, "27", true);
}
TEST(28_inputFragmentation)
{
run_test (_this, "28", true);
}

View File

@ -287,7 +287,11 @@ std::string dirname (const std::string &s)
parts.pop_back ();
}
return tl::join (parts, "");
if (parts.empty ()) {
return is_part_with_separator (s) ? "" : ".";
} else {
return tl::join (parts, "");
}
}
std::string filename (const std::string &s)

View File

@ -351,6 +351,9 @@ TEST (10)
EXPECT_EQ (tl::normalize_path ("d:/"), "D:\\");
EXPECT_EQ (tl::normalize_path ("d://"), "D:\\");
EXPECT_EQ (tl::dirname ("hello"), ".");
EXPECT_EQ (tl::dirname (".\\hello"), ".");
EXPECT_EQ (tl::dirname ("/hello"), "");
EXPECT_EQ (tl::dirname ("/hello/world"), "\\hello");
EXPECT_EQ (tl::dirname ("\\hello\\world"), "\\hello");
EXPECT_EQ (tl::dirname ("/hello//world/"), "\\hello\\world");
@ -406,6 +409,33 @@ TEST (10)
EXPECT_EQ (tl::combine_path ("hello", "world"), "hello\\world");
EXPECT_EQ (tl::combine_path ("hello", ""), "hello");
EXPECT_EQ (tl::combine_path ("hello", "", true), "hello\\");
EXPECT_EQ (tl::combine_path ("", "hello", true), "\\hello");
EXPECT_EQ (tl::combine_path (".", "hello", true), ".\\hello");
EXPECT_EQ (tl::combine_path (tl::dirname ("hello"), tl::filename ("hello")), ".\\hello");
EXPECT_EQ (tl::combine_path (tl::dirname ("\\hello"), tl::filename ("\\hello")), "\\hello");
EXPECT_EQ (tl::combine_path (tl::dirname ("c:\\hello"), tl::filename ("c:\\hello")), "C:\\hello");
EXPECT_EQ (tl::combine_path (tl::dirname ("\\c:\\hello"), tl::filename ("\\c:\\hello")), "C:\\hello");
EXPECT_EQ (tl::combine_path (tl::dirname ("\\\\hello"), tl::filename ("\\\\hello")), "\\hello");
EXPECT_EQ (tl::combine_path (tl::dirname ("\\\\server:\\hello"), tl::filename ("\\\\server:\\hello")), "\\\\server:\\hello");
EXPECT_EQ (tl::combine_path (tl::dirname ("\\hello\\x"), tl::filename ("\\hello\\x")), "\\hello\\x");
EXPECT_EQ (tl::combine_path (tl::dirname ("c:\\hello\\x"), tl::filename ("c:\\hello\\x")), "C:\\hello\\x");
EXPECT_EQ (tl::combine_path (tl::dirname ("\\c:\\hello\\x"), tl::filename ("\\c:\\hello\\x")), "C:\\hello\\x");
EXPECT_EQ (tl::combine_path (tl::dirname ("\\\\hello\\x"), tl::filename ("\\\\hello\\x")), "\\\\hello\\x");
EXPECT_EQ (tl::combine_path (tl::dirname ("\\hello\\x\\y"), tl::filename ("\\hello\\x\\y")), "\\hello\\x\\y");
EXPECT_EQ (tl::combine_path (tl::dirname ("hello/x"), tl::filename ("hello/x")), "hello\\x");
EXPECT_EQ (tl::combine_path (tl::dirname ("/hello"), tl::filename ("/hello")), "\\hello");
EXPECT_EQ (tl::combine_path (tl::dirname ("c:/hello"), tl::filename ("c:/hello")), "C:\\hello");
EXPECT_EQ (tl::combine_path (tl::dirname ("/c:/hello"), tl::filename ("/c:/hello")), "C:\\hello");
EXPECT_EQ (tl::combine_path (tl::dirname ("//hello"), tl::filename ("//hello")), "\\hello");
EXPECT_EQ (tl::combine_path (tl::dirname ("//server:/hello"), tl::filename ("//server:/hello")), "\\\\server:\\hello");
EXPECT_EQ (tl::combine_path (tl::dirname ("/hello/x"), tl::filename ("/hello/x")), "\\hello\\x");
EXPECT_EQ (tl::combine_path (tl::dirname ("c:/hello/x"), tl::filename ("c:/hello/x")), "C:\\hello\\x");
EXPECT_EQ (tl::combine_path (tl::dirname ("/c:/hello/x"), tl::filename ("/c:/hello/x")), "C:\\hello\\x");
EXPECT_EQ (tl::combine_path (tl::dirname ("//hello/x"), tl::filename ("//hello/x")), "\\\\hello\\x");
EXPECT_EQ (tl::combine_path (tl::dirname ("/hello/x/y"), tl::filename ("/hello/x/y")), "\\hello\\x\\y");
EXPECT_EQ (tl::combine_path (tl::dirname ("hello/x"), tl::filename ("hello/x")), "hello\\x");
tl::file_utils_force_reset ();
@ -436,6 +466,9 @@ TEST (11)
EXPECT_EQ (tl::join (tl::split_path ("/"), "+"), "/");
EXPECT_EQ (tl::join (tl::split_path ("//"), "+"), "/");
EXPECT_EQ (tl::dirname ("hello"), ".");
EXPECT_EQ (tl::dirname ("./hello"), ".");
EXPECT_EQ (tl::dirname ("/hello"), "");
EXPECT_EQ (tl::dirname ("/hello/world"), "/hello");
EXPECT_EQ (tl::dirname ("/hello//world/"), "/hello/world");
EXPECT_EQ (tl::dirname ("hello//world/"), "hello/world");
@ -461,6 +494,14 @@ TEST (11)
EXPECT_EQ (tl::combine_path ("hello", "world"), "hello/world");
EXPECT_EQ (tl::combine_path ("hello", ""), "hello");
EXPECT_EQ (tl::combine_path ("hello", "", true), "hello/");
EXPECT_EQ (tl::combine_path ("", "hello", true), "/hello");
EXPECT_EQ (tl::combine_path (".", "hello", true), "./hello");
EXPECT_EQ (tl::combine_path (tl::dirname ("hello"), tl::filename ("hello")), "./hello");
EXPECT_EQ (tl::combine_path (tl::dirname ("/hello"), tl::filename ("/hello")), "/hello");
EXPECT_EQ (tl::combine_path (tl::dirname ("/hello/x"), tl::filename ("/hello/x")), "/hello/x");
EXPECT_EQ (tl::combine_path (tl::dirname ("/hello/x/y"), tl::filename ("/hello/x/y")), "/hello/x/y");
EXPECT_EQ (tl::combine_path (tl::dirname ("hello/x"), tl::filename ("hello/x")), "hello/x");
tl::file_utils_force_reset ();

View File

@ -138,15 +138,15 @@ TEST(TextInputStream)
tl::InputStream is (fn);
tl::TextInputStream tis (is);
EXPECT_EQ (tis.get_line (), "Hello, world!");
EXPECT_EQ (tis.line_number (), 1);
EXPECT_EQ (tis.line_number (), size_t (1));
EXPECT_EQ (tis.get_line (), "With another line");
EXPECT_EQ (tis.line_number (), 2);
EXPECT_EQ (tis.line_number (), size_t (2));
EXPECT_EQ (tis.peek_char (), '\n');
EXPECT_EQ (tis.get_line (), "");
EXPECT_EQ (tis.line_number (), 3);
EXPECT_EQ (tis.line_number (), size_t (3));
EXPECT_EQ (tis.peek_char (), 's');
EXPECT_EQ (tis.get_line (), "separated by a LFCR and CRLF.");
EXPECT_EQ (tis.line_number (), 4);
EXPECT_EQ (tis.line_number (), size_t (4));
EXPECT_EQ (tis.at_end (), true);
}

18
testdata/drc/drcSimpleTests_28.drc vendored Normal file
View File

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

BIN
testdata/drc/drcSimpleTests_28.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au28d.gds vendored Normal file

Binary file not shown.

View File

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

View File

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