Grayscale rasterizer for Region

This commit is contained in:
Matthias Koefferlein 2024-01-28 22:10:33 +01:00
parent 1dbb3917c8
commit 596c6c0aac
2 changed files with 95 additions and 0 deletions

View File

@ -780,6 +780,39 @@ size_dvm (db::Region *region, const db::Vector &dv, unsigned int mode)
return *region;
}
static std::vector<std::vector<double> >
rasterize2 (const db::Region *region, const db::Point &origin, const db::Vector &pixel_distance, const db::Vector &pixel_size, unsigned int nx, unsigned int ny)
{
db::AreaMap am (origin, pixel_distance, pixel_size, nx, ny);
auto si = region->begin ();
si = si.confined (am.bbox (), false /*not overlapping*/);
while (! si.at_end ()) {
db::rasterize (*si, am);
++si;
}
std::vector<std::vector<double> > result;
result.reserve (ny);
for (unsigned int y = 0; y < ny; ++y) {
result.push_back (std::vector<double> ());
std::vector<double> &row = result.back ();
row.reserve (nx);
for (unsigned int x = 0; x < nx; ++x) {
row.push_back (am.get (x, y));
}
}
return result;
}
static std::vector<std::vector<double> >
rasterize1 (const db::Region *region, const db::Point &origin, const db::Vector &pixel_size, unsigned int nx, unsigned int ny)
{
return rasterize2 (region, origin, pixel_size, pixel_size, nx, ny);
}
static db::Point default_origin;
// provided by gsiDeclDbPolygon.cc:
@ -3071,6 +3104,38 @@ Class<db::Region> decl_Region (decl_dbShapeCollection, "db", "Region",
"@brief Converts the region to a string\n"
"This version allows specification of the maximum number of polygons contained in the string."
) +
method_ext ("rasterize", &rasterize1, gsi::arg ("origin"), gsi::arg ("pixel_size"), gsi::arg ("nx"), gsi::arg ("ny"),
"@brief A grayscale rasterizer delivering the area covered per pixel\n"
"@param origin The lower-left corner of the lowest-left pixel\n"
"@param pixel_size The dimension of each pixel (the x component gives the width, the y component the height)\n"
"@param nx The number of pixels in horizontal direction\n"
"@param ny The number of pixels in vertical direction\n"
"The method will create a grayscale, high-resolution density map of a rectangular region.\n"
"The scan region is defined by the origin, the pixel size and the number of pixels in horizontal (nx) and\n"
"vertical (ny) direction. The resulting array will contain the area covered by polygons from the region\n"
"in square database units.\n"
"\n"
"For non-overlapping polygons, the maximum density value is px*py. Overlapping polygons are counted multiple\n"
"times, so the actual values may be larger. If you want overlaps removed, you have to\n"
"merge the region before. Merge semantics does not apply for the 'rasterize' method.\n"
"\n"
"Although the resulting area values are floating-point, internal computation is done with integer precision currently.\n"
"This implies a certain area error when skew angle edges are involved. The pixel area is precise for Manhattan and\n""
"half-Manhattan (45 degree multiples) input geometries.\n"
"\n"
"A second version exists that allows specifying an active pixel size which is smaller than the\n"
"pixel distance hence allowing pixels samples that do not cover the full area, but leave gaps between the pixels.\n"
"\n"
"This method has been added in version 0.29.\n"
) +
method_ext ("rasterize", &rasterize2, gsi::arg ("origin"), gsi::arg ("pixel_distance"), gsi::arg ("pixel_size"), gsi::arg ("nx"), gsi::arg ("ny"),
"@brief A version of 'rasterize' that allows a pixel step distance which is larger than the pixel size\n"
"This version behaves like the first variant of 'rasterize', but the pixel distance (pixel-to-pixel step raster)\n"
"can be specified separately from the pixel size. Currently, the pixel size must be equal or smaller than the\n"
"pixel distance - i.e. the pixels must not overlap.\n"
"\n"
"This method has been added in version 0.29.\n"
) +
method ("enable_progress", &db::Region::enable_progress, gsi::arg ("label"),
"@brief Enable progress reporting\n"
"After calling this method, the region will report the progress through a progress bar while "

View File

@ -1188,6 +1188,36 @@ class DBRegion_TestClass < TestBase
end
# rasterize
def test_rasterize
r = RBA::Region::new()
r.insert(RBA::Polygon::new([[0, 0], [100, 100], [200, 0]]))
r.insert(RBA::Polygon::new(RBA::Box::new([0, 200], [100, 300])))
pd = RBA::Vector::new(50, 50)
ps = RBA::Vector::new(25, 25)
sum = 0
2.times do |ix|
2.times do |iy|
am = r.rasterize(RBA::Point::new(-50 + ix * ps.x, -20 + iy * ps.y), pd, ps, 7, 7)
sum += am.collect { |r| r.sum }.sum
end
end
assert_equal(sum, 8.0 * pd.x * pd.y)
tot = 0.0
pd = RBA::Vector::new(50, 50)
am = r.rasterize(RBA::Point::new(-50, -20), pd, 7, 7)
sum = am.collect { |r| r.sum }.sum
assert_equal(sum, 8.0 * pd.x * pd.y)
end
end
load("test_epilogue.rb")