From a431f70ad422e05812cb1b5bd209d6494a1d1d4a Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 29 Feb 2024 22:57:28 +0100 Subject: [PATCH] Polygon#break, DPolygon#break, SimplPolygon#break, DSimplePolygon#break --- src/db/db/gsiDeclDbPolygon.cc | 79 +++++++++++++++++++++++++++------- testdata/ruby/dbPolygonTest.rb | 48 +++++++++++++++++++++ 2 files changed, 111 insertions(+), 16 deletions(-) diff --git a/src/db/db/gsiDeclDbPolygon.cc b/src/db/db/gsiDeclDbPolygon.cc index 417351c16..bc31beb55 100644 --- a/src/db/db/gsiDeclDbPolygon.cc +++ b/src/db/db/gsiDeclDbPolygon.cc @@ -31,6 +31,39 @@ namespace gsi { +template +static std::vector split_poly (const C *p) +{ + std::vector parts; + db::split_polygon (*p, parts); + return parts; +} + +template +static void break_polygon (const C &poly, size_t max_vertex_count, double max_area_ratio, std::vector &result) +{ + if ((max_vertex_count > 0 && poly.vertices () > max_vertex_count) || + (max_area_ratio > 0 && poly.area_ratio () > max_area_ratio)) { + + std::vector split_polygons; + db::split_polygon (poly, split_polygons); + for (auto p = split_polygons.begin (); p != split_polygons.end (); ++p) { + break_polygon (*p, max_vertex_count, max_area_ratio, result); + } + + } else { + result.push_back (poly); + } +} + +template +static std::vector break_poly (const C *p, size_t max_vertex_count, double max_area_ratio) +{ + std::vector parts; + break_polygon (*p, max_vertex_count, max_area_ratio, parts); + return parts; +} + // --------------------------------------------------------------- // simple polygon binding @@ -245,13 +278,6 @@ struct simple_polygon_defs return db::interact (*p, spoly); } - static std::vector split_poly (const C *p) - { - std::vector parts; - db::split_polygon (*p, parts); - return parts; - } - static gsi::Methods methods () { return @@ -508,7 +534,7 @@ struct simple_polygon_defs "\n" "This method was introduced in version 0.25.\n" ) + - method_ext ("split", &split_poly, + method_ext ("split", &split_poly, "@brief Splits the polygon into two or more parts\n" "This method will break the polygon into parts. The exact breaking algorithm is unspecified, the " "result are smaller polygons of roughly equal number of points and 'less concave' nature. " @@ -521,6 +547,20 @@ struct simple_polygon_defs "\n" "This method has been introduced in version 0.25.3." ) + + method_ext ("break", &break_poly, gsi::arg ("max_vertex_count"), gsi::arg ("max_area_ratio"), + "@brief Splits the polygon into parts with a maximum vertex count and area ratio\n" + "The area ratio is the ratio between the bounding box area and the polygon area. Higher values " + "mean more 'skinny' polygons.\n" + "\n" + "This method will split the input polygon into pieces having a maximum of 'max_vertex_count' vertices " + "and an area ratio less than 'max_area_ratio'. 'max_vertex_count' can be zero. In this case the " + "limit is ignored. Also 'max_area_ratio' can be zero, in which case it is ignored as well.\n" + "\n" + "The method of splitting is unspecified. The algorithm will apply 'split' recursively until the " + "parts satisfy the limits.\n" + "\n" + "This method has been introduced in version 0.29." + ) + method_ext ("area", &area, "@brief Gets the area of the polygon\n" "The area is correct only if the polygon is not self-overlapping and the polygon is oriented clockwise." @@ -1098,13 +1138,6 @@ struct polygon_defs return db::interact (*p, spoly); } - static std::vector split_spoly (const C *p) - { - std::vector parts; - db::split_polygon (*p, parts); - return parts; - } - static gsi::Methods methods () { return @@ -1520,7 +1553,7 @@ struct polygon_defs "\n" "This method was introduced in version 0.25.\n" ) + - method_ext ("split", &split_spoly, + method_ext ("split", &split_poly, "@brief Splits the polygon into two or more parts\n" "This method will break the polygon into parts. The exact breaking algorithm is unspecified, the " "result are smaller polygons of roughly equal number of points and 'less concave' nature. " @@ -1533,6 +1566,20 @@ struct polygon_defs "\n" "This method has been introduced in version 0.25.3." ) + + method_ext ("break", &break_poly, gsi::arg ("max_vertex_count"), gsi::arg ("max_area_ratio"), + "@brief Splits the polygon into parts with a maximum vertex count and area ratio\n" + "The area ratio is the ratio between the bounding box area and the polygon area. Higher values " + "mean more 'skinny' polygons.\n" + "\n" + "This method will split the input polygon into pieces having a maximum of 'max_vertex_count' vertices " + "and an area ratio less than 'max_area_ratio'. 'max_vertex_count' can be zero. In this case the " + "limit is ignored. Also 'max_area_ratio' can be zero, in which case it is ignored as well.\n" + "\n" + "The method of splitting is unspecified. The algorithm will apply 'split' recursively until the " + "parts satisfy the limits.\n" + "\n" + "This method has been introduced in version 0.29." + ) + method_ext ("area", &area, "@brief Gets the area of the polygon\n" "The area is correct only if the polygon is not self-overlapping and the polygon is oriented clockwise." diff --git a/testdata/ruby/dbPolygonTest.rb b/testdata/ruby/dbPolygonTest.rb index bdd290f01..cb1910017 100644 --- a/testdata/ruby/dbPolygonTest.rb +++ b/testdata/ruby/dbPolygonTest.rb @@ -821,6 +821,54 @@ class DBPolygon_TestClass < TestBase end + def test_breakPolygon + + pts = [] + pts << RBA::Point::new(0, 0) + pts << RBA::Point::new(0, 1000) + pts << RBA::Point::new(100, 1000) + pts << RBA::Point::new(100, 100) + pts << RBA::Point::new(1000, 100) + pts << RBA::Point::new(1000, 0) + + split = RBA::Polygon::new(pts).break(4, 0) + assert_equal(split.collect { |p| p.to_s }.join(";"), "(0,0;0,100;1000,100;1000,0);(0,100;0,1000;100,1000;100,100)") + split = RBA::Polygon::new(pts).break(0, 2.0) + assert_equal(split.collect { |p| p.to_s }.join(";"), "(0,0;0,100;1000,100;1000,0);(0,100;0,1000;100,1000;100,100)") + split = RBA::Polygon::new(pts).break(0, 0) + assert_equal(split.collect { |p| p.to_s }.join(";"), "(0,0;0,1000;100,1000;100,100;1000,100;1000,0)") + + split = RBA::SimplePolygon::new(pts).break(4, 0) + assert_equal(split.collect { |p| p.to_s }.join(";"), "(0,0;0,100;1000,100;1000,0);(0,100;0,1000;100,1000;100,100)") + split = RBA::SimplePolygon::new(pts).break(0, 2.0) + assert_equal(split.collect { |p| p.to_s }.join(";"), "(0,0;0,100;1000,100;1000,0);(0,100;0,1000;100,1000;100,100)") + split = RBA::SimplePolygon::new(pts).break(0, 0) + assert_equal(split.collect { |p| p.to_s }.join(";"), "(0,0;0,1000;100,1000;100,100;1000,100;1000,0)") + + pts = [] + pts << RBA::DPoint::new(0, 0) + pts << RBA::DPoint::new(0, 1000) + pts << RBA::DPoint::new(100, 1000) + pts << RBA::DPoint::new(100, 100) + pts << RBA::DPoint::new(1000, 100) + pts << RBA::DPoint::new(1000, 0) + + split = RBA::DPolygon::new(pts).break(4, 0) + assert_equal(split.collect { |p| p.to_s }.join(";"), "(0,0;0,100;1000,100;1000,0);(0,100;0,1000;100,1000;100,100)") + split = RBA::DPolygon::new(pts).break(0, 2.0) + assert_equal(split.collect { |p| p.to_s }.join(";"), "(0,0;0,100;1000,100;1000,0);(0,100;0,1000;100,1000;100,100)") + split = RBA::DPolygon::new(pts).break(0, 0) + assert_equal(split.collect { |p| p.to_s }.join(";"), "(0,0;0,1000;100,1000;100,100;1000,100;1000,0)") + + split = RBA::DSimplePolygon::new(pts).break(4, 0) + assert_equal(split.collect { |p| p.to_s }.join(";"), "(0,0;0,100;1000,100;1000,0);(0,100;0,1000;100,1000;100,100)") + split = RBA::DSimplePolygon::new(pts).break(0, 2.0) + assert_equal(split.collect { |p| p.to_s }.join(";"), "(0,0;0,100;1000,100;1000,0);(0,100;0,1000;100,1000;100,100)") + split = RBA::DSimplePolygon::new(pts).break(0, 0) + assert_equal(split.collect { |p| p.to_s }.join(";"), "(0,0;0,1000;100,1000;100,100;1000,100;1000,0)") + + end + def test_voidMethodsReturnSelf hull = [ RBA::Point::new(0, 0), RBA::Point::new(6000, 0),