GSI binding of Region#binned_area - experimental!

This commit is contained in:
Matthias Koefferlein 2024-08-29 22:53:19 +02:00
parent 8fa308b74c
commit a2e449989e
2 changed files with 103 additions and 1 deletions

View File

@ -21,10 +21,107 @@
*/
#include "dbBinnedAreaCollector.h"
#include "dbTypes.h"
#include "dbRegion.h"
#include "gsiDecl.h"
#include <vector>
namespace db
{
// .. nothing yet ..
namespace
{
class AreaReceiver
: public db::binned_area_receiver<unsigned int>
{
public:
typedef db::coord_traits<db::Coord>::area_type area_type;
AreaReceiver (unsigned int count)
{
m_areas.resize (count, 0.0);
}
virtual void add_area (area_type area, const unsigned int &index)
{
m_areas [index] += area;
}
const std::vector<area_type> &get () const
{
return m_areas;
}
private:
std::vector<area_type> m_areas;
};
}
// NOTE: this does not belong here. It is an experimental feature
static std::vector<AreaReceiver::area_type>
binned_area (const std::vector<const db::Region *> &inputs, const std::vector<std::string> &vectors)
{
db::EdgeProcessor ep;
unsigned int index = 0;
for (auto r = inputs.begin (); r != inputs.end (); ++r, ++index) {
for (auto p = (*r)->begin (); ! p.at_end (); ++p) {
ep.insert (*p, index);
}
}
tl::bit_set_map<unsigned int> bsm;
index = 0;
for (auto i = vectors.begin (); i != vectors.end (); ++i, ++index) {
bsm.insert (tl::BitSetMask (*i), index);
}
bsm.sort ();
AreaReceiver rec (index);
db::binned_area_collector<unsigned int> coll (bsm, rec);
ep.process (coll, coll);
return rec.get ();
}
gsi::ClassExt<db::Region> extend_region_by_binned_area (
gsi::method ("binned_area", &binned_area, gsi::arg ("inputs"), gsi::arg ("masks"),
"@brief Computes the areas of a binned decomposition of the overall region.\n"
"In this function, the overall region is decomposed into subregions with different overlap situations. "
"Each overlap case is assigned a bin using a bit mask from the 'masks' argument. "
"Each bit corresponds to one input from 'inputs' - bit 0 is the first one etc.\n"
"The masks are strings of characters 0, 1 or 'X', representing 'inside', 'outside' and "
"'any' for the respective input. The first character represents the first input, the second the second input etc.\n"
"Missing characters are treated as 'any', so the empty string matches every situation.\n"
"\n"
"The result is a vector of accumulated areas for each bin identified by one mask. "
"Bins may overlay if multiple masks match, so the total sum of areas is not necessarily "
"identical to the total area. A bin with an empty string mask will deliver the total area.\n"
"\n"
"Merge semantics always applies - i.e. all shapes inside the regions are conceptually "
"merged in 'positive wrap count' mode before computing the area. Hence overlapping shapes ""
"per input region just count once.\n"
"\n"
"Example:\n"
"\n"
"@code\n"
"r1 = RBA::Region::new\n"
"r1.insert(RBA::Box::new(0, 0, 1000, 2000))\n"
"\n"
"r2 = RBA::Region::new\n"
"r2.insert(RBA::Box::new(500, 1000, 1500, 3000))\n"
"\n"
"areas = RBA::Region::binned_area([ r1, r2 ], [ \"10\", \"01\", \"\" ])\n"
"r1_not_r2, r2_not_r1, all = areas\n"
"@/code\n"
"\n"
"This feature is highly experimental."
)
);
}

View File

@ -206,6 +206,11 @@ public:
mp_receiver->finish ();
}
virtual void put (const db::Edge &, int)
{
// not used.
}
virtual void put (const db::Edge &edge)
{
area_type partial_area = area_type (edge.p1 ().x () + edge.p2 ().x ()) * area_type (edge.dy ()) * 0.5;