mirror of https://github.com/KLayout/klayout.git
Added twofold-typed box scanner.
This commit is contained in:
parent
4c4261be6c
commit
b25401c254
|
|
@ -122,7 +122,7 @@ struct box_scanner_receiver
|
|||
*/
|
||||
void finish (const Obj * /*obj*/, const Prop & /*prop*/) { }
|
||||
|
||||
/*
|
||||
/**
|
||||
* @brief Callback for an interaction of o1 with o2.
|
||||
*
|
||||
* This method is called when the object o1 interacts with o2 within the current
|
||||
|
|
@ -389,6 +389,375 @@ private:
|
|||
std::string m_progress_desc;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A template for the twofold box scanner output receiver
|
||||
*
|
||||
* This template specifies the methods or provides a default implementation for them
|
||||
* for use as the output receiver of the twofold box scanner.
|
||||
*/
|
||||
template <class Obj1, class Prop1, class Obj2, class Prop2>
|
||||
struct box_scanner_receiver2
|
||||
{
|
||||
/**
|
||||
* @brief Indicates that the given object of first type is no longer used
|
||||
*
|
||||
* The finish1 method is called when an object of the first type is no longer in the queue and can be
|
||||
* discarded.
|
||||
*/
|
||||
void finish1 (const Obj1 * /*obj*/, const Prop1 & /*prop*/) { }
|
||||
|
||||
/**
|
||||
* @brief Indicates that the given object of second type is no longer used
|
||||
*
|
||||
* The finish method is called when an object of the second type is no longer in the queue and can be
|
||||
* discarded.
|
||||
*/
|
||||
void finish2 (const Obj2 * /*obj*/, const Prop2 & /*prop*/) { }
|
||||
|
||||
/**
|
||||
* @brief Callback for an interaction of o1 with o2.
|
||||
*
|
||||
* This method is called when the object o1 interacts with o2 within the current
|
||||
* definition.
|
||||
*/
|
||||
void add (const Obj1 * /*o1*/, const Prop1 & /*p1*/, const Obj2 * /*o2*/, const Prop2 & /*p2*/) { }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A box scanner framework (twofold version)
|
||||
*
|
||||
* This implementation provides a box scanner for two different types. Apart from
|
||||
* that it is similar to the uniform-type box scanner.
|
||||
*
|
||||
* It will not report interactions within the Obj1 or Obj2 group, but only
|
||||
* interactions between Obj1 and Obj2 objects.
|
||||
*/
|
||||
template <class Obj1, class Prop1, class Obj2, class Prop2>
|
||||
class box_scanner2
|
||||
{
|
||||
public:
|
||||
typedef Obj1 object_type1;
|
||||
typedef Obj2 object_type2;
|
||||
typedef std::vector<std::pair<const Obj1 *, Prop1> > container_type1;
|
||||
typedef std::vector<std::pair<const Obj2 *, Prop2> > container_type2;
|
||||
typedef typename container_type1::iterator iterator_type1;
|
||||
typedef typename container_type2::iterator iterator_type2;
|
||||
|
||||
/**
|
||||
* @brief Default ctor
|
||||
*/
|
||||
box_scanner2 (bool report_progress = false, const std::string &progress_desc = std::string ())
|
||||
: m_fill_factor (2), m_scanner_thr (100),
|
||||
m_report_progress (report_progress), m_progress_desc (progress_desc)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the scanner threshold
|
||||
*
|
||||
* This value determines for how many elements the implementation switches to the scanner
|
||||
* implementation instead of the plain element-by-element interaction test.
|
||||
* The default value is 100.
|
||||
*/
|
||||
void set_scanner_threshold (size_t n)
|
||||
{
|
||||
m_scanner_thr = n;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the scanner threshold
|
||||
*/
|
||||
size_t scanner_threshold () const
|
||||
{
|
||||
return m_scanner_thr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the fill factor
|
||||
*
|
||||
* The fill factor determines how many new entries will be collected for a band.
|
||||
* A fill factor of 2 means that the number of elements in the band will be
|
||||
* doubled after elements outside of the band have been removed.
|
||||
* The default fill factor is 2.
|
||||
*/
|
||||
void set_fill_factor (double ff)
|
||||
{
|
||||
m_fill_factor = ff;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the fill factor
|
||||
*/
|
||||
double fill_factor () const
|
||||
{
|
||||
return m_fill_factor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reserve for n elements of Obj1 type
|
||||
*/
|
||||
void reserve1 (size_t n)
|
||||
{
|
||||
m_pp1.reserve (n);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reserve for n elements of Obj2 type
|
||||
*/
|
||||
void reserve2 (size_t n)
|
||||
{
|
||||
m_pp2.reserve (n);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clears the container
|
||||
*/
|
||||
void clear ()
|
||||
{
|
||||
m_pp1.clear ();
|
||||
m_pp2.clear ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts a new object of type Obj1 into the scanner
|
||||
*
|
||||
* The object's pointer is stored, so the object must remain valid until the
|
||||
* scanner does not need it any longer. An additional property can be attached to
|
||||
* the object which will be stored along with the object.
|
||||
*/
|
||||
void insert1 (const Obj1 *obj, const Prop1 &prop)
|
||||
{
|
||||
m_pp1.push_back (std::make_pair (obj, prop));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts a new object of type Obj2 into the scanner
|
||||
*
|
||||
* The object's pointer is stored, so the object must remain valid until the
|
||||
* scanner does not need it any longer. An additional property can be attached to
|
||||
* the object which will be stored along with the object.
|
||||
*/
|
||||
void insert2 (const Obj2 *obj, const Prop2 &prop)
|
||||
{
|
||||
m_pp2.push_back (std::make_pair (obj, prop));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the interactions between the stored objects
|
||||
*
|
||||
* Two objects interact if the boxes of the objects enlarged by the given value overlap.
|
||||
* The enlargement is specified in units of width and height, i.e. half of the enlargement
|
||||
* is applied to one side before the overlap check.
|
||||
*
|
||||
* An enlargement of 1 means that boxes have to touch only in order to get an interaction.
|
||||
*
|
||||
* The box scanner will report all interactions of type Obj1 and Obj2 objects to the receiver object.
|
||||
* See box_scanner_receiver2 for details about the methods that this object must provide.
|
||||
*
|
||||
* The box converter 1 must be capable of converting the Obj1 object into a box.
|
||||
* It must provide a box_type typedef. The box converter 2 must be able to convert Obj2 to
|
||||
* a box. The box type of both box converters must be identical.
|
||||
*/
|
||||
template <class Rec, class BoxConvert1, class BoxConvert2>
|
||||
void process (Rec &rec, typename BoxConvert1::box_type::coord_type enl, const BoxConvert1 &bc1 = BoxConvert1 (), const BoxConvert2 &bc2 = BoxConvert2 ())
|
||||
{
|
||||
typedef typename BoxConvert1::box_type box_type; // must be same as BoxConvert2::box_type
|
||||
typedef typename box_type::coord_type coord_type;
|
||||
typedef bs_side_compare_func<BoxConvert1, Obj1, Prop1, box_bottom<Box> > bottom_side_compare_func1;
|
||||
typedef bs_side_compare_func<BoxConvert1, Obj1, Prop1, box_left<Box> > left_side_compare_func1;
|
||||
typedef bs_side_compare_vs_const_func<BoxConvert1, Obj1, Prop1, box_top<Box> > below_func1;
|
||||
typedef bs_side_compare_vs_const_func<BoxConvert1, Obj1, Prop1, box_right<Box> > left_func1;
|
||||
typedef bs_side_compare_func<BoxConvert2, Obj2, Prop2, box_bottom<Box> > bottom_side_compare_func2;
|
||||
typedef bs_side_compare_func<BoxConvert2, Obj2, Prop2, box_left<Box> > left_side_compare_func2;
|
||||
typedef bs_side_compare_vs_const_func<BoxConvert2, Obj2, Prop2, box_top<Box> > below_func2;
|
||||
typedef bs_side_compare_vs_const_func<BoxConvert2, Obj2, Prop2, box_right<Box> > left_func2;
|
||||
|
||||
if (m_pp1.empty () || m_pp2.empty ()) {
|
||||
|
||||
// trivial case
|
||||
|
||||
for (iterator_type1 i = m_pp1.begin (); i != m_pp1.end (); ++i) {
|
||||
rec.finish1 (i->first, i->second);
|
||||
}
|
||||
for (iterator_type2 i = m_pp2.begin (); i != m_pp2.end (); ++i) {
|
||||
rec.finish2 (i->first, i->second);
|
||||
}
|
||||
|
||||
} else if (m_pp1.size () + m_pp2.size () <= m_scanner_thr) {
|
||||
|
||||
// below m_scanner_thr elements use the brute force approach which is faster in that case
|
||||
|
||||
for (iterator_type1 i = m_pp1.begin (); i != m_pp1.end (); ++i) {
|
||||
for (iterator_type2 j = m_pp2.begin (); j != m_pp2.end (); ++j) {
|
||||
if (bs_boxes_overlap (bc1 (*i->first), bc2 (*j->first), enl)) {
|
||||
rec.add (i->first, i->second, j->first, j->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (iterator_type1 i = m_pp1.begin (); i != m_pp1.end (); ++i) {
|
||||
rec.finish1 (i->first, i->second);
|
||||
}
|
||||
for (iterator_type2 i = m_pp2.begin (); i != m_pp2.end (); ++i) {
|
||||
rec.finish2 (i->first, i->second);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
std::set<std::pair<const Obj1 *, const Obj2 *> > seen1;
|
||||
std::set<std::pair<const Obj2 *, const Obj1 *> > seen2;
|
||||
|
||||
std::sort (m_pp1.begin (), m_pp1.end (), bottom_side_compare_func1 (bc1));
|
||||
std::sort (m_pp2.begin (), m_pp2.end (), bottom_side_compare_func2 (bc2));
|
||||
|
||||
coord_type y = std::min (bc1 (*m_pp1.front ().first).bottom (), bc2 (*m_pp2.front ().first).bottom ());
|
||||
|
||||
iterator_type1 current1 = m_pp1.begin ();
|
||||
iterator_type1 future1 = m_pp1.begin ();
|
||||
iterator_type2 current2 = m_pp2.begin ();
|
||||
iterator_type2 future2 = m_pp2.begin ();
|
||||
|
||||
std::auto_ptr<tl::RelativeProgress> progress (0);
|
||||
if (m_report_progress) {
|
||||
if (m_progress_desc.empty ()) {
|
||||
progress.reset (new tl::RelativeProgress (tl::to_string (tr ("Processing")), m_pp1.size () + m_pp2.size (), 1000));
|
||||
} else {
|
||||
progress.reset (new tl::RelativeProgress (m_progress_desc, m_pp1.size () + m_pp2.size (), 1000));
|
||||
}
|
||||
}
|
||||
|
||||
while (future1 != m_pp1.end () || future2 != m_pp2.end ()) {
|
||||
|
||||
iterator_type1 cc1 = current1;
|
||||
iterator_type2 cc2 = current2;
|
||||
current1 = std::partition (current1, future1, below_func1 (bc1, y + 1 - enl));
|
||||
current2 = std::partition (current2, future2, below_func2 (bc2, y + 1 - enl));
|
||||
|
||||
while (cc1 != current1) {
|
||||
rec.finish1 (cc1->first, cc1->second);
|
||||
typename std::set<std::pair<const Obj1 *, const Obj2 *> >::iterator s;
|
||||
s = seen1.lower_bound (std::make_pair (cc1->first, (const Obj2 *)0));
|
||||
while (s != seen1.end () && s->first == cc1->first) {
|
||||
seen1.erase (s++);
|
||||
}
|
||||
++cc1;
|
||||
}
|
||||
|
||||
while (cc2 != current2) {
|
||||
rec.finish2 (cc2->first, cc2->second);
|
||||
typename std::set<std::pair<const Obj2 *, const Obj1 *> >::iterator s;
|
||||
s = seen2.lower_bound (std::make_pair (cc2->first, (const Obj1 *)0));
|
||||
while (s != seen2.end () && s->first == cc2->first) {
|
||||
seen2.erase (s++);
|
||||
}
|
||||
++cc2;
|
||||
}
|
||||
|
||||
// add at least the required items per band
|
||||
size_t min_band_size = size_t ((future1 - current1) * m_fill_factor) + size_t ((future2 - current2) * m_fill_factor);
|
||||
coord_type yy = y;
|
||||
do {
|
||||
if (future1 != m_pp1.end () && future2 != m_pp2.end ()) {
|
||||
yy = std::min (bc1 (*future1->first).bottom (), bc2 (*future2->first).bottom ());
|
||||
} else if (future1 != m_pp1.end ()) {
|
||||
yy = bc1 (*future1->first).bottom ();
|
||||
} else {
|
||||
yy = bc2 (*future2->first).bottom ();
|
||||
}
|
||||
while (future1 != m_pp1.end () && bc1 (*future1->first).bottom () == yy) {
|
||||
++future1;
|
||||
}
|
||||
while (future2 != m_pp2.end () && bc2 (*future2->first).bottom () == yy) {
|
||||
++future2;
|
||||
}
|
||||
} while ((future1 != m_pp1.end () || future2 != m_pp2.end ()) && size_t (future1 - current1) + size_t (future2 - current2) < min_band_size);
|
||||
|
||||
if (current1 != future1 && current2 != future2) {
|
||||
|
||||
std::sort (current1, future1, left_side_compare_func1 (bc1));
|
||||
std::sort (current2, future2, left_side_compare_func2 (bc2));
|
||||
|
||||
iterator_type1 c1 = current1;
|
||||
iterator_type1 f1 = current1;
|
||||
iterator_type2 c2 = current2;
|
||||
iterator_type2 f2 = current2;
|
||||
|
||||
coord_type x = std::min (bc1 (*c1->first).left (), bc2 (*c2->first).left ());
|
||||
|
||||
while (f1 != future1 || f2 != future2) {
|
||||
|
||||
c1 = std::partition (c1, f1, left_func1 (bc1, x + 1 - enl));
|
||||
c2 = std::partition (c2, f2, left_func2 (bc2, x + 1 - enl));
|
||||
|
||||
// add at least the required items per band
|
||||
size_t min_box_size = size_t ((f1 - c1) * m_fill_factor) + size_t ((f2 - c2) * m_fill_factor);
|
||||
coord_type xx = x;
|
||||
do {
|
||||
if (f1 != future1 && f2 != future2) {
|
||||
xx = std::min (bc1 (*f1->first).left (), bc2 (*f2->first).left ());
|
||||
} else if (f1 != future1) {
|
||||
xx = bc1 (*f1->first).left ();
|
||||
} else if (f2 != future2) {
|
||||
xx = bc2 (*f2->first).left ();
|
||||
}
|
||||
while (f1 != future1 && bc1 (*f1->first).left () == xx) {
|
||||
++f1;
|
||||
}
|
||||
while (f2 != future2 && bc2 (*f2->first).left () == xx) {
|
||||
++f2;
|
||||
}
|
||||
} while ((f1 != future1 || f2 != future2) && size_t (f1 - c1) + size_t (f2 - c2) < min_box_size);
|
||||
|
||||
if (c1 != f1 && c2 != f2) {
|
||||
for (iterator_type1 i = c1; i != f1; ++i) {
|
||||
for (iterator_type2 j = c2; j < f2; ++j) {
|
||||
if (bs_boxes_overlap (bc1 (*i->first), bc2 (*j->first), enl)) {
|
||||
if (seen1.insert (std::make_pair (i->first, j->first)).second) {
|
||||
seen2.insert (std::make_pair (j->first, i->first));
|
||||
rec.add (i->first, i->second, j->first, j->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
x = xx;
|
||||
|
||||
if (m_report_progress) {
|
||||
progress->set (std::min (f1 - m_pp1.begin (), f2 - m_pp2.begin ()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
y = yy;
|
||||
|
||||
}
|
||||
|
||||
while (current1 != m_pp1.end ()) {
|
||||
rec.finish1 (current1->first, current1->second);
|
||||
++current1;
|
||||
}
|
||||
while (current2 != m_pp2.end ()) {
|
||||
rec.finish2 (current2->first, current2->second);
|
||||
++current2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
container_type1 m_pp1;
|
||||
container_type2 m_pp2;
|
||||
double m_fill_factor;
|
||||
size_t m_scanner_thr;
|
||||
bool m_report_progress;
|
||||
std::string m_progress_desc;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A cluster template that stores properties
|
||||
*
|
||||
|
|
|
|||
|
|
@ -56,6 +56,37 @@ struct BoxScannerTestRecorder2
|
|||
std::set<std::pair<size_t, size_t> > interactions;
|
||||
};
|
||||
|
||||
struct BoxScannerTestRecorderTwo
|
||||
{
|
||||
void finish1 (const db::Box * /*box*/, size_t p) {
|
||||
str += "<" + tl::to_string (p) + ">";
|
||||
}
|
||||
|
||||
void finish2 (const db::SimplePolygon * /*poly*/, int p) {
|
||||
str += "<" + tl::to_string (p) + ">";
|
||||
}
|
||||
|
||||
void add (const db::Box * /*b1*/, size_t p1, const db::SimplePolygon * /*b2*/, int p2)
|
||||
{
|
||||
str += "(" + tl::to_string (p1) + "-" + tl::to_string (p2) + ")";
|
||||
}
|
||||
|
||||
std::string str;
|
||||
};
|
||||
|
||||
struct BoxScannerTestRecorder2Two
|
||||
{
|
||||
void finish1 (const db::Box *, size_t) { }
|
||||
void finish2 (const db::SimplePolygon *, int) { }
|
||||
|
||||
void add (const db::Box * /*b1*/, size_t p1, const db::SimplePolygon * /*b2*/, int p2)
|
||||
{
|
||||
interactions.insert (std::make_pair (p1, p2));
|
||||
}
|
||||
|
||||
std::set<std::pair<size_t, int> > interactions;
|
||||
};
|
||||
|
||||
TEST(1)
|
||||
{
|
||||
db::box_scanner<db::Box, size_t> bs;
|
||||
|
|
@ -787,3 +818,219 @@ TEST(100)
|
|||
|
||||
}
|
||||
|
||||
|
||||
TEST(two_1)
|
||||
{
|
||||
db::box_scanner2<db::Box, size_t, db::SimplePolygon, int> bs;
|
||||
|
||||
std::vector<db::Box> bb;
|
||||
std::vector<db::SimplePolygon> bb2;
|
||||
bb.push_back (db::Box (0, 210, 200, 310));
|
||||
bb.push_back (db::Box (10, 220, 210, 320));
|
||||
bb.push_back (db::Box (0, 0, 100, 100));
|
||||
bb.push_back (db::Box (50, 50, 150, 150));
|
||||
bb.push_back (db::Box (10, 10, 110, 110));
|
||||
bb.push_back (db::Box (100, 10, 200, 110));
|
||||
|
||||
for (std::vector<db::Box>::const_iterator b = bb.begin (); b != bb.end (); ++b) {
|
||||
bb2.push_back (db::SimplePolygon (*b));
|
||||
}
|
||||
|
||||
for (std::vector<db::Box>::const_iterator b = bb.begin (); b != bb.end (); ++b) {
|
||||
bs.insert1 (&*b, b - bb.begin ());
|
||||
}
|
||||
for (std::vector<db::SimplePolygon>::const_iterator b = bb2.begin (); b != bb2.end (); ++b) {
|
||||
bs.insert2 (&*b, int (b - bb2.begin ()) + 10);
|
||||
}
|
||||
|
||||
BoxScannerTestRecorderTwo tr;
|
||||
bs.set_fill_factor (0.0);
|
||||
db::box_convert<db::Box> bc1;
|
||||
db::box_convert<db::SimplePolygon> bc2;
|
||||
bs.set_scanner_threshold (0);
|
||||
bs.process (tr, 1, bc1, bc2);
|
||||
EXPECT_EQ (tr.str, "(2-12)(2-14)(4-12)(4-14)(2-15)(4-15)(5-12)(5-14)(5-15)(2-13)(4-13)(3-12)(3-14)(3-13)(3-15)(5-13)(0-10)<2><5><4><3><12><15><14><13>(0-11)(1-10)(1-11)<0><1><10><11>");
|
||||
}
|
||||
|
||||
TEST(two_1a)
|
||||
{
|
||||
db::box_scanner2<db::Box, size_t, db::SimplePolygon, int> bs;
|
||||
|
||||
std::vector<db::Box> bb;
|
||||
bb.push_back (db::Box (0, 210, 200, 310));
|
||||
//bb.push_back (db::Box (10, 220, 210, 320));
|
||||
//bb.push_back (db::Box (0, 0, 100, 100));
|
||||
bb.push_back (db::Box (50, 50, 150, 150));
|
||||
bb.push_back (db::Box (10, 10, 110, 110));
|
||||
//bb.push_back (db::Box (100, 10, 200, 110));
|
||||
|
||||
std::vector<db::SimplePolygon> bb2;
|
||||
//bb2.push_back (db::SimplePolygon (db::Box (0, 210, 200, 310)));
|
||||
bb2.push_back (db::SimplePolygon (db::Box (10, 220, 210, 320)));
|
||||
bb2.push_back (db::SimplePolygon (db::Box (0, 0, 100, 100)));
|
||||
//bb2.push_back (db::SimplePolygon (db::Box (50, 50, 150, 150)));
|
||||
//bb2.push_back (db::SimplePolygon (db::Box (10, 10, 110, 110)));
|
||||
bb2.push_back (db::SimplePolygon (db::Box (100, 10, 200, 110)));
|
||||
|
||||
for (std::vector<db::Box>::const_iterator b = bb.begin (); b != bb.end (); ++b) {
|
||||
bs.insert1 (&*b, b - bb.begin ());
|
||||
}
|
||||
for (std::vector<db::SimplePolygon>::const_iterator b = bb2.begin (); b != bb2.end (); ++b) {
|
||||
bs.insert2 (&*b, int (b - bb2.begin ()) + 10);
|
||||
}
|
||||
|
||||
BoxScannerTestRecorderTwo tr;
|
||||
bs.set_fill_factor (0.0);
|
||||
db::box_convert<db::Box> bc1;
|
||||
db::box_convert<db::SimplePolygon> bc2;
|
||||
bs.set_scanner_threshold (0);
|
||||
bs.process (tr, 1, bc1, bc2);
|
||||
EXPECT_EQ (tr.str, "(2-11)(2-12)(1-11)(1-12)<1><2><11><12>(0-10)<0><10>");
|
||||
}
|
||||
|
||||
TEST(two_1b)
|
||||
{
|
||||
db::box_scanner2<db::Box, size_t, db::SimplePolygon, int> bs;
|
||||
|
||||
std::vector<db::Box> bb;
|
||||
//bb.push_back (db::Box (0, 210, 200, 310));
|
||||
bb.push_back (db::Box (10, 220, 210, 320));
|
||||
bb.push_back (db::Box (0, 0, 100, 100));
|
||||
//bb.push_back (db::Box (50, 50, 150, 150));
|
||||
//bb.push_back (db::Box (10, 10, 110, 110));
|
||||
bb.push_back (db::Box (100, 10, 200, 110));
|
||||
|
||||
std::vector<db::SimplePolygon> bb2;
|
||||
bb2.push_back (db::SimplePolygon (db::Box (0, 210, 200, 310)));
|
||||
//bb2.push_back (db::SimplePolygon (db::Box (10, 220, 210, 320)));
|
||||
//bb2.push_back (db::SimplePolygon (db::Box (0, 0, 100, 100)));
|
||||
bb2.push_back (db::SimplePolygon (db::Box (50, 50, 150, 150)));
|
||||
bb2.push_back (db::SimplePolygon (db::Box (10, 10, 110, 110)));
|
||||
//bb2.push_back (db::SimplePolygon (db::Box (100, 10, 200, 110)));
|
||||
|
||||
for (std::vector<db::Box>::const_iterator b = bb.begin (); b != bb.end (); ++b) {
|
||||
bs.insert1 (&*b, b - bb.begin ());
|
||||
}
|
||||
for (std::vector<db::SimplePolygon>::const_iterator b = bb2.begin (); b != bb2.end (); ++b) {
|
||||
bs.insert2 (&*b, int (b - bb2.begin ()) + 10);
|
||||
}
|
||||
|
||||
BoxScannerTestRecorderTwo tr;
|
||||
bs.set_fill_factor (0.0);
|
||||
db::box_convert<db::Box> bc1;
|
||||
db::box_convert<db::SimplePolygon> bc2;
|
||||
bs.set_scanner_threshold (0);
|
||||
bs.process (tr, 1, bc1, bc2);
|
||||
EXPECT_EQ (tr.str, "(1-12)(2-12)(1-11)(2-11)<1><2><11><12>(0-10)<0><10>");
|
||||
}
|
||||
|
||||
void run_test2_two (tl::TestBase *_this, size_t n, double ff, db::Coord spread, bool touch = true)
|
||||
{
|
||||
std::vector<db::Box> bb;
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
db::Coord x = rand () % spread;
|
||||
db::Coord y = rand () % spread;
|
||||
bb.push_back (db::Box (x, y, x + 100, y + 100));
|
||||
// std::cout << "Box 1" << bb.back ().to_string () << std::endl;
|
||||
}
|
||||
|
||||
std::vector<db::SimplePolygon> bb2;
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
db::Coord x = rand () % spread;
|
||||
db::Coord y = rand () % spread;
|
||||
bb2.push_back (db::SimplePolygon (db::Box (x, y, x + 100, y + 100)));
|
||||
// std::cout << "Polygon 2" << bb2.back ().to_string () << std::endl;
|
||||
}
|
||||
|
||||
db::box_scanner2<db::Box, size_t, db::SimplePolygon, int> bs;
|
||||
for (std::vector<db::Box>::const_iterator b = bb.begin (); b != bb.end (); ++b) {
|
||||
bs.insert1 (&*b, b - bb.begin ());
|
||||
}
|
||||
for (std::vector<db::SimplePolygon>::const_iterator b2 = bb2.begin (); b2 != bb2.end (); ++b2) {
|
||||
bs.insert2 (&*b2, int (b2 - bb2.begin ()));
|
||||
}
|
||||
|
||||
BoxScannerTestRecorder2Two tr;
|
||||
bs.set_fill_factor (ff);
|
||||
db::box_convert<db::Box> bc1;
|
||||
db::box_convert<db::SimplePolygon> bc2;
|
||||
{
|
||||
tl::SelfTimer timer ("box-scanner");
|
||||
bs.set_scanner_threshold (0);
|
||||
bs.process (tr, touch ? 1 : 0, bc1, bc2);
|
||||
}
|
||||
|
||||
std::set<std::pair<size_t, int> > interactions;
|
||||
{
|
||||
tl::SelfTimer timer ("brute-force");
|
||||
for (size_t i = 0; i < bb.size (); ++i) {
|
||||
for (size_t j = 0; j < bb2.size (); ++j) {
|
||||
if ((touch && bb[i].touches (bb2[j].box ())) || (!touch && bb[i].overlaps (bb2[j].box ()))) {
|
||||
interactions.insert (std::make_pair (i, int (j)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (interactions != tr.interactions) {
|
||||
tl::info << "Interactions 1-2 in 'brute force' but not in 'box-scanner':";
|
||||
for (std::set<std::pair<size_t, int> >::const_iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
if (tr.interactions.find (*i) == tr.interactions.end ()) {
|
||||
tl::info << " " << i->first << "-" << i->second;
|
||||
}
|
||||
}
|
||||
tl::info << "Interactions 1-2 in 'box-scanner' but not in 'brute force':";
|
||||
for (std::set<std::pair<size_t, int> >::const_iterator i = tr.interactions.begin (); i != tr.interactions.end (); ++i) {
|
||||
if (interactions.find (*i) == interactions.end ()) {
|
||||
tl::info << " " << i->first << "-" << i->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPECT_EQ (interactions == tr.interactions, true);
|
||||
|
||||
}
|
||||
|
||||
TEST(two_2a)
|
||||
{
|
||||
run_test2_two(_this, 10, 0.0, 1000);
|
||||
}
|
||||
|
||||
TEST(two_2b)
|
||||
{
|
||||
run_test2_two(_this, 10, 0.0, 100);
|
||||
}
|
||||
|
||||
TEST(two_2c)
|
||||
{
|
||||
run_test2_two(_this, 10, 0.0, 10);
|
||||
}
|
||||
|
||||
TEST(two_2d)
|
||||
{
|
||||
run_test2_two(_this, 1000, 0.0, 1000);
|
||||
}
|
||||
|
||||
TEST(two_2e)
|
||||
{
|
||||
run_test2_two(_this, 1000, 2, 1000);
|
||||
}
|
||||
|
||||
TEST(two_2f)
|
||||
{
|
||||
run_test2_two(_this, 1000, 2, 1000, false);
|
||||
}
|
||||
|
||||
TEST(two_2g)
|
||||
{
|
||||
run_test2_two(_this, 1000, 2, 500);
|
||||
}
|
||||
|
||||
TEST(two_2h)
|
||||
{
|
||||
run_test2_two(_this, 1000, 2, 100);
|
||||
}
|
||||
|
||||
TEST(two_2i)
|
||||
{
|
||||
run_test2_two(_this, 10000, 2, 10000);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue