WIP: Hierarchical production of error db's. Needs testing.

This commit is contained in:
Matthias Koefferlein 2019-02-11 00:11:03 +01:00
parent dd4fcd9e36
commit 2d9a3aaaa6
11 changed files with 828 additions and 499 deletions

View File

@ -463,7 +463,7 @@ DeepRegion::and_or_not_with (const DeepRegion *other, bool and_op) const
db::BoolAndOrNotLocalOperation op (and_op);
db::local_processor<db::PolygonRef> proc (const_cast<db::Layout *> (&m_deep_layer.layout ()), const_cast<db::Cell *> (&m_deep_layer.initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell ());
db::local_processor<db::PolygonRef, db::PolygonRef> proc (const_cast<db::Layout *> (&m_deep_layer.layout ()), const_cast<db::Cell *> (&m_deep_layer.initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell ());
proc.set_base_verbosity (base_verbosity ());
proc.set_threads (m_deep_layer.store ()->threads ());
proc.set_area_ratio (m_deep_layer.store ()->max_area_ratio ());

File diff suppressed because it is too large Load Diff

View File

@ -42,12 +42,12 @@
namespace db
{
template <class T> class local_processor;
template <class T> class local_processor_cell_context;
template <class T> class local_processor_contexts;
template <class TS, class TI> class local_processor;
template <class TS, class TI> class local_processor_cell_context;
template <class TS, class TI> class local_processor_contexts;
// TODO: move this somewhere else?
template <class T>
template <class TS, class TI>
class DB_PUBLIC shape_interactions
{
public:
@ -67,12 +67,15 @@ public:
return m_interactions.end ();
}
bool has_shape_id (unsigned int id) const;
void add_shape (unsigned int id, const T &shape);
void add_subject (unsigned int id, const T &shape);
bool has_intruder_shape_id (unsigned int id) const;
bool has_subject_shape_id (unsigned int id) const;
void add_intruder_shape (unsigned int id, const TI &shape);
void add_subject_shape (unsigned int id, const TS &shape);
void add_subject (unsigned int id, const TS &shape);
void add_interaction (unsigned int subject_id, unsigned int intruder_id);
const std::vector<unsigned int> &intruders_for (unsigned int subject_id) const;
const T &shape (unsigned int id) const;
const TS &subject_shape (unsigned int id) const;
const TI &intruder_shape (unsigned int id) const;
unsigned int next_id ()
{
@ -81,45 +84,46 @@ public:
private:
std::unordered_map<unsigned int, std::vector<unsigned int> > m_interactions;
std::unordered_map<unsigned int, T> m_shapes;
std::unordered_map<unsigned int, TS> m_subject_shapes;
std::unordered_map<unsigned int, TI> m_intruder_shapes;
unsigned int m_id;
};
// TODO: should be hidden (private data?)
template <class T>
template <class TS, class TI>
struct DB_PUBLIC local_processor_cell_drop
{
local_processor_cell_drop (db::local_processor_cell_context<T> *_parent_context, db::Cell *_parent, const db::ICplxTrans &_cell_inst)
local_processor_cell_drop (db::local_processor_cell_context<TS, TI> *_parent_context, db::Cell *_parent, const db::ICplxTrans &_cell_inst)
: parent_context (_parent_context), parent (_parent), cell_inst (_cell_inst)
{
// .. nothing yet ..
}
db::local_processor_cell_context<T> *parent_context;
db::local_processor_cell_context<TS, TI> *parent_context;
db::Cell *parent;
db::ICplxTrans cell_inst;
};
// TODO: should be hidden (private data?)
template <class T>
template <class TS, class TI>
class DB_PUBLIC local_processor_cell_context
{
public:
typedef std::pair<const db::Cell *, db::ICplxTrans> parent_inst_type;
typedef typename std::vector<local_processor_cell_drop<T> >::const_iterator drop_iterator;
typedef typename std::vector<local_processor_cell_drop<TS, TI> >::const_iterator drop_iterator;
local_processor_cell_context ();
local_processor_cell_context (const local_processor_cell_context &other);
void add (db::local_processor_cell_context<T> *parent_context, db::Cell *parent, const db::ICplxTrans &cell_inst);
void propagate (const std::unordered_set<T> &res);
void add (db::local_processor_cell_context<TS, TI> *parent_context, db::Cell *parent, const db::ICplxTrans &cell_inst);
void propagate (const std::unordered_set<TS> &res);
std::unordered_set<T> &propagated ()
std::unordered_set<TS> &propagated ()
{
return m_propagated;
}
const std::unordered_set<T> &propagated () const
const std::unordered_set<TS> &propagated () const
{
return m_propagated;
}
@ -147,25 +151,25 @@ public:
}
private:
std::unordered_set<T> m_propagated;
std::vector<local_processor_cell_drop<T> > m_drops;
std::unordered_set<TS> m_propagated;
std::vector<local_processor_cell_drop<TS, TI> > m_drops;
tl::Mutex m_lock;
};
template <class T>
template <class TS, class TI>
class DB_PUBLIC local_processor_cell_contexts
{
public:
typedef std::pair<std::set<CellInstArray>, std::set<T> > context_key_type;
typedef std::unordered_map<context_key_type, db::local_processor_cell_context<T> > context_map_type;
typedef std::pair<std::set<CellInstArray>, std::set<TI> > context_key_type;
typedef std::unordered_map<context_key_type, db::local_processor_cell_context<TS, TI> > context_map_type;
typedef typename context_map_type::const_iterator iterator;
local_processor_cell_contexts ();
local_processor_cell_contexts (const db::Cell *intruder_cell);
db::local_processor_cell_context<T> *find_context (const context_key_type &intruders);
db::local_processor_cell_context<T> *create (const context_key_type &intruders);
void compute_results (const local_processor_contexts<T> &contexts, db::Cell *cell, const local_operation<T> *op, unsigned int output_layer, const local_processor<T> *proc);
db::local_processor_cell_context<TS, TI> *find_context (const context_key_type &intruders);
db::local_processor_cell_context<TS, TI> *create (const context_key_type &intruders);
void compute_results (const local_processor_contexts<TS, TI> &contexts, db::Cell *cell, const local_operation<TS, TI> *op, unsigned int output_layer, const local_processor<TS, TI> *proc);
iterator begin () const
{
@ -179,14 +183,14 @@ public:
private:
const db::Cell *mp_intruder_cell;
std::unordered_map<context_key_type, db::local_processor_cell_context<T> > m_contexts;
std::unordered_map<context_key_type, db::local_processor_cell_context<TS, TI> > m_contexts;
};
template <class T>
template <class TS, class TI>
class DB_PUBLIC local_processor_contexts
{
public:
typedef std::unordered_map<db::Cell *, local_processor_cell_contexts<T> > contexts_per_cell_type;
typedef std::unordered_map<db::Cell *, local_processor_cell_contexts<TS, TI> > contexts_per_cell_type;
typedef typename contexts_per_cell_type::iterator iterator;
local_processor_contexts ()
@ -206,11 +210,11 @@ public:
m_contexts_per_cell.clear ();
}
local_processor_cell_contexts<T> &contexts_per_cell (db::Cell *subject_cell, const db::Cell *intruder_cell)
local_processor_cell_contexts<TS, TI> &contexts_per_cell (db::Cell *subject_cell, const db::Cell *intruder_cell)
{
typename contexts_per_cell_type::iterator ctx = m_contexts_per_cell.find (subject_cell);
if (ctx == m_contexts_per_cell.end ()) {
ctx = m_contexts_per_cell.insert (std::make_pair (subject_cell, local_processor_cell_contexts<T> (intruder_cell))).first;
ctx = m_contexts_per_cell.insert (std::make_pair (subject_cell, local_processor_cell_contexts<TS, TI> (intruder_cell))).first;
}
return ctx->second;
}
@ -261,27 +265,27 @@ private:
mutable tl::Mutex m_lock;
};
template <class T>
template <class TS, class TI>
class DB_PUBLIC local_processor_context_computation_task
: public tl::Task
{
public:
local_processor_context_computation_task (const local_processor<T> *proc, local_processor_contexts<T> &contexts, db::local_processor_cell_context<T> *parent_context, db::Cell *subject_parent, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, typename local_processor_cell_contexts<T>::context_key_type &intruders, db::Coord dist);
local_processor_context_computation_task (const local_processor<TS, TI> *proc, local_processor_contexts<TS, TI> &contexts, db::local_processor_cell_context<TS, TI> *parent_context, db::Cell *subject_parent, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, typename local_processor_cell_contexts<TS, TI>::context_key_type &intruders, db::Coord dist);
void perform ();
private:
const local_processor<T> *mp_proc;
local_processor_contexts<T> *mp_contexts;
db::local_processor_cell_context<T> *mp_parent_context;
const local_processor<TS, TI> *mp_proc;
local_processor_contexts<TS, TI> *mp_contexts;
db::local_processor_cell_context<TS, TI> *mp_parent_context;
db::Cell *mp_subject_parent;
db::Cell *mp_subject_cell;
db::ICplxTrans m_subject_cell_inst;
const db::Cell *mp_intruder_cell;
typename local_processor_cell_contexts<T>::context_key_type m_intruders;
typename local_processor_cell_contexts<TS, TI>::context_key_type m_intruders;
db::Coord m_dist;
};
template <class T>
template <class TS, class TI>
class DB_PUBLIC local_processor_context_computation_worker
: public tl::Worker
{
@ -294,28 +298,28 @@ public:
void perform_task (tl::Task *task)
{
static_cast<local_processor_context_computation_task<T> *> (task)->perform ();
static_cast<local_processor_context_computation_task<TS, TI> *> (task)->perform ();
}
};
template <class T>
template <class TS, class TI>
class DB_PUBLIC local_processor_result_computation_task
: public tl::Task
{
public:
local_processor_result_computation_task (const local_processor<T> *proc, local_processor_contexts<T> &contexts, db::Cell *cell, local_processor_cell_contexts<T> *cell_contexts, const local_operation<T> *op, unsigned int output_layer);
local_processor_result_computation_task (const local_processor<TS, TI> *proc, local_processor_contexts<TS, TI> &contexts, db::Cell *cell, local_processor_cell_contexts<TS, TI> *cell_contexts, const local_operation<TS, TI> *op, unsigned int output_layer);
void perform ();
private:
const local_processor<T> *mp_proc;
local_processor_contexts<T> *mp_contexts;
const local_processor<TS, TI> *mp_proc;
local_processor_contexts<TS, TI> *mp_contexts;
db::Cell *mp_cell;
local_processor_cell_contexts<T> *mp_cell_contexts;
const local_operation<T> *mp_op;
local_processor_cell_contexts<TS, TI> *mp_cell_contexts;
const local_operation<TS, TI> *mp_op;
unsigned int m_output_layer;
};
template <class T>
template <class TS, class TI>
class DB_PUBLIC local_processor_result_computation_worker
: public tl::Worker
{
@ -328,19 +332,19 @@ public:
void perform_task (tl::Task *task)
{
static_cast<local_processor_result_computation_task<T> *> (task)->perform ();
static_cast<local_processor_result_computation_task<TS, TI> *> (task)->perform ();
}
};
template <class T>
template <class TS, class TI>
class DB_PUBLIC local_processor
{
public:
local_processor (db::Layout *layout, db::Cell *top);
local_processor (db::Layout *subject_layout, db::Cell *subject_top, const db::Layout *intruder_layout, const db::Cell *intruder_cell);
void run (local_operation<T> *op, unsigned int subject_layer, unsigned int intruder_layer, unsigned int output_layer);
void compute_contexts (local_processor_contexts<T> &contexts, const local_operation<T> *op, unsigned int subject_layer, unsigned int intruder_layer) const;
void compute_results (local_processor_contexts<T> &contexts, const local_operation<T> *op, unsigned int output_layer) const;
void run (local_operation<TS, TI> *op, unsigned int subject_layer, unsigned int intruder_layer, unsigned int output_layer);
void compute_contexts (local_processor_contexts<TS, TI> &contexts, const local_operation<TS, TI> *op, unsigned int subject_layer, unsigned int intruder_layer) const;
void compute_results (local_processor_contexts<TS, TI> &contexts, const local_operation<TS, TI> *op, unsigned int output_layer) const;
void set_description (const std::string &d)
{
@ -388,8 +392,8 @@ public:
}
private:
template<typename> friend class local_processor_cell_contexts;
template<typename> friend class local_processor_context_computation_task;
template<typename, typename> friend class local_processor_cell_contexts;
template<typename, typename> friend class local_processor_context_computation_task;
db::Layout *mp_subject_layout;
const db::Layout *mp_intruder_layout;
@ -400,14 +404,14 @@ private:
size_t m_max_vertex_count;
double m_area_ratio;
int m_base_verbosity;
mutable std::auto_ptr<tl::Job<local_processor_context_computation_worker<T> > > mp_cc_job;
mutable std::auto_ptr<tl::Job<local_processor_context_computation_worker<TS, TI> > > mp_cc_job;
std::string description (const local_operation<T> *op) const;
void compute_contexts (db::local_processor_contexts<T> &contexts, db::local_processor_cell_context<T> *parent_context, db::Cell *subject_parent, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, const typename local_processor_cell_contexts<T>::context_key_type &intruders, db::Coord dist) const;
void do_compute_contexts (db::local_processor_cell_context<T> *cell_context, const db::local_processor_contexts<T> &contexts, db::local_processor_cell_context<T> *parent_context, db::Cell *subject_parent, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, const typename local_processor_cell_contexts<T>::context_key_type &intruders, db::Coord dist) const;
void issue_compute_contexts (db::local_processor_contexts<T> &contexts, db::local_processor_cell_context<T> *parent_context, db::Cell *subject_parent, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, typename local_processor_cell_contexts<T>::context_key_type &intruders, db::Coord dist) const;
void push_results (db::Cell *cell, unsigned int output_layer, const std::unordered_set<T> &result) const;
void compute_local_cell (const db::local_processor_contexts<T> &contexts, db::Cell *subject_cell, const db::Cell *intruder_cell, const local_operation<T> *op, const typename local_processor_cell_contexts<T>::context_key_type &intruders, std::unordered_set<T> &result) const;
std::string description (const local_operation<TS, TI> *op) const;
void compute_contexts (db::local_processor_contexts<TS, TI> &contexts, db::local_processor_cell_context<TS, TI> *parent_context, db::Cell *subject_parent, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, const typename local_processor_cell_contexts<TS, TI>::context_key_type &intruders, db::Coord dist) const;
void do_compute_contexts (db::local_processor_cell_context<TS, TI> *cell_context, const db::local_processor_contexts<TS, TI> &contexts, db::local_processor_cell_context<TS, TI> *parent_context, db::Cell *subject_parent, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, const typename local_processor_cell_contexts<TS, TI>::context_key_type &intruders, db::Coord dist) const;
void issue_compute_contexts (db::local_processor_contexts<TS, TI> &contexts, db::local_processor_cell_context<TS, TI> *parent_context, db::Cell *subject_parent, db::Cell *subject_cell, const db::ICplxTrans &subject_cell_inst, const db::Cell *intruder_cell, typename local_processor_cell_contexts<TS, TI>::context_key_type &intruders, db::Coord dist) const;
void push_results (db::Cell *cell, unsigned int output_layer, const std::unordered_set<TS> &result) const;
void compute_local_cell (const db::local_processor_contexts<TS, TI> &contexts, db::Cell *subject_cell, const db::Cell *intruder_cell, const local_operation<TS, TI> *op, const typename local_processor_cell_contexts<TS, TI>::context_key_type &intruders, std::unordered_set<TS> &result) const;
};
}
@ -415,8 +419,8 @@ private:
namespace tl
{
template <class T>
struct type_traits<db::local_processor<T> > : public tl::type_traits<void>
template <class TS, class TI>
struct type_traits<db::local_processor<TS, TI> > : public tl::type_traits<void>
{
// mark "LocalProcessor" as not having a default ctor and no copy ctor
typedef tl::false_tag has_default_constructor;

View File

@ -45,7 +45,7 @@ BoolAndOrNotLocalOperation::BoolAndOrNotLocalOperation (bool is_and)
// .. nothing yet ..
}
local_operation<db::PolygonRef>::on_empty_intruder_mode
local_operation<db::PolygonRef, db::PolygonRef>::on_empty_intruder_mode
BoolAndOrNotLocalOperation::on_empty_intruder_hint () const
{
return m_is_and ? local_operation::Drop : local_operation::Copy;
@ -58,22 +58,22 @@ BoolAndOrNotLocalOperation::description () const
}
void
BoolAndOrNotLocalOperation::compute_local (db::Layout *layout, const shape_interactions<db::PolygonRef> &interactions, std::unordered_set<db::PolygonRef> &result, size_t max_vertex_count, double area_ratio) const
BoolAndOrNotLocalOperation::compute_local (db::Layout *layout, const shape_interactions<db::PolygonRef, db::PolygonRef> &interactions, std::unordered_set<db::PolygonRef> &result, size_t max_vertex_count, double area_ratio) const
{
db::EdgeProcessor ep;
size_t p1 = 0, p2 = 1;
std::set<db::PolygonRef> others;
for (shape_interactions<db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (shape_interactions<db::PolygonRef>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
others.insert (interactions.shape (*j));
for (shape_interactions<db::PolygonRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (shape_interactions<db::PolygonRef, db::PolygonRef>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
others.insert (interactions.intruder_shape (*j));
}
}
for (shape_interactions<db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (shape_interactions<db::PolygonRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
const db::PolygonRef &subject = interactions.shape (i->first);
const db::PolygonRef &subject = interactions.subject_shape (i->first);
if (others.find (subject) != others.end ()) {
if (m_is_and) {
result.insert (subject);
@ -119,7 +119,7 @@ SelfOverlapMergeLocalOperation::SelfOverlapMergeLocalOperation (unsigned int wra
// .. nothing yet ..
}
void SelfOverlapMergeLocalOperation::compute_local (db::Layout *layout, const shape_interactions<db::PolygonRef> &interactions, std::unordered_set<db::PolygonRef> &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const
void SelfOverlapMergeLocalOperation::compute_local (db::Layout *layout, const shape_interactions<db::PolygonRef, db::PolygonRef> &interactions, std::unordered_set<db::PolygonRef> &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const
{
if (m_wrap_count == 0) {
return;
@ -130,23 +130,23 @@ void SelfOverlapMergeLocalOperation::compute_local (db::Layout *layout, const sh
size_t p1 = 0, p2 = 1;
std::set<unsigned int> seen;
for (shape_interactions<db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (shape_interactions<db::PolygonRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
if (seen.find (i->first) == seen.end ()) {
seen.insert (i->first);
const db::PolygonRef &subject = interactions.shape (i->first);
const db::PolygonRef &subject = interactions.subject_shape (i->first);
for (db::PolygonRef::polygon_edge_iterator e = subject.begin_edge (); ! e.at_end(); ++e) {
ep.insert (*e, p1);
}
p1 += 2;
}
for (db::shape_interactions<db::PolygonRef>::iterator2 o = i->second.begin (); o != i->second.end (); ++o) {
for (db::shape_interactions<db::PolygonRef, db::PolygonRef>::iterator2 o = i->second.begin (); o != i->second.end (); ++o) {
// don't take the same (really the same, not an identical one) shape twice - the interaction
// set does not take care to list just one copy of the same item on the intruder side.
if (seen.find (*o) == seen.end ()) {
seen.insert (*o);
const db::PolygonRef &intruder = interactions.shape (*o);
const db::PolygonRef &intruder = interactions.intruder_shape (*o);
for (db::PolygonRef::polygon_edge_iterator e = intruder.begin_edge (); ! e.at_end(); ++e) {
ep.insert (*e, p2);
}

View File

@ -36,7 +36,7 @@
namespace db
{
template <class T> class shape_interactions;
template <class TS, class TI> class shape_interactions;
/**
* @brief A base class for "local operations"
@ -49,7 +49,7 @@ template <class T> class shape_interactions;
* This class implements the actual operation. It receives a
* cluster of subject shapes vs. corresponding intruder shapes.
*/
template <class T>
template <class TS, class TI>
class DB_PUBLIC local_operation
{
public:
@ -89,7 +89,7 @@ public:
* @param interactions The interaction set
* @param result The container to which the results are written
*/
virtual void compute_local (db::Layout *layout, const shape_interactions<T> &interactions, std::unordered_set<T> &result, size_t max_vertex_count, double area_ratio) const = 0;
virtual void compute_local (db::Layout *layout, const shape_interactions<TS, TI> &interactions, std::unordered_set<TS> &result, size_t max_vertex_count, double area_ratio) const = 0;
/**
* @brief Indicates the desired behaviour when a shape does not have an intruder
@ -112,12 +112,12 @@ public:
* @brief Implements a boolean AND or NOT operation
*/
class DB_PUBLIC BoolAndOrNotLocalOperation
: public local_operation<db::PolygonRef>
: public local_operation<db::PolygonRef, db::PolygonRef>
{
public:
BoolAndOrNotLocalOperation (bool is_and);
virtual void compute_local (db::Layout *layout, const shape_interactions<db::PolygonRef> &interactions, std::unordered_set<db::PolygonRef> &result, size_t max_vertex_count, double area_ratio) const;
virtual void compute_local (db::Layout *layout, const shape_interactions<db::PolygonRef, db::PolygonRef> &interactions, std::unordered_set<db::PolygonRef> &result, size_t max_vertex_count, double area_ratio) const;
virtual on_empty_intruder_mode on_empty_intruder_hint () const;
virtual std::string description () const;
@ -131,12 +131,12 @@ private:
* the original shapes overlap at least "wrap_count" times.
*/
class DB_PUBLIC SelfOverlapMergeLocalOperation
: public local_operation<db::PolygonRef>
: public local_operation<db::PolygonRef, db::PolygonRef>
{
public:
SelfOverlapMergeLocalOperation (unsigned int wrap_count);
virtual void compute_local (db::Layout *layout, const shape_interactions<db::PolygonRef> &interactions, std::unordered_set<db::PolygonRef> &result, size_t max_vertex_count, double area_ratio) const;
virtual void compute_local (db::Layout *layout, const shape_interactions<db::PolygonRef, db::PolygonRef> &interactions, std::unordered_set<db::PolygonRef> &result, size_t max_vertex_count, double area_ratio) const;
virtual on_empty_intruder_mode on_empty_intruder_hint () const;
virtual std::string description () const;

View File

@ -55,15 +55,15 @@ public:
// .. nothing yet ..
}
virtual void compute_local (db::Layout *layout, const db::shape_interactions<db::PolygonRef> &interactions, std::unordered_set<db::PolygonRef> &result, size_t max_vertex_count, double area_ratio) const
virtual void compute_local (db::Layout *layout, const db::shape_interactions<db::PolygonRef, db::PolygonRef> &interactions, std::unordered_set<db::PolygonRef> &result, size_t max_vertex_count, double area_ratio) const
{
db::shape_interactions<db::PolygonRef> sized_interactions = interactions;
for (db::shape_interactions<db::PolygonRef>::iterator i = sized_interactions.begin (); i != sized_interactions.end (); ++i) {
for (db::shape_interactions<db::PolygonRef>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
const db::PolygonRef &ref = interactions.shape (*j);
db::shape_interactions<db::PolygonRef, db::PolygonRef> sized_interactions = interactions;
for (db::shape_interactions<db::PolygonRef, db::PolygonRef>::iterator i = sized_interactions.begin (); i != sized_interactions.end (); ++i) {
for (db::shape_interactions<db::PolygonRef, db::PolygonRef>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
const db::PolygonRef &ref = interactions.intruder_shape (*j);
db::Polygon poly = ref.obj ().transformed (ref.trans ());
poly.size (m_dist, m_dist);
sized_interactions.add_shape (*j, db::PolygonRef (poly, layout->shape_repository ()));
sized_interactions.add_intruder_shape (*j, db::PolygonRef (poly, layout->shape_repository ()));
}
}
BoolAndOrNotLocalOperation::compute_local (layout, sized_interactions, result, max_vertex_count, area_ratio);
@ -91,21 +91,21 @@ public:
// .. nothing yet ..
}
virtual void compute_local (db::Layout *layout, const db::shape_interactions<db::PolygonRef> &interactions, std::unordered_set<db::PolygonRef> &result, size_t max_vertex_count, double area_ratio) const
virtual void compute_local (db::Layout *layout, const db::shape_interactions<db::PolygonRef, db::PolygonRef> &interactions, std::unordered_set<db::PolygonRef> &result, size_t max_vertex_count, double area_ratio) const
{
db::shape_interactions<db::PolygonRef> sized_interactions = interactions;
for (db::shape_interactions<db::PolygonRef>::iterator i = sized_interactions.begin (); i != sized_interactions.end (); ++i) {
db::shape_interactions<db::PolygonRef, db::PolygonRef> sized_interactions = interactions;
for (db::shape_interactions<db::PolygonRef, db::PolygonRef>::iterator i = sized_interactions.begin (); i != sized_interactions.end (); ++i) {
const db::PolygonRef &ref = interactions.shape (i->first);
const db::PolygonRef &ref = interactions.subject_shape (i->first);
db::Polygon poly = ref.obj ().transformed (ref.trans ());
poly.size (m_dist / 2, m_dist / 2);
sized_interactions.add_shape (i->first, db::PolygonRef (poly, layout->shape_repository ()));
sized_interactions.add_subject_shape (i->first, db::PolygonRef (poly, layout->shape_repository ()));
for (db::shape_interactions<db::PolygonRef>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
const db::PolygonRef &ref = interactions.shape (*j);
for (db::shape_interactions<db::PolygonRef, db::PolygonRef>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
const db::PolygonRef &ref = interactions.intruder_shape (*j);
db::Polygon poly = ref.obj ().transformed (ref.trans ());
poly.size (m_dist / 2, m_dist / 2);
sized_interactions.add_shape (*j, db::PolygonRef (poly, layout->shape_repository ()));
sized_interactions.add_intruder_shape (*j, db::PolygonRef (poly, layout->shape_repository ()));
}
}
@ -140,15 +140,15 @@ static void normalize_layer (db::Layout &layout, unsigned int layer)
}
static std::string contexts_to_s (db::Layout *layout, db::local_processor_contexts<db::PolygonRef> &contexts)
static std::string contexts_to_s (db::Layout *layout, db::local_processor_contexts<db::PolygonRef, db::PolygonRef> &contexts)
{
std::string res;
for (db::Layout::top_down_const_iterator i = layout->begin_top_down (); i != layout->end_top_down(); ++i) {
db::local_processor_contexts<db::PolygonRef>::iterator cc = contexts.context_map ().find (&layout->cell (*i));
db::local_processor_contexts<db::PolygonRef, db::PolygonRef>::iterator cc = contexts.context_map ().find (&layout->cell (*i));
if (cc != contexts.context_map ().end ()) {
int index = 1;
for (db::local_processor_cell_contexts<db::PolygonRef>::iterator j = cc->second.begin (); j != cc->second.end (); ++j) {
for (db::local_processor_cell_contexts<db::PolygonRef, db::PolygonRef>::iterator j = cc->second.begin (); j != cc->second.end (); ++j) {
res += tl::sprintf ("%s[%d] %d insts, %d shapes (%d times)\n", layout->cell_name (*i), index, int (j->first.first.size ()), int (j->first.second.size ()), int (j->second.size ()));
index += 1;
}
@ -203,7 +203,7 @@ static void run_test_bool_gen (tl::TestBase *_this, const char *file, TestMode m
normalize_layer (layout_org, l2);
}
db::local_operation<db::PolygonRef> *lop = 0;
db::local_operation<db::PolygonRef, db::PolygonRef> *lop = 0;
db::BoolAndOrNotLocalOperation bool_op (mode == TMAnd || mode == TMAndSwapped);
db::SelfOverlapMergeLocalOperation self_intersect_op (2);
BoolAndOrNotWithSizedLocalOperation sized_bool_op (mode == TMAnd || mode == TMAndSwapped, dist);
@ -224,7 +224,7 @@ static void run_test_bool_gen (tl::TestBase *_this, const char *file, TestMode m
if (single) {
db::local_processor<db::PolygonRef> proc (&layout_org, &layout_org.cell (*layout_org.begin_top_down ()));
db::local_processor<db::PolygonRef, db::PolygonRef> proc (&layout_org, &layout_org.cell (*layout_org.begin_top_down ()));
proc.set_threads (nthreads);
proc.set_area_ratio (3.0);
proc.set_max_vertex_count (16);
@ -232,7 +232,7 @@ static void run_test_bool_gen (tl::TestBase *_this, const char *file, TestMode m
if (! context_doc) {
proc.run (lop, l1, l2, lout);
} else {
db::local_processor_contexts<db::PolygonRef> contexts;
db::local_processor_contexts<db::PolygonRef, db::PolygonRef> contexts;
proc.compute_contexts (contexts, lop, l1, l2);
*context_doc = contexts_to_s (&layout_org, contexts);
proc.compute_results (contexts, lop, lout);
@ -242,7 +242,7 @@ static void run_test_bool_gen (tl::TestBase *_this, const char *file, TestMode m
db::Layout layout_org2 = layout_org;
db::local_processor<db::PolygonRef> proc (&layout_org, &layout_org.cell (*layout_org.begin_top_down ()), &layout_org2, &layout_org2.cell (*layout_org2.begin_top_down ()));
db::local_processor<db::PolygonRef, db::PolygonRef> proc (&layout_org, &layout_org.cell (*layout_org.begin_top_down ()), &layout_org2, &layout_org2.cell (*layout_org2.begin_top_down ()));
proc.set_threads (nthreads);
proc.set_area_ratio (3.0);
proc.set_max_vertex_count (16);
@ -250,7 +250,7 @@ static void run_test_bool_gen (tl::TestBase *_this, const char *file, TestMode m
if (! context_doc) {
proc.run (lop, l1, l2, lout);
} else {
db::local_processor_contexts<db::PolygonRef> contexts;
db::local_processor_contexts<db::PolygonRef, db::PolygonRef> contexts;
proc.compute_contexts (contexts, lop, l1, l2);
*context_doc = contexts_to_s (&layout_org, contexts);
proc.compute_results (contexts, lop, lout);

View File

@ -267,9 +267,27 @@ static void scan_layer3 (rdb::Category *cat, const db::Layout &layout, unsigned
rdb::scan_layer (cat, layout, layer, from_cell, levels);
}
static void scan_shapes (rdb::Category *cat, const db::RecursiveShapeIterator &iter)
static void scan_shapes (rdb::Category *cat, const db::RecursiveShapeIterator &iter, bool flat)
{
rdb::scan_layer (cat, iter);
rdb::scan_layer (cat, iter, flat);
}
static void scan_region (rdb::Category *cat, rdb::Cell *cell, const db::CplxTrans &trans, const db::Region &region, bool flat)
{
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> it = region.begin_iter ();
rdb::scan_layer (cat, cell, trans * it.second, it.first, flat);
}
static void scan_edges (rdb::Category *cat, rdb::Cell *cell, const db::CplxTrans &trans, const db::Edges &edges, bool flat)
{
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> it = edges.begin_iter ();
rdb::scan_layer (cat, cell, trans * it.second, it.first, flat);
}
static void scan_edge_pairs (rdb::Category *cat, rdb::Cell *cell, const db::CplxTrans &trans, const db::EdgePairs &edge_pairs, bool flat)
{
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> it; /* @@@ = edges.begin_iter (); */
rdb::scan_layer (cat, cell, trans * it.second, it.first, flat);
}
Class<rdb::Category> decl_RdbCategory ("rdb", "RdbCategory",
@ -289,13 +307,41 @@ Class<rdb::Category> decl_RdbCategory ("rdb", "RdbCategory",
"\n"
"This method has been introduced in version 0.23."
) +
gsi::method_ext ("scan_shapes", &scan_shapes,
gsi::method_ext ("scan_shapes", &scan_shapes, gsi::arg ("iter"), gsi::arg ("flat", false),
"@brief Scans the polygon or edge shapes from the shape iterator into the category\n"
"@args iter\n"
"Creates RDB items for each polygon or edge shape read from the iterator and puts them into this category.\n"
"A similar, but lower-level method is \\ReportDatabase#create_items with a \\RecursiveShapeIterator argument.\n"
"In contrast to \\ReportDatabase#create_items, 'scan_shapes' can also produce hierarchical databases "
"if the \\flat argument is false. In this case, the hierarchy the recursive shape iterator traverses is "
"copied into the report database using sample references.\n"
"\n"
"This method has been introduced in version 0.23.\n"
"This method has been introduced in version 0.23. The flat mode argument has been added in version 0.26.\n"
) +
gsi::method_ext ("scan_region", &scan_region, gsi::arg ("cell"), gsi::arg ("trans"), gsi::arg ("region"), gsi::arg ("flat", false),
"@brief Turns the given region into a hierarchical or flat report database\n"
"The exact behavior depends on the nature of the region. If the region is a hierarchical (original or deep) region "
"and the 'flat' argument is false, this method will produce a hierarchical report database in the given category. "
"The 'cell_id' parameter is ignored in this case. Sample references will be produced to supply "
"minimal instantiation information.\n"
"\n"
"If the region is a flat one or the 'flat' argument is true, the region's polygons will be produced as "
"report database items in this category and in the cell given by 'cell_id'.\n"
"\n"
"The transformation argument needs to supply the dbu-to-micron transformation.\n"
"\n"
"This method has been introduced in version 0.26.\n"
) +
gsi::method_ext ("scan_edges", &scan_edges, gsi::arg ("cell"), gsi::arg ("trans"), gsi::arg ("edges"), gsi::arg ("flat", false),
"@brief Turns the given edge collection into a hierarchical or flat report database\n"
"This method behaves like the \\scan_region method, except that is accepts an edge collection.\n"
"\n"
"This method has been introduced in version 0.26.\n"
) +
gsi::method_ext ("scan_edge_pairs", &scan_edge_pairs, gsi::arg ("cell"), gsi::arg ("trans"), gsi::arg ("edge_pairs"), gsi::arg ("flat", false),
"@brief Turns the given edge pair collection into a hierarchical or flat report database\n"
"This method behaves like the \\scan_region method, except that is accepts an edge pair collection.\n"
"\n"
"This method has been introduced in version 0.26.\n"
) +
gsi::method_ext ("scan_layer", &scan_layer1,
"@brief Scans a layer from a layout into this category\n"
@ -966,98 +1012,19 @@ void database_set_tag_description (rdb::Database *db, rdb::id_type tag, const st
db->set_tag_description (tag, d);
}
void create_items_from_iterator (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::RecursiveShapeIterator &iter)
{
tl_assert (iter.layout ());
double dbu = iter.layout ()->dbu ();
for (db::RecursiveShapeIterator i = iter; !i.at_end (); ++i) {
std::auto_ptr<rdb::ValueBase> value (rdb::ValueBase::create_from_shape (*i, db::CplxTrans (dbu) * i.trans ()));
if (value.get ()) {
rdb::Item *item = db->create_item (cell_id, cat_id);
item->values ().add (value.release ());
}
}
}
void create_items_from_shapes (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Shapes &shapes)
{
for (db::Shapes::shape_iterator s = shapes.begin (db::ShapeIterator::All); !s.at_end (); ++s) {
std::auto_ptr<rdb::ValueBase> value (rdb::ValueBase::create_from_shape (*s, trans));
if (value.get ()) {
rdb::Item *item = db->create_item (cell_id, cat_id);
item->values ().add (value.release ());
}
}
}
void create_item_from_shape (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Shape &shape)
{
std::auto_ptr<rdb::ValueBase> value (rdb::ValueBase::create_from_shape (shape, trans));
if (value.get ()) {
rdb::Item *item = db->create_item (cell_id, cat_id);
item->values ().add (value.release ());
}
}
void create_items_from_region (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Region &collection)
{
typedef db::Region::const_iterator iter;
for (iter o = collection.begin (); ! o.at_end (); ++o) {
rdb::Item *item = db->create_item (cell_id, cat_id);
item->values ().add (new rdb::Value <db::DPolygon> (o->transformed (trans)));
}
}
void create_items_from_edges (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Edges &collection)
{
typedef db::Edges::const_iterator iter;
for (iter o = collection.begin (); ! o.at_end (); ++o) {
rdb::Item *item = db->create_item (cell_id, cat_id);
item->values ().add (new rdb::Value <db::DEdge> (o->transformed (trans)));
}
}
void create_items_from_edge_pairs (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::EdgePairs &collection)
{
typedef db::EdgePairs::const_iterator iter;
for (iter o = collection.begin (); ! o.at_end (); ++o) {
rdb::Item *item = db->create_item (cell_id, cat_id);
item->values ().add (new rdb::Value <db::DEdgePair> (o->transformed (trans)));
}
}
void create_items_from_polygon_array (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const std::vector<db::Polygon> &collection)
{
typedef std::vector<db::Polygon>::const_iterator iter;
for (iter o = collection.begin (); o != collection.end (); ++o) {
rdb::Item *item = db->create_item (cell_id, cat_id);
item->values ().add (new rdb::Value <db::DPolygon> (o->transformed (trans)));
}
rdb::create_items_from_sequence (db, cell_id, cat_id, trans, collection.begin (), collection.end ());
}
void create_items_from_edge_array (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const std::vector<db::Edge> &collection)
{
typedef std::vector<db::Edge>::const_iterator iter;
for (iter o = collection.begin (); o != collection.end (); ++o) {
rdb::Item *item = db->create_item (cell_id, cat_id);
item->values ().add (new rdb::Value <db::DEdge> (o->transformed (trans)));
}
rdb::create_items_from_sequence (db, cell_id, cat_id, trans, collection.begin (), collection.end ());
}
void create_items_from_edge_pair_array (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const std::vector<db::EdgePair> &collection)
{
typedef std::vector<db::EdgePair>::const_iterator iter;
for (iter o = collection.begin (); o != collection.end (); ++o) {
rdb::Item *item = db->create_item (cell_id, cat_id);
item->values ().add (new rdb::Value <db::DEdgePair> (o->transformed (trans)));
}
rdb::create_items_from_sequence (db, cell_id, cat_id, trans, collection.begin (), collection.end ());
}
static rdb::Item *create_item (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id)
@ -1081,9 +1048,8 @@ static rdb::Item *create_item_from_objects (rdb::Database *db, rdb::Cell *cell,
}
Class<rdb::Database> decl_ReportDatabase ("rdb", "ReportDatabase",
gsi::constructor ("new", &create_rdb,
gsi::constructor ("new", &create_rdb, gsi::arg ("name"),
"@brief Creates a report database\n"
"@args name\n"
"@param name The name of the database\n"
"The name of the database will be used in the user interface to refer to a certain database."
) +
@ -1093,9 +1059,8 @@ Class<rdb::Database> decl_ReportDatabase ("rdb", "ReportDatabase",
"in a human-readable form.\n"
"@return The description string\n"
) +
gsi::method ("description=", &rdb::Database::set_description,
gsi::method ("description=", &rdb::Database::set_description, gsi::arg ("desc"),
"@brief Sets the databases description\n"
"@args desc\n"
"@param desc The description string\n"
) +
gsi::method ("generator", &rdb::Database::generator,
@ -1104,9 +1069,8 @@ Class<rdb::Database> decl_ReportDatabase ("rdb", "ReportDatabase",
"In a later version this should allow to rerun the tool that created the report.\n"
"@return The generator string\n"
) +
gsi::method ("generator=", &rdb::Database::set_generator,
gsi::method ("generator=", &rdb::Database::set_generator, gsi::arg ("generator"),
"@brief Sets the generator string\n"
"@args generator\n"
"@param generator The generator string\n"
) +
gsi::method ("filename", &rdb::Database::filename,
@ -1126,9 +1090,8 @@ Class<rdb::Database> decl_ReportDatabase ("rdb", "ReportDatabase",
"This property must be set to establish a proper hierarchical context for a hierarchical report database. "
"@return The top cell name\n"
) +
gsi::method ("top_cell_name=", &rdb::Database::set_top_cell_name,
gsi::method ("top_cell_name=", &rdb::Database::set_top_cell_name, gsi::arg ("cell_name"),
"@brief Sets the top cell name string\n"
"@args cell_name\n"
"@param cell_name The top cell name\n"
) +
gsi::method ("original_file", &rdb::Database::original_file,
@ -1136,14 +1099,12 @@ Class<rdb::Database> decl_ReportDatabase ("rdb", "ReportDatabase",
"The original file name is supposed to describe the file from which this report database was generated. "
"@return The original file name and path\n"
) +
gsi::method ("original_file=", &rdb::Database::set_original_file,
gsi::method ("original_file=", &rdb::Database::set_original_file, gsi::arg ("path"),
"@brief Sets the original file name and path\n"
"@args path\n"
"@param path The path\n"
) +
gsi::method_ext ("tag_id", &database_tag_id,
gsi::method_ext ("tag_id", &database_tag_id, gsi::arg ("name"),
"@brief Gets the tag ID for a given tag name\n"
"@args name\n"
"@param name The tag name\n"
"@return The corresponding tag ID\n"
"Tags are used to tag items in the database and to specify tagged (named) values. "
@ -1153,9 +1114,8 @@ Class<rdb::Database> decl_ReportDatabase ("rdb", "ReportDatabase",
"\n"
"\\tag_id handles system tags while \\user_tag_id handles user tags.\n"
) +
gsi::method_ext ("user_tag_id", &database_user_tag_id,
gsi::method_ext ("user_tag_id", &database_user_tag_id, gsi::arg ("name"),
"@brief Gets the tag ID for a given user tag name\n"
"@args name\n"
"@param name The user tag name\n"
"@return The corresponding tag ID\n"
"This method will always succeed and the tag will be created if it does not exist yet. "
@ -1163,23 +1123,20 @@ Class<rdb::Database> decl_ReportDatabase ("rdb", "ReportDatabase",
"\n"
"This method has been added in version 0.24.\n"
) +
gsi::method_ext ("set_tag_description", &database_set_tag_description,
gsi::method_ext ("set_tag_description", &database_set_tag_description, gsi::arg ("tag_id"), gsi::arg ("description"),
"@brief Sets the tag description for the given tag ID\n"
"@args tag_id, description\n"
"@param tag_id The ID of the tag\n"
"@param description The description string\n"
"See \\tag_id for a details about tags.\n"
) +
gsi::method_ext ("tag_description", &database_tag_description,
gsi::method_ext ("tag_description", &database_tag_description, gsi::arg ("tag_id"),
"@brief Gets the tag description for the given tag ID\n"
"@args tag_id\n"
"@param tag_id The ID of the tag\n"
"@return The description string\n"
"See \\tag_id for a details about tags.\n"
) +
gsi::method_ext ("tag_name", &database_tag_name,
gsi::method_ext ("tag_name", &database_tag_name, gsi::arg ("tag_id"),
"@brief Gets the tag name for the given tag ID\n"
"@args tag_id\n"
"@param tag_id The ID of the tag\n"
"@return The name of the tag\n"
"See \\tag_id for a details about tags.\n\n"
@ -1188,54 +1145,45 @@ Class<rdb::Database> decl_ReportDatabase ("rdb", "ReportDatabase",
gsi::iterator_ext ("each_category", &database_begin_categories, &database_end_categories,
"@brief Iterates over all top-level categories\n"
) +
gsi::method ("create_category", (rdb::Category *(rdb::Database::*) (const std::string &)) &rdb::Database::create_category,
gsi::method ("create_category", (rdb::Category *(rdb::Database::*) (const std::string &)) &rdb::Database::create_category, gsi::arg ("name"),
"@brief Creates a new top level category\n"
"@args name\n"
"@param name The name of the category\n"
) +
gsi::method ("create_category", (rdb::Category *(rdb::Database::*) (rdb::Category *, const std::string &)) &rdb::Database::create_category,
gsi::method ("create_category", (rdb::Category *(rdb::Database::*) (rdb::Category *, const std::string &)) &rdb::Database::create_category, gsi::arg ("parent"), gsi::arg ("name"),
"@brief Creates a new sub-category\n"
"@args parent,name\n"
"@param parent The category under which the category should be created\n"
"@param name The name of the category\n"
) +
gsi::method ("category_by_path", &rdb::Database::category_by_name,
gsi::method ("category_by_path", &rdb::Database::category_by_name, gsi::arg ("path"),
"@brief Gets a category by path\n"
"@args path\n"
"@param path The full path to the category starting from the top level (subcategories separated by dots)\n"
"@return The (const) category object or nil if the name is not valid\n"
) +
gsi::method ("category_by_id", &rdb::Database::category_by_id,
gsi::method ("category_by_id", &rdb::Database::category_by_id, gsi::arg ("id"),
"@brief Gets a category by ID\n"
"@args id\n"
"@return The (const) category object or nil if the ID is not valid\n"
) +
gsi::method ("create_cell", (rdb::Cell *(rdb::Database::*) (const std::string &)) &rdb::Database::create_cell,
gsi::method ("create_cell", (rdb::Cell *(rdb::Database::*) (const std::string &)) &rdb::Database::create_cell, gsi::arg ("name"),
"@brief Creates a new cell\n"
"@args name\n"
"@param name The name of the cell\n"
) +
gsi::method ("create_cell", (rdb::Cell *(rdb::Database::*) (const std::string &, const std::string &)) &rdb::Database::create_cell,
gsi::method ("create_cell", (rdb::Cell *(rdb::Database::*) (const std::string &, const std::string &)) &rdb::Database::create_cell, gsi::arg ("name"), gsi::arg ("variant"),
"@brief Creates a new cell, potentially as a variant for a cell with the same name\n"
"@args name, variant\n"
"@param name The name of the cell\n"
"@param variant The variant name of the cell\n"
) +
gsi::method ("variants", &rdb::Database::variants,
gsi::method ("variants", &rdb::Database::variants, gsi::arg ("name"),
"@brief Gets the variants for a given cell name\n"
"@args name\n"
"@param name The basic name of the cell\n"
"@return An array of ID's representing cells that are variants for the given base name\n"
) +
gsi::method ("cell_by_qname", &rdb::Database::cell_by_qname,
gsi::method ("cell_by_qname", &rdb::Database::cell_by_qname, gsi::arg ("qname"),
"@brief Returns the cell for a given qualified name\n"
"@args qname\n"
"@param qname The qualified name of the cell (name plus variant name optionally)\n"
"@return The cell object or nil if no such cell exists\n"
) +
gsi::method ("cell_by_id", &rdb::Database::cell_by_id,
gsi::method ("cell_by_id", &rdb::Database::cell_by_id, gsi::arg ("id"),
"@brief Returns the cell for a given ID\n"
"@args id\n"
"@param id The ID of the cell\n"
"@return The cell object or nil if no cell with that ID exists\n"
) +
@ -1281,12 +1229,13 @@ Class<rdb::Database> decl_ReportDatabase ("rdb", "ReportDatabase",
"\n"
"This convenience method has been added in version 0.25.\n"
) +
gsi::method_ext ("create_items", &create_items_from_iterator, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("iter"),
gsi::method_ext ("create_items", &rdb::create_items_from_iterator, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("iter"),
"@brief Creates new items from a shape iterator\n"
"This method takes the shapes from the given iterator and produces items from them.\n"
"It accepts various kind of shapes, such as texts, polygons, boxes and paths and "
"converts them to corresponding items. "
"A similar method, which is intended for production of polygon or edge error layers is \\RdbCategory#scan_shapes.\n"
"converts them to corresponding items. This method will produce a flat version of the shapes iterated by the shape iterator. "
"A similar method, which is intended for production of polygon or edge error layers and also provides hierarchical database "
"construction is \\RdbCategory#scan_shapes.\n"
"\n"
"This method has been introduced in version 0.25.3.\n"
"\n"
@ -1294,7 +1243,7 @@ Class<rdb::Database> decl_ReportDatabase ("rdb", "ReportDatabase",
"@param category_id The ID of the category to which the item is associated\n"
"@param iter The iterator (a \\RecursiveShapeIterator object) from which to take the items\n"
) +
gsi::method_ext ("create_item", &create_item_from_shape, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("shape"),
gsi::method_ext ("create_item", &rdb::create_item_from_shape, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("shape"),
"@brief Creates a new item from a single shape\n"
"This method produces an item from the given shape.\n"
"It accepts various kind of shapes, such as texts, polygons, boxes and paths and "
@ -1308,7 +1257,7 @@ Class<rdb::Database> decl_ReportDatabase ("rdb", "ReportDatabase",
"@param shape The shape to take the geometrical object from\n"
"@param trans The transformation to apply\n"
) +
gsi::method_ext ("create_items", &create_items_from_shapes, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("shapes"),
gsi::method_ext ("create_items", &rdb::create_items_from_shapes, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("shapes"),
"@brief Creates new items from a shape container\n"
"This method takes the shapes from the given container and produces items from them.\n"
"It accepts various kind of shapes, such as texts, polygons, boxes and paths and "
@ -1322,52 +1271,61 @@ Class<rdb::Database> decl_ReportDatabase ("rdb", "ReportDatabase",
"@param shapes The shape container from which to take the items\n"
"@param trans The transformation to apply\n"
) +
gsi::method_ext ("create_items", &create_items_from_region,
gsi::method_ext ("create_items", &rdb::create_items_from_region, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("region"),
"@brief Creates new polygon items for the given cell/category combination\n"
"For each polygon in the region a single item will be created. The value of the item will be this "
"polygon.\n"
"A transformation can be supplied which can be used for example to convert the "
"object's dimensions to micron units by scaling by the database unit.\n"
"\n"
"This method will also produce a flat version of the shapes inside the region. "
"\\RdbCategory#scan_region is a similar method which also supports construction of "
"hierarchical databases from deep regions.\n"
"\n"
"This method has been introduced in version 0.23.\n"
"\n"
"@args cell_id, category_id, trans, polygons\n"
"@param cell_id The ID of the cell to which the item is associated\n"
"@param category_id The ID of the category to which the item is associated\n"
"@param trans The transformation to apply\n"
"@param region The region (a \\Region object) containing the polygons for which to create items\n"
) +
gsi::method_ext ("create_items", &create_items_from_edges,
gsi::method_ext ("create_items", &rdb::create_items_from_edges, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("edges"),
"@brief Creates new edge items for the given cell/category combination\n"
"For each edge a single item will be created. The value of the item will be this "
"edge.\n"
"A transformation can be supplied which can be used for example to convert the "
"object's dimensions to micron units by scaling by the database unit.\n"
"\n"
"This method will also produce a flat version of the edges inside the edge collection. "
"\\RdbCategory#scan_edges is a similar method which also supports construction of "
"hierarchical databases from deep edge collections.\n"
"\n"
"This method has been introduced in version 0.23.\n"
"\n"
"@args cell_id, category_id, trans, edges\n"
"@param cell_id The ID of the cell to which the item is associated\n"
"@param category_id The ID of the category to which the item is associated\n"
"@param trans The transformation to apply\n"
"@param edges The list of edges (an \\Edges object) for which the items are created\n"
) +
gsi::method_ext ("create_items", &create_items_from_edge_pairs,
gsi::method_ext ("create_items", &rdb::create_items_from_edge_pairs, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("edge_pairs"),
"@brief Creates new edge pair items for the given cell/category combination\n"
"For each edge pair a single item will be created. The value of the item will be this "
"edge pair.\n"
"A transformation can be supplied which can be used for example to convert the "
"object's dimensions to micron units by scaling by the database unit.\n"
"\n"
"This method will also produce a flat version of the edge pairs inside the edge pair collection. "
"\\RdbCategory#scan_edge_pairs is a similar method which also supports construction of "
"hierarchical databases from deep edge pair collections.\n"
"\n"
"This method has been introduced in version 0.23.\n"
"\n"
"@args cell_id, category_id, trans, edge_pairs\n"
"@param cell_id The ID of the cell to which the item is associated\n"
"@param category_id The ID of the category to which the item is associated\n"
"@param trans The transformation to apply\n"
"@param edges The list of edge pairs (an \\EdgePairs object) for which the items are created\n"
) +
gsi::method_ext ("create_items", &create_items_from_polygon_array,
gsi::method_ext ("create_items", &create_items_from_polygon_array, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("array"),
"@brief Creates new polygon items for the given cell/category combination\n"
"For each polygon a single item will be created. The value of the item will be this "
"polygon.\n"
@ -1376,13 +1334,12 @@ Class<rdb::Database> decl_ReportDatabase ("rdb", "ReportDatabase",
"\n"
"This method has been introduced in version 0.23.\n"
"\n"
"@args cell_id, category_id, trans, polygons\n"
"@param cell_id The ID of the cell to which the item is associated\n"
"@param category_id The ID of the category to which the item is associated\n"
"@param trans The transformation to apply\n"
"@param polygons The list of polygons for which the items are created\n"
) +
gsi::method_ext ("create_items", &create_items_from_edge_array,
gsi::method_ext ("create_items", &create_items_from_edge_array, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("array"),
"@brief Creates new edge items for the given cell/category combination\n"
"For each edge a single item will be created. The value of the item will be this "
"edge.\n"
@ -1391,13 +1348,12 @@ Class<rdb::Database> decl_ReportDatabase ("rdb", "ReportDatabase",
"\n"
"This method has been introduced in version 0.23.\n"
"\n"
"@args cell_id, category_id, trans, edges\n"
"@param cell_id The ID of the cell to which the item is associated\n"
"@param category_id The ID of the category to which the item is associated\n"
"@param trans The transformation to apply\n"
"@param edges The list of edges for which the items are created\n"
) +
gsi::method_ext ("create_items", &create_items_from_edge_pair_array,
gsi::method_ext ("create_items", &create_items_from_edge_pair_array, gsi::arg ("cell_id"), gsi::arg ("category_id"), gsi::arg ("trans"), gsi::arg ("array"),
"@brief Creates new edge pair items for the given cell/category combination\n"
"For each edge pair a single item will be created. The value of the item will be this "
"edge pair.\n"
@ -1406,7 +1362,6 @@ Class<rdb::Database> decl_ReportDatabase ("rdb", "ReportDatabase",
"\n"
"This method has been introduced in version 0.23.\n"
"\n"
"@args cell_id, category_id, trans, edge_pairs\n"
"@param cell_id The ID of the cell to which the item is associated\n"
"@param category_id The ID of the category to which the item is associated\n"
"@param trans The transformation to apply\n"

View File

@ -520,6 +520,15 @@ private:
C m_value;
};
/**
* @brief Type bindings
*/
template <class T>
RDB_PUBLIC ValueBase *make_value (const T &value)
{
return new Value<T> (value);
}
/**
* @brief A class encapsulating ValueBase pointer
*/

View File

@ -26,11 +26,14 @@
#include "dbLayout.h"
#include "dbLayoutUtils.h"
#include "dbRecursiveShapeIterator.h"
#include "dbRegion.h"
#include "dbEdges.h"
#include "dbEdgePairs.h"
namespace rdb
{
RDB_PUBLIC void
void
scan_layer (rdb::Category *cat, const db::Layout &layout, unsigned int layer, const db::Cell *from, int levels)
{
rdb::Database *rdb = cat->database ();
@ -75,63 +78,231 @@ scan_layer (rdb::Category *cat, const db::Layout &layout, unsigned int layer, co
}
for (db::ShapeIterator shape = cell.shapes (layer).begin (db::ShapeIterator::All); ! shape.at_end (); ++shape) {
if (shape->is_polygon () || shape->is_path () || shape->is_box ()) {
db::Polygon poly;
shape->polygon (poly);
rdb::Item *item = rdb->create_item (rdb_cell->id (), cat->id ());
item->values ().add (new rdb::Value <db::DPolygon> (poly.transformed (db::CplxTrans (layout.dbu ()))));
} else if (shape->is_edge ()) {
db::Edge edge;
shape->edge (edge);
rdb::Item *item = rdb->create_item (rdb_cell->id (), cat->id ());
item->values ().add (new rdb::Value <db::DEdge> (edge.transformed (db::CplxTrans (layout.dbu ()))));
}
}
create_items_from_shapes (rdb, rdb_cell->id (), cat->id (), db::CplxTrans (layout.dbu ()), cell.shapes (layer));
}
}
}
RDB_PUBLIC void
scan_layer (rdb::Category *cat, const db::RecursiveShapeIterator &iter)
namespace
{
class CreateItemsRecursiveReceiver
: public db::RecursiveShapeReceiver
{
public:
CreateItemsRecursiveReceiver (rdb::Category *cat, const db::CplxTrans &trans, rdb::Cell *cell)
: mp_cat (cat), mp_rdb (cat->database ()), m_trans (trans), mp_rdb_cell (cell)
{
// just in case the iterator is non-hierarchical
if (cell) {
m_cell_stack.push_back (cell);
}
}
virtual void begin (const db::RecursiveShapeIterator *iter)
{
m_cell_stack.clear ();
db::cell_index_type ci = iter->top_cell ()->cell_index ();
const rdb::Cell *rdb_cell = cell_for_id (iter->layout (), ci);
m_cell_stack.push_back (rdb_cell);
m_id_to_cell.insert (std::make_pair (ci, rdb_cell));
}
virtual void end (const db::RecursiveShapeIterator *)
{
m_cell_stack.pop_back ();
}
virtual void enter_cell (const db::RecursiveShapeIterator *iter, const db::Cell *cell, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
{
db::cell_index_type ci = cell->cell_index ();
const rdb::Cell *rdb_cell = cell_for_id (iter->layout (), ci);
m_cell_stack.push_back (rdb_cell);
m_id_to_cell.insert (std::make_pair (ci, rdb_cell));
if (rdb_cell->references ().begin () == rdb_cell->references ().end ()) {
db::DCplxTrans t = m_trans * iter->trans () * m_trans.inverted ();
// TODO: get rid of the const_cast
(const_cast<rdb::Cell *> (rdb_cell))->references ().insert (rdb::Reference (t, m_cell_stack.front ()->id ()));
}
}
virtual void leave_cell (const db::RecursiveShapeIterator * /*iter*/, const db::Cell * /*cell*/)
{
m_cell_stack.pop_back ();
}
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator * /*iter*/, const db::CellInstArray &inst, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/)
{
db::cell_index_type ci = inst.object ().cell_index ();
if (m_id_to_cell.find (ci) != m_id_to_cell.end ()) {
return NI_skip;
} else {
return NI_single;
}
}
virtual void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
{
tl_assert (! m_cell_stack.empty ());
create_item_from_shape (mp_rdb, m_cell_stack.back ()->id (), mp_cat->id (), m_trans, shape);
}
public:
rdb::Category *mp_cat;
rdb::Database *mp_rdb;
std::vector<const rdb::Cell *> m_cell_stack;
std::map<db::cell_index_type, const rdb::Cell *> m_id_to_cell;
db::CplxTrans m_trans;
rdb::Cell *mp_rdb_cell;
const rdb::Cell *cell_for_id (const db::Layout *layout, db::cell_index_type ci)
{
tl_assert (layout != 0);
std::string cn = layout->cell_name (ci);
const rdb::Cell *rdb_cell = mp_rdb->cell_by_qname (cn);
if (! rdb_cell) {
return mp_rdb->create_cell (cn);
} else {
return rdb_cell;
}
}
};
class CreateItemsFlatReceiver
: public db::RecursiveShapeReceiver
{
public:
CreateItemsFlatReceiver (rdb::Category *cat, const db::CplxTrans &trans, rdb::Cell *cell)
: mp_cat (cat), mp_rdb (cat->database ()), m_trans (trans), mp_rdb_cell (cell)
{
// .. nothing yet ..
}
virtual void begin (const db::RecursiveShapeIterator *iter)
{
if (! mp_rdb_cell) {
db::cell_index_type ci = iter->top_cell ()->cell_index ();
tl_assert (iter->layout () != 0);
std::string cn = iter->layout ()->cell_name (ci);
mp_rdb_cell = mp_rdb->cell_by_qname (cn);
if (! mp_rdb_cell) {
mp_rdb_cell = mp_rdb->create_cell (cn);
}
}
}
virtual void shape (const db::RecursiveShapeIterator *iter, const db::Shape &shape, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
{
create_item_from_shape (mp_rdb, mp_rdb_cell->id (), mp_cat->id (), m_trans * iter->trans (), shape);
}
public:
rdb::Category *mp_cat;
rdb::Database *mp_rdb;
db::CplxTrans m_trans;
const rdb::Cell *mp_rdb_cell;
};
}
void
scan_layer (rdb::Category *cat, const db::RecursiveShapeIterator &iter, bool flat)
{
if (! iter.top_cell () || ! iter.layout ()) {
return;
}
rdb::Database *rdb = cat->database ();
if (! rdb) {
db::CplxTrans trans (iter.layout ()->dbu ());
scan_layer (cat, 0, trans, iter, flat);
}
void
scan_layer (rdb::Category *cat, rdb::Cell *cell, const db::CplxTrans &trans, const db::RecursiveShapeIterator &iter, bool flat)
{
if (! cat->database ()) {
return;
}
rdb::Cell *rdb_cell = rdb->create_cell (iter.layout ()->cell_name (iter.top_cell ()->cell_index ()));
std::auto_ptr<db::RecursiveShapeReceiver> rec;
if (flat) {
rec.reset (new CreateItemsFlatReceiver (cat, trans, cell));
} else {
rec.reset (new CreateItemsRecursiveReceiver (cat, trans, cell));
}
for (db::RecursiveShapeIterator i = iter; ! i.at_end (); ++i) {
db::RecursiveShapeIterator (iter).push (rec.get ());
}
if (i.shape ().is_polygon () || i.shape ().is_path () || i.shape ().is_box ()) {
// ------------------------------------------------------------------------------------------------------------
db::Polygon poly;
i.shape ().polygon (poly);
rdb::Item *item = rdb->create_item (rdb_cell->id (), cat->id ());
item->values ().add (new rdb::Value <db::DPolygon> (poly.transformed (db::CplxTrans (iter.layout ()->dbu ()) * i.trans ())));
} else if (i.shape ().is_edge ()) {
db::Edge edge;
i.shape ().edge (edge);
rdb::Item *item = rdb->create_item (rdb_cell->id (), cat->id ());
item->values ().add (new rdb::Value <db::DEdge> (edge.transformed (db::CplxTrans (iter.layout ()->dbu ()) * i.trans ())));
void create_items_from_iterator (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::RecursiveShapeIterator &iter)
{
tl_assert (iter.layout ());
double dbu = iter.layout ()->dbu ();
for (db::RecursiveShapeIterator i = iter; !i.at_end (); ++i) {
std::auto_ptr<rdb::ValueBase> value (rdb::ValueBase::create_from_shape (*i, db::CplxTrans (dbu) * i.trans ()));
if (value.get ()) {
rdb::Item *item = db->create_item (cell_id, cat_id);
item->values ().add (value.release ());
}
}
}
void create_items_from_shapes (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Shapes &shapes)
{
for (db::Shapes::shape_iterator s = shapes.begin (db::ShapeIterator::All); !s.at_end (); ++s) {
std::auto_ptr<rdb::ValueBase> value (rdb::ValueBase::create_from_shape (*s, trans));
if (value.get ()) {
rdb::Item *item = db->create_item (cell_id, cat_id);
item->values ().add (value.release ());
}
}
}
void create_item_from_shape (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Shape &shape)
{
std::auto_ptr<rdb::ValueBase> value (rdb::ValueBase::create_from_shape (shape, trans));
if (value.get ()) {
rdb::Item *item = db->create_item (cell_id, cat_id);
item->values ().add (value.release ());
}
}
void create_items_from_region (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Region &collection)
{
typedef db::Region::const_iterator iter;
for (iter o = collection.begin (); ! o.at_end (); ++o) {
rdb::Item *item = db->create_item (cell_id, cat_id);
item->values ().add (new rdb::Value <db::DPolygon> (o->transformed (trans)));
}
}
void create_items_from_edges (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Edges &collection)
{
typedef db::Edges::const_iterator iter;
for (iter o = collection.begin (); ! o.at_end (); ++o) {
rdb::Item *item = db->create_item (cell_id, cat_id);
item->values ().add (new rdb::Value <db::DEdge> (o->transformed (trans)));
}
}
void create_items_from_edge_pairs (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::EdgePairs &collection)
{
typedef db::EdgePairs::const_iterator iter;
for (iter o = collection.begin (); ! o.at_end (); ++o) {
rdb::Item *item = db->create_item (cell_id, cat_id);
item->values ().add (new rdb::Value <db::DEdgePair> (o->transformed (trans)));
}
}

View File

@ -26,12 +26,17 @@
#include "rdb.h"
#include "dbTypes.h"
#include "dbTrans.h"
namespace db
{
class Layout;
class Cell;
class RecursiveShapeIterator;
class Shapes;
class Region;
class Edges;
class EdgePairs;
}
namespace rdb
@ -52,7 +57,84 @@ RDB_PUBLIC void scan_layer (rdb::Category *cat, const db::Layout &layout, unsign
/**
* @brief Scans a recursive shape iterator into a RDB category
*/
RDB_PUBLIC void scan_layer (rdb::Category *cat, const db::RecursiveShapeIterator &iter);
RDB_PUBLIC void scan_layer (rdb::Category *cat, const db::RecursiveShapeIterator &iter, bool flat = false);
/**
* @brief Scans a recursive shape iterator into a RDB category
*
* This version allows supplying a cell and a transformation. With this information, the function can also handle
* pseudo-iterators which don't deliver the information from a layout from from a plain shape collection.
*/
RDB_PUBLIC void scan_layer (rdb::Category *cat, rdb::Cell *cell, const db::CplxTrans &trans, const db::RecursiveShapeIterator &iter, bool flat = false);
/**
* @brief Creates RDB items from a recursive shape iterator
*
* This function will produce items from the flattened shape iterator. The items will be stored under
* the given cell.
*/
RDB_PUBLIC void create_items_from_iterator (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::RecursiveShapeIterator &iter);
/**
* @brief Creates RDB items from a shape collection
*
* An arbitrary transformation can be applied to translate the shapes before turning them to items.
* This transformation is useful for providing the DBU-to-micron conversion.
*/
RDB_PUBLIC void create_items_from_shapes (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Shapes &shapes);
/**
* @brief Creates RDB items from a single shape
*
* An arbitrary transformation can be applied to translate the shapes before turning them to items.
* This transformation is useful for providing the DBU-to-micron conversion.
*/
RDB_PUBLIC void create_item_from_shape (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Shape &shape);
/**
* @brief Creates RDB items from a region
*
* This function will flatten the region and store the resulting items under the given cell.
*
* An arbitrary transformation can be applied to translate the shapes before turning them to items.
* This transformation is useful for providing the DBU-to-micron conversion.
*/
RDB_PUBLIC void create_items_from_region (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Region &collection);
/**
* @brief Creates RDB items from an edge collection
*
* This function will flatten the edge collection and store the resulting items under the given cell.
*
* An arbitrary transformation can be applied to translate the shapes before turning them to items.
* This transformation is useful for providing the DBU-to-micron conversion.
*/
RDB_PUBLIC void create_items_from_edges (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::Edges &collection);
/**
* @brief Creates RDB items from an edge pair collection
*
* This function will flatten the edge pair collection and store the resulting items under the given cell.
*
* An arbitrary transformation can be applied to translate the shapes before turning them to items.
* This transformation is useful for providing the DBU-to-micron conversion.
*/
RDB_PUBLIC void create_items_from_edge_pairs (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const db::CplxTrans &trans, const db::EdgePairs &collection);
/**
* @brief Creates RDB items from a sequence of integer-type objects
*
* An arbitrary transformation can be applied to translate the shapes before turning them to items.
* This transformation is useful for providing the DBU-to-micron conversion.
*/
template <class Trans, class Iter>
RDB_PUBLIC void create_items_from_sequence (rdb::Database *db, rdb::id_type cell_id, rdb::id_type cat_id, const Trans &trans, Iter begin, Iter end)
{
for (Iter o = begin; o != end; ++o) {
rdb::Item *item = db->create_item (cell_id, cat_id);
item->values ().add (rdb::make_value (o->transformed (trans)));
}
}
}

View File

@ -769,18 +769,18 @@ class RDB_TestClass < TestBase
rdb = RBA::ReportDatabase.new("neu")
cat = rdb.create_category("l1")
cat.scan_shapes(c1.begin_shapes_rec(l1))
cat.scan_shapes(c1.begin_shapes_rec(l1)) # hierarchical scan
assert_equal(cat.num_items, 3)
cn = []
rdb.each_cell { |c| cn << c.to_s_test }
assert_equal(cn.join(";"), "c1[]")
assert_equal(cn.join(";"), "c1[];c2[c1->r0 *1 0.01,0.02];c3[c1->r0 *1 0.021,0.041]")
cn = []
rdb.each_cell { |c| cn << c.to_s_items }
assert_equal(cn.join(";"), "c1[polygon: (0,0.001;0,0.03;0.02,0.03;0.02,0.001),polygon: (0.01,0.021;0.01,0.051;0.031,0.051;0.031,0.021),polygon: (0.021,0.042;0.021,0.073;0.043,0.073;0.043,0.042)]")
assert_equal(cn.join(";"), "c1[polygon: (0,0.001;0,0.03;0.02,0.03;0.02,0.001)];c2[polygon: (0,0.001;0,0.031;0.021,0.031;0.021,0.001)];c3[polygon: (0,0.001;0,0.032;0.022,0.032;0.022,0.001)]")
rdb = RBA::ReportDatabase.new("neu")
cat = rdb.create_category("l1")
cat.scan_shapes(c1.begin_shapes_rec(l1))
cat.scan_shapes(c1.begin_shapes_rec(l1), true) # flat scan
assert_equal(cat.num_items, 3)
cn = []
rdb.each_cell { |c| cn << c.to_s_test }