WIP: new classes for hier network processor.

This commit is contained in:
Matthias Koefferlein 2018-12-02 01:30:56 +01:00
parent 3609bdda81
commit 59d1aead59
5 changed files with 393 additions and 45 deletions

View File

@ -129,6 +129,14 @@ struct box_scanner_receiver
* definition.
*/
void add (const Obj * /*o1*/, const Prop & /*p1*/, const Obj * /*o2*/, const Prop & /*p2*/) { }
/**
* @brief Indicates whether the scanner may stop
*
* The scanner will stop if this method returns true. This feature can be used to
* terminate the scan process early if the outcome is known.
*/
bool stop () const { return false; }
};
/**
@ -250,9 +258,13 @@ public:
*
* The box converter must be capable of converting the Obj object into a box.
* It must provide a box_type typedef.
*
* The scanner process can be terminated early by making the receiver's
* stop() method return true. In this case, this method will return false.
* Otherwise it will return true.
*/
template <class Rec, class BoxConvert>
void process (Rec &rec, typename BoxConvert::box_type::coord_type enl, const BoxConvert &bc = BoxConvert ())
bool process (Rec &rec, typename BoxConvert::box_type::coord_type enl, const BoxConvert &bc = BoxConvert ())
{
typedef typename BoxConvert::box_type box_type;
typedef typename box_type::coord_type coord_type;
@ -269,6 +281,9 @@ public:
for (iterator_type j = i + 1; j != m_pp.end (); ++j) {
if (bs_boxes_overlap (bc (*i->first), bc (*j->first), enl)) {
rec.add (i->first, i->second, j->first, j->second);
if (rec.stop ()) {
return false;
}
}
}
}
@ -355,6 +370,9 @@ public:
if (seen.insert (std::make_pair (i->first, j->first)).second) {
seen.insert (std::make_pair (j->first, i->first));
rec.add (i->first, i->second, j->first, j->second);
if (rec.stop ()) {
return false;
}
}
}
}
@ -379,6 +397,8 @@ public:
}
return true;
}
private:
@ -421,6 +441,14 @@ struct box_scanner_receiver2
* definition.
*/
void add (const Obj1 * /*o1*/, const Prop1 & /*p1*/, const Obj2 * /*o2*/, const Prop2 & /*p2*/) { }
/**
* @brief Indicates whether the scanner may stop
*
* The scanner will stop if this method returns true. This feature can be used to
* terminate the scan process early if the outcome is known.
*/
bool stop () const { return false; }
};
/**
@ -558,9 +586,13 @@ public:
* 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.
*
* The scanner process can be terminated early by making the receiver's
* stop() method return true. In this case, this method will return false.
* Otherwise it will return true.
*/
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 ())
bool 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;
@ -592,6 +624,9 @@ public:
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);
if (rec.stop ()) {
return false;
}
}
}
}
@ -716,6 +751,9 @@ public:
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);
if (rec.stop ()) {
return false;
}
}
}
}
@ -747,6 +785,8 @@ public:
}
return true;
}
private:

View File

@ -27,7 +27,7 @@
#include "dbInstElement.h"
#include "dbPolygon.h"
#include "dbPolygonTools.h"
#include "dbBoxConvert.h"
#include "dbBoxScanner.h"
#include <vector>
#include <map>
@ -95,62 +95,193 @@ Connectivity::end_connected (unsigned int layer)
}
}
template <class Trans>
static bool
interaction_test (const db::PolygonRef &a, const db::PolygonRef &b)
interaction_test (const db::PolygonRef &a, const db::PolygonRef &b, const Trans &trans)
{
// TODO: this could be part of db::interact (including transformation)
if (a.obj ().is_box () && b.obj ().is_box ()) {
return db::interact (a.obj ().box ().transformed (b.trans ().inverted () * a.trans ()), b.obj ().box ());
return db::interact (a.obj ().box ().transformed (b.trans ().inverted () * a.trans ()), b.obj ().box ().transformed (trans));
} else {
return db::interact (a.obj ().transformed (b.trans ().inverted () * a.trans ()), b.obj ());
return db::interact (a.obj ().transformed (b.trans ().inverted () * a.trans ()), b.obj ().transformed (trans));
}
}
template <class T>
bool Connectivity::interacts (const T &a, unsigned int la, T &b, unsigned int lb) const
template <class T, class Trans>
bool Connectivity::interacts (const T &a, unsigned int la, const T &b, unsigned int lb, const Trans &trans) const
{
std::map<unsigned int, layers_type>::const_iterator i = m_connected.find (la);
if (i == m_connected.end () || i->second.find (lb) == i->second.end ()) {
return false;
} else {
return interaction_test (a, b);
return interaction_test (a, b, trans);
}
}
// explicit instantiations
template DB_PUBLIC bool Connectivity::interacts<db::PolygonRef> (const db::PolygonRef &a, unsigned int la, db::PolygonRef &b, unsigned int lb) const;
template DB_PUBLIC bool Connectivity::interacts<db::PolygonRef> (const db::PolygonRef &a, unsigned int la, const db::PolygonRef &b, unsigned int lb, const db::UnitTrans &trans) const;
template DB_PUBLIC bool Connectivity::interacts<db::PolygonRef> (const db::PolygonRef &a, unsigned int la, const db::PolygonRef &b, unsigned int lb, const db::ICplxTrans &trans) const;
// ------------------------------------------------------------------------------
// ...
// local_cluster implementation
template <class T>
local_cluster<T>::local_cluster ()
: m_id (0), m_needs_update (false)
{
// .. nothing yet ..
}
template <class T>
void
local_cluster<T>::add (const T &s, unsigned int la)
{
m_shapes[la].insert (s);
m_needs_update = true;
}
template <class T>
void
local_cluster<T>::join_with (const local_cluster<T> &other)
{
for (typename std::map<unsigned int, tree_type>::const_iterator s = other.m_shapes.begin (); s != other.m_shapes.end (); ++s) {
tree_type &other_tree = m_shapes[s->first];
other_tree.insert (s->second.begin (), s->second.end ());
}
m_needs_update = true;
}
template <class T>
void
local_cluster<T>::ensure_sorted ()
{
if (! m_needs_update) {
return;
}
// sort the shape trees
for (typename std::map<unsigned int, tree_type>::iterator s = m_shapes.begin (); s != m_shapes.end (); ++s) {
s->second.sort (db::box_convert<T> ());
}
// recompute bounding box
m_bbox = box_type ();
db::box_convert<T> bc;
for (typename std::map<unsigned int, tree_type>::const_iterator s = m_shapes.begin (); s != m_shapes.end (); ++s) {
for (typename tree_type::const_iterator i = s->second.begin (); i != s->second.end (); ++i) {
m_bbox += bc (*i);
}
}
m_needs_update = false;
}
namespace
{
template <class T>
struct interaction_receiver
: public box_scanner_receiver2<T, unsigned int, T, unsigned int>
{
public:
typedef typename local_cluster<T>::box_type box_type;
interaction_receiver (const Connectivity &conn, const db::ICplxTrans &trans)
: mp_conn (&conn), m_any (false), m_trans (trans)
{
// .. nothing yet ..
}
void add (const T *s1, unsigned int l1, const T *s2, unsigned int l2)
{
if (mp_conn->interacts (*s1, l1, *s2, l2, m_trans)) {
m_any = true;
}
}
bool stop () const
{
return m_any;
}
private:
const Connectivity *mp_conn;
bool m_any;
db::ICplxTrans m_trans;
};
template <class T, class Trans>
struct transformed_box
{
typedef db::box_convert<T> base_bc;
typedef typename T::box_type box_type;
transformed_box (const Trans &trans)
: m_trans (trans)
{
// .. nothing yet ..
}
box_type operator() (const T &t) const
{
return m_bc (t).transformed (m_trans);
}
private:
base_bc m_bc;
Trans m_trans;
};
}
template <class T>
bool
local_cluster<T>::interacts (const local_cluster<T> &other, const db::ICplxTrans &trans, const Connectivity &conn) const
{
const_cast<local_cluster<T> *> (this)->ensure_sorted ();
if (! other.bbox ().overlaps (bbox ())) {
return false;
}
box_type common = other.bbox () & bbox ();
db::box_scanner2<T, unsigned int, T, unsigned int> scanner;
transformed_box <T, db::ICplxTrans> bc_t (trans);
db::box_convert<T> bc;
bool any = false;
for (typename std::map<unsigned int, tree_type>::const_iterator s = m_shapes.begin (); s != m_shapes.end (); ++s) {
for (typename tree_type::overlapping_iterator i = s->second.begin_overlapping (common, bc); ! i.at_end (); ++i) {
scanner.insert1 (i.operator-> (), s->first);
any = true;
}
}
if (! any) {
return false;
}
for (typename std::map<unsigned int, tree_type>::const_iterator s = other.m_shapes.begin (); s != other.m_shapes.end (); ++s) {
for (typename tree_type::overlapping_iterator i = s->second.begin_overlapping (common.transformed (trans.inverted ()), bc); ! i.at_end (); ++i) {
scanner.insert2 (i.operator-> (), s->first);
}
}
interaction_receiver<T> rec (conn, trans);
return ! scanner.process (rec, 0, bc, bc_t);
}
// explicit instantiations
template class DB_PUBLIC local_cluster<db::PolygonRef>;
// ------------------------------------------------------------------------------
// local_cluster implementation
#if 0
/**
* @brief Represents a cluster of shapes
*
* A cluster of shapes is a set of shapes which are connected in terms
* of a given connectivity.
*/
class LocalCluster
{
public:
typedef size_t id_type;
LocalCluster ();
void connect (const db::Shape &a, unsigned int la, const db::Shape &b, unsigned int lb);
id_type id () const;
// @@@ Trans is the transformation of the cluster to the shape (instance transformation)
void interacts (const db::Shape &s, unsigned int ls, const db::ICplxTrans &trans, const Connectivity &conn);
const db::Box &bbox () const;
private:
friend class LocalClusters;
void set_id (id_type id);
};
/**
* @brief Represents a collection of clusters in a cell
*

View File

@ -25,6 +25,9 @@
#define HDR_dbHierNetworkProcessor
#include "dbCommon.h"
#include "dbTrans.h"
#include "dbBoxConvert.h"
#include "dbBoxTree.h"
#include <map>
#include <set>
@ -81,17 +84,112 @@ public:
*/
layer_iterator end_connected (unsigned int layer);
/**
* @brief Returns true, if the given shapes on the given layers interact
*
* This method accepts a transformation. This transformation is applied
* to the b shape before checking against a.
*/
template <class T, class Trans>
bool interacts (const T &a, unsigned int la, const T &b, unsigned int lb, const Trans &trans) const;
/**
* @brief Returns true, if the given shapes on the given layers interact
*/
template <class T>
bool interacts (const T &a, unsigned int la, T &b, unsigned int lb) const;
bool interacts (const T &a, unsigned int la, const T &b, unsigned int lb) const
{
return interacts (a, la, b, lb, UnitTrans ());
}
private:
layers_type m_all_layers;
std::map<unsigned int, layers_type> m_connected;
};
/**
* @brief Represents a cluster of shapes
*
* A cluster of shapes is a set of shapes of type T which are connected in terms
* of a given connectivity. The shapes will still be organised in layers.
*/
template <class T>
class DB_PUBLIC local_cluster
{
public:
typedef size_t id_type;
typedef typename T::box_type box_type;
/**
* @brief Creates an empty cluster
*/
local_cluster ();
/**
* @brief Adds a shape with the given layer to the cluster
*/
void add (const T &s, unsigned int la);
/**
* @brief Joins this cluster with the other one
*
* This will copy all shapes from the other cluster into ourself.
*/
void join_with (const local_cluster<T> &other);
/**
* @brief Gets the cluster's ID
*
* The ID is a unique identifier for the cluster. An ID value of 0 is reserved for
* "no cluster".
*/
id_type id () const
{
return m_id;
}
/**
* @brief Tests whether this cluster interacts with another cluster
*
* "trans" is the transformation which is applied to the other cluster before
* the test.
*/
bool interacts (const local_cluster<T> &other, const db::ICplxTrans &trans, const Connectivity &conn) const;
/**
* @brief Gets the bounding box of this cluster
*/
const box_type &bbox () const
{
const_cast<local_cluster<T> *> (this)->ensure_sorted (); // also updates bbox
return m_bbox;
}
private:
template <typename> friend class local_clusters;
template <typename> friend class interaction_receiver;
typedef db::unstable_box_tree<box_type, T, db::box_convert<T> > tree_type;
void set_id (id_type id)
{
m_id = id;
}
const T &shape (unsigned int l, size_t index) const
{
typename std::map<unsigned int, tree_type>::const_iterator s = m_shapes.find (l);
tl_assert (s != m_shapes.end ());
return s->second.objects () [index];
}
void ensure_sorted ();
id_type m_id;
bool m_needs_update;
std::map<unsigned int, tree_type> m_shapes;
box_type m_bbox;
};
}
#endif

View File

@ -35,6 +35,8 @@ struct BoxScannerTestRecorder
str += "<" + tl::to_string (p) + ">";
}
bool stop () const { return false; }
void add (const db::Box * /*b1*/, size_t p1, const db::Box * /*b2*/, size_t p2)
{
str += "(" + tl::to_string (p1) + "-" + tl::to_string (p2) + ")";
@ -43,10 +45,32 @@ struct BoxScannerTestRecorder
std::string str;
};
struct BoxScannerTestRecorderStopping
{
BoxScannerTestRecorderStopping () : do_stop (false) { }
void finish (const db::Box * /*box*/, size_t p) {
str += "<" + tl::to_string (p) + ">";
}
bool stop () const { return do_stop; }
void add (const db::Box * /*b1*/, size_t p1, const db::Box * /*b2*/, size_t p2)
{
str += "(" + tl::to_string (p1) + "-" + tl::to_string (p2) + ")";
do_stop = true;
}
std::string str;
bool do_stop;
};
struct BoxScannerTestRecorder2
{
void finish (const db::Box *, size_t) { }
bool stop () const { return false; }
void add (const db::Box * /*b1*/, size_t p1, const db::Box * /*b2*/, size_t p2)
{
interactions.insert (std::make_pair (p1, p2));
@ -66,6 +90,8 @@ struct BoxScannerTestRecorderTwo
str += "<" + tl::to_string (p) + ">";
}
bool stop () const { return false; }
void add (const db::Box * /*b1*/, size_t p1, const db::SimplePolygon * /*b2*/, int p2)
{
str += "(" + tl::to_string (p1) + "-" + tl::to_string (p2) + ")";
@ -74,11 +100,37 @@ struct BoxScannerTestRecorderTwo
std::string str;
};
struct BoxScannerTestRecorderTwoStopping
{
BoxScannerTestRecorderTwoStopping () : do_stop (false) { }
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) + ">";
}
bool stop () const { return do_stop; }
void add (const db::Box * /*b1*/, size_t p1, const db::SimplePolygon * /*b2*/, int p2)
{
str += "(" + tl::to_string (p1) + "-" + tl::to_string (p2) + ")";
do_stop = true;
}
std::string str;
bool do_stop;
};
struct BoxScannerTestRecorder2Two
{
void finish1 (const db::Box *, size_t) { }
void finish2 (const db::SimplePolygon *, int) { }
bool stop () const { return false; }
void add (const db::Box * /*b1*/, size_t p1, const db::SimplePolygon * /*b2*/, int p2)
{
interactions.insert (std::make_pair (p1, p2));
@ -106,8 +158,12 @@ TEST(1)
bs.set_fill_factor (0.0);
db::box_convert<db::Box> bc;
bs.set_scanner_threshold (0);
bs.process (tr, 1, bc);
EXPECT_EQ (bs.process (tr, 1, bc), true);
EXPECT_EQ (tr.str, "(4-2)(5-2)(5-4)(3-2)(3-4)(5-3)<2><5><4><3>(1-0)<0><1>");
BoxScannerTestRecorderStopping trstop;
EXPECT_EQ (bs.process (trstop, 1, bc), false);
EXPECT_EQ (trstop.str, "(4-2)");
}
TEST(1a)
@ -920,8 +976,13 @@ TEST(two_1b)
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 (bs.process (tr, 1, bc1, bc2), true);
EXPECT_EQ (tr.str, "(1-12)(2-12)(1-11)(2-11)<1><2><11><12>(0-10)<0><10>");
BoxScannerTestRecorderTwoStopping trstop;
EXPECT_EQ (bs.process (trstop, 1, bc1, bc2), false);
EXPECT_EQ (trstop.str, "(1-12)");
}
void run_test2_two (tl::TestBase *_this, size_t n, double ff, db::Coord spread, bool touch = true)

View File

@ -80,15 +80,23 @@ TEST(2_ShapeInteractions)
tl::from_string ("(0,0;0,1000;1000,1000;1000,0)", poly);
db::GenericRepository repo;
db::PolygonRef ref1 (poly, repo);
db::PolygonRef ref2 (poly.transformed (db::Trans (db::Vector (0, 10))), repo);
db::PolygonRef ref3 (poly.transformed (db::Trans (db::Vector (0, 2000))), repo);
db::ICplxTrans t2 (db::Trans (db::Vector (0, 10)));
db::PolygonRef ref2 (poly.transformed (t2), repo);
db::ICplxTrans t3 (db::Trans (db::Vector (0, 2000)));
db::PolygonRef ref3 (poly.transformed (t3), repo);
EXPECT_EQ (conn.interacts (ref1, 0, ref2, 0), true);
EXPECT_EQ (conn.interacts (ref1, 0, ref1, 0, t2), true); // t2*ref1 == ref2
EXPECT_EQ (conn.interacts (ref1, 0, ref2, 1), true);
EXPECT_EQ (conn.interacts (ref1, 0, ref1, 1, t2), true);
EXPECT_EQ (conn.interacts (ref1, 1, ref2, 0), true);
EXPECT_EQ (conn.interacts (ref1, 1, ref1, 0, t2), true);
EXPECT_EQ (conn.interacts (ref1, 0, ref3, 0), false);
EXPECT_EQ (conn.interacts (ref1, 0, ref1, 0, t3), false); // t3*ref1 == ref3
EXPECT_EQ (conn.interacts (ref1, 0, ref3, 1), false);
EXPECT_EQ (conn.interacts (ref1, 0, ref1, 1, t3), false);
EXPECT_EQ (conn.interacts (ref1, 1, ref2, 2), false);
EXPECT_EQ (conn.interacts (ref1, 1, ref1, 2, t2), false);
}
TEST(2_ShapeInteractionsRealPolygon)
@ -103,15 +111,25 @@ TEST(2_ShapeInteractionsRealPolygon)
tl::from_string ("(0,0;0,1000;500,1000;500,1500;1000,1500;1000,0)", poly);
db::GenericRepository repo;
db::PolygonRef ref1 (poly, repo);
db::PolygonRef ref2 (poly.transformed (db::Trans (db::Vector (0, 10))), repo);
db::PolygonRef ref3 (poly.transformed (db::Trans (db::Vector (0, 2000))), repo);
db::PolygonRef ref4 (poly.transformed (db::Trans (db::Vector (0, 1500))), repo);
db::ICplxTrans t2 (db::Trans (db::Vector (0, 10)));
db::PolygonRef ref2 (poly.transformed (t2), repo);
db::ICplxTrans t3 (db::Trans (db::Vector (0, 2000)));
db::PolygonRef ref3 (poly.transformed (t3), repo);
db::ICplxTrans t4 (db::Trans (db::Vector (0, 1500)));
db::PolygonRef ref4 (poly.transformed (t4), repo);
EXPECT_EQ (conn.interacts (ref1, 0, ref2, 0), true);
EXPECT_EQ (conn.interacts (ref1, 0, ref1, 0, t2), true); // t2*ref1 == ref2
EXPECT_EQ (conn.interacts (ref1, 0, ref2, 1), true);
EXPECT_EQ (conn.interacts (ref1, 0, ref1, 1, t2), true);
EXPECT_EQ (conn.interacts (ref1, 1, ref2, 0), true);
EXPECT_EQ (conn.interacts (ref1, 1, ref1, 0, t2), true);
EXPECT_EQ (conn.interacts (ref1, 0, ref3, 0), false);
EXPECT_EQ (conn.interacts (ref1, 0, ref1, 0, t3), false);
EXPECT_EQ (conn.interacts (ref1, 0, ref4, 0), true);
EXPECT_EQ (conn.interacts (ref1, 0, ref1, 0, t4), true);
EXPECT_EQ (conn.interacts (ref1, 0, ref3, 1), false);
EXPECT_EQ (conn.interacts (ref1, 0, ref1, 1, t3), false);
EXPECT_EQ (conn.interacts (ref1, 1, ref2, 2), false);
EXPECT_EQ (conn.interacts (ref1, 1, ref1, 2, t2), false);
}