Polygon#break, DPolygon#break, SimplPolygon#break, DSimplePolygon#break

This commit is contained in:
Matthias Koefferlein 2024-02-29 22:57:28 +01:00
parent c2187e0bf0
commit a431f70ad4
2 changed files with 111 additions and 16 deletions

View File

@ -31,6 +31,39 @@
namespace gsi
{
template <class C>
static std::vector<C> split_poly (const C *p)
{
std::vector<C> parts;
db::split_polygon (*p, parts);
return parts;
}
template <class C>
static void break_polygon (const C &poly, size_t max_vertex_count, double max_area_ratio, std::vector<C> &result)
{
if ((max_vertex_count > 0 && poly.vertices () > max_vertex_count) ||
(max_area_ratio > 0 && poly.area_ratio () > max_area_ratio)) {
std::vector<C> 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 <class C>
static std::vector<C> break_poly (const C *p, size_t max_vertex_count, double max_area_ratio)
{
std::vector<C> 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<C> split_poly (const C *p)
{
std::vector<C> 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<C>,
"@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<C>, 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<C> split_spoly (const C *p)
{
std::vector<C> 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<C>,
"@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<C>, 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."

View File

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