diff --git a/src/db/db/dbHierarchyBuilder.cc b/src/db/db/dbHierarchyBuilder.cc index 0ae678485..5a6751f87 100644 --- a/src/db/db/dbHierarchyBuilder.cc +++ b/src/db/db/dbHierarchyBuilder.cc @@ -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 split_polygons; db::split_polygon (poly, split_polygons); diff --git a/src/db/db/dbPolygon.h b/src/db/db/dbPolygon.h index 7c5b4aa3c..56e8b5e04 100644 --- a/src/db/db/dbPolygon.h +++ b/src/db/db/dbPolygon.h @@ -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 * diff --git a/src/db/db/gsiDeclDbPolygon.cc b/src/db/db/gsiDeclDbPolygon.cc index d0f07fcda..76f3315c9 100644 --- a/src/db/db/gsiDeclDbPolygon.cc +++ b/src/db/db/gsiDeclDbPolygon.cc @@ -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" diff --git a/src/db/unit_tests/dbPolygonTests.cc b/src/db/unit_tests/dbPolygonTests.cc index fbacfade3..c8729acdf 100644 --- a/src/db/unit_tests/dbPolygonTests.cc +++ b/src/db/unit_tests/dbPolygonTests.cc @@ -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 ()); @@ -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 ()); @@ -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) diff --git a/src/drc/unit_tests/drcSimpleTests.cc b/src/drc/unit_tests/drcSimpleTests.cc index b52c4213f..9f0d45e6a 100644 --- a/src/drc/unit_tests/drcSimpleTests.cc +++ b/src/drc/unit_tests/drcSimpleTests.cc @@ -1147,3 +1147,8 @@ TEST(27d_advancedShielding) { run_test (_this, "27", true); } + +TEST(28_inputFragmentation) +{ + run_test (_this, "28", true); +} diff --git a/src/tl/tl/tlFileUtils.cc b/src/tl/tl/tlFileUtils.cc index d4028e093..93fa77860 100644 --- a/src/tl/tl/tlFileUtils.cc +++ b/src/tl/tl/tlFileUtils.cc @@ -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) diff --git a/src/tl/unit_tests/tlFileUtilsTests.cc b/src/tl/unit_tests/tlFileUtilsTests.cc index edf0ae01f..b77b7968e 100644 --- a/src/tl/unit_tests/tlFileUtilsTests.cc +++ b/src/tl/unit_tests/tlFileUtilsTests.cc @@ -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 (); diff --git a/src/tl/unit_tests/tlStreamTests.cc b/src/tl/unit_tests/tlStreamTests.cc index a684f14fa..daad877f7 100644 --- a/src/tl/unit_tests/tlStreamTests.cc +++ b/src/tl/unit_tests/tlStreamTests.cc @@ -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); } diff --git a/testdata/drc/drcSimpleTests_28.drc b/testdata/drc/drcSimpleTests_28.drc new file mode 100644 index 000000000..1775c164b --- /dev/null +++ b/testdata/drc/drcSimpleTests_28.drc @@ -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) + diff --git a/testdata/drc/drcSimpleTests_28.gds b/testdata/drc/drcSimpleTests_28.gds new file mode 100644 index 000000000..ec5efa65a Binary files /dev/null and b/testdata/drc/drcSimpleTests_28.gds differ diff --git a/testdata/drc/drcSimpleTests_au28d.gds b/testdata/drc/drcSimpleTests_au28d.gds new file mode 100644 index 000000000..b8bb80e76 Binary files /dev/null and b/testdata/drc/drcSimpleTests_au28d.gds differ diff --git a/testdata/ruby/dbPolygonTest.rb b/testdata/ruby/dbPolygonTest.rb index e573b975c..468864b35 100644 --- a/testdata/ruby/dbPolygonTest.rb +++ b/testdata/ruby/dbPolygonTest.rb @@ -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) diff --git a/testdata/ruby/dbSimplePolygonTest.rb b/testdata/ruby/dbSimplePolygonTest.rb index 4a35ab0ee..850640561 100644 --- a/testdata/ruby/dbSimplePolygonTest.rb +++ b/testdata/ruby/dbSimplePolygonTest.rb @@ -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