WIP: a new concept for complex DRC - 'foreign' subjects

This commit is contained in:
Matthias Koefferlein 2021-01-05 22:49:30 +01:00
parent 6dd190e3af
commit 9812ff7901
13 changed files with 497 additions and 72 deletions

View File

@ -411,7 +411,7 @@ AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse,
std::vector<db::Shapes *> results;
results.push_back (&output->raw_polygons ());
proc.run_flat (polygons, others, &op, results);
proc.run_flat (polygons, others, std::vector<bool> (), &op, results);
return output.release ();
@ -487,7 +487,7 @@ AsIfFlatRegion::selected_interacting_generic (const Texts &other, bool inverse,
std::vector<db::Shapes *> results;
results.push_back (&output->raw_polygons ());
proc.run_flat (polygons, others, &op, results);
proc.run_flat (polygons, others, std::vector<bool> (), &op, results);
return output.release ();
@ -572,7 +572,7 @@ AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, boo
std::vector<db::Shapes *> results;
results.push_back (&output->raw_polygons ());
proc.run_flat (polygons, others, &op, results);
proc.run_flat (polygons, others, std::vector<bool> (), &op, results);
return output.release ();
@ -710,7 +710,7 @@ AsIfFlatRegion::pull_generic (const Edges &other) const
std::vector<db::Shapes *> results;
results.push_back (&output->raw_edges ());
proc.run_flat (polygons, others, &op, results);
proc.run_flat (polygons, others, std::vector<bool> (), &op, results);
return output.release ();
@ -760,7 +760,7 @@ AsIfFlatRegion::pull_generic (const Texts &other) const
std::vector<db::Shapes *> results;
results.push_back (&output->raw_texts ());
proc.run_flat (polygons, others, &op, results);
proc.run_flat (polygons, others, std::vector<bool> (), &op, results);
return output.release ();
@ -815,7 +815,7 @@ AsIfFlatRegion::pull_generic (const Region &other, int mode, bool touching) cons
std::vector<db::Shapes *> results;
results.push_back (&output->raw_polygons ());
proc.run_flat (polygons, others, &op, results);
proc.run_flat (polygons, others, std::vector<bool> (), &op, results);
return output.release ();
@ -1050,16 +1050,23 @@ void region_cop_impl (AsIfFlatRegion *region, db::Shapes *output_to, db::Compoun
db::RegionIterator polygons (needs_merged ? region->begin_merged () : region->begin ());
std::vector<generic_shape_iterator<db::Polygon> > others;
std::vector<bool> foreign;
std::vector<db::Region *> inputs = node.inputs ();
for (std::vector<db::Region *>::const_iterator i = inputs.begin (); i != inputs.end (); ++i) {
others.push_back (*i ? (*i)->begin () : (needs_merged ? region->begin_merged () : region->begin ()));
if (*i == subject_regionptr () || *i == foreign_regionptr ()) {
others.push_back (needs_merged ? region->begin_merged () : region->begin ());
foreign.push_back (*i == foreign_regionptr ());
} else {
others.push_back ((*i)->begin ());
foreign.push_back (false);
}
}
std::vector<db::Shapes *> results;
results.push_back (output_to);
compound_local_operation<db::Polygon, db::Polygon, TR> op (&node);
proc.run_flat (polygons, others, &op, results);
proc.run_flat (polygons, others, foreign, &op, results);
}
EdgePairsDelegate *
@ -1112,7 +1119,7 @@ AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons,
std::vector<db::Shapes *> results;
results.push_back (&output->raw_edge_pairs ());
proc.run_flat (polygons, others, &op, results);
proc.run_flat (polygons, others, std::vector<bool> (), &op, results);
return output.release ();

View File

@ -122,7 +122,7 @@ CompoundRegionOperationPrimaryNode::~CompoundRegionOperationPrimaryNode ()
std::vector<db::Region *> CompoundRegionOperationPrimaryNode::inputs () const
{
std::vector<db::Region *> is;
is.push_back (0);
is.push_back (subject_regionptr ());
return is;
}
@ -177,6 +177,40 @@ void CompoundRegionOperationSecondaryNode::do_compute_local (db::Layout *, const
// ---------------------------------------------------------------------------------------------
CompoundRegionOperationForeignNode::CompoundRegionOperationForeignNode ()
{
set_description ("foreign");
}
CompoundRegionOperationForeignNode::~CompoundRegionOperationForeignNode ()
{
// .. nothing yet ..
}
std::vector<db::Region *> CompoundRegionOperationForeignNode::inputs () const
{
std::vector<db::Region *> iv;
iv.push_back (foreign_regionptr ());
return iv;
}
void CompoundRegionOperationForeignNode::do_compute_local (db::Layout *, const shape_interactions<db::Polygon, db::Polygon> &interactions, std::vector<std::unordered_set<db::Polygon> > &results, size_t, double) const
{
for (shape_interactions<db::Polygon, db::Polygon>::intruder_iterator i = interactions.begin_intruders (); i != interactions.end_intruders (); ++i) {
results.front ().insert (i->second.second);
}
}
void CompoundRegionOperationForeignNode::do_compute_local (db::Layout *, const shape_interactions<db::PolygonRef, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::PolygonRef> > &results, size_t, double) const
{
for (shape_interactions<db::PolygonRef, db::PolygonRef>::intruder_iterator i = interactions.begin_intruders (); i != interactions.end_intruders (); ++i) {
results.front ().insert (i->second.second);
}
}
// ---------------------------------------------------------------------------------------------
CompoundTransformationReducer::CompoundTransformationReducer ()
{
// .. nothing yet ..
@ -916,7 +950,7 @@ void compound_region_generic_operation_node<TS, TI, TR>::implement_compute_local
}
db::local_processor <TS, TI, TR> proc (layout);
proc.run_flat (is, iiv, m_op, adaptor.results ());
proc.run_flat (is, iiv, std::vector<bool> (), m_op, adaptor.results ());
adaptor.finish (layout);
}
@ -1177,8 +1211,8 @@ CompoundRegionEdgePairFilterOperationNode::is_selected (const db::EdgePair &p) c
// ---------------------------------------------------------------------------------------------
CompoundRegionProcessingOperationNode::CompoundRegionProcessingOperationNode (PolygonProcessorBase *proc, CompoundRegionOperationNode *input, bool owns_proc)
: CompoundRegionMultiInputOperationNode (input), mp_proc (proc), m_owns_proc (owns_proc)
CompoundRegionProcessingOperationNode::CompoundRegionProcessingOperationNode (PolygonProcessorBase *proc, CompoundRegionOperationNode *input, bool owns_proc, db::Coord dist_adder)
: CompoundRegionMultiInputOperationNode (input), mp_proc (proc), m_owns_proc (owns_proc), m_dist_adder (dist_adder)
{
set_description ("processor");
}
@ -1497,7 +1531,7 @@ CompoundRegionCheckOperationNode::wants_merged () const
void
CompoundRegionCheckOperationNode::do_compute_local (db::Layout *layout, const shape_interactions<db::Polygon, db::Polygon> &interactions, std::vector<std::unordered_set<db::EdgePair> > &results, size_t max_vertex_count, double area_ratio) const
{
bool other_merged = (children () > 0 && !inputs ()[0]);
bool other_merged = (children () > 0 && is_subject_regionptr (inputs ()[0]));
db::check_local_operation<db::Polygon, db::Polygon> op (m_check, m_different_polygons, children () > 0, other_merged, m_options);
@ -1515,7 +1549,7 @@ CompoundRegionCheckOperationNode::do_compute_local (db::Layout *layout, const sh
void
CompoundRegionCheckOperationNode::do_compute_local (db::Layout *layout, const shape_interactions<db::PolygonRef, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::EdgePair> > &results, size_t max_vertex_count, double area_ratio) const
{
bool other_merged = (children () > 0 && !inputs ()[0]);
bool other_merged = (children () > 0 && is_subject_regionptr (inputs ()[0]));
db::check_local_operation<db::PolygonRef, db::PolygonRef> op (m_check, m_different_polygons, children () > 0, other_merged, m_options);

View File

@ -44,6 +44,10 @@
namespace db
{
inline db::Region *subject_regionptr () { return (db::Region *) 0; }
inline db::Region *foreign_regionptr () { return (db::Region *) 1; }
inline bool is_subject_regionptr (const db::Region *ptr) { return ptr == subject_regionptr () || ptr == foreign_regionptr (); }
/**
* @brief A node of the compound operation tree
*
@ -282,6 +286,20 @@ public:
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::PolygonRef, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::PolygonRef> > &results, size_t max_vertex_count, double area_ratio) const;
};
class DB_PUBLIC CompoundRegionOperationForeignNode
: public CompoundRegionOperationNode
{
public:
CompoundRegionOperationForeignNode ();
virtual ~CompoundRegionOperationForeignNode ();
virtual std::vector<db::Region *> inputs () const;
virtual db::Coord dist () const { return 0; }
virtual ResultType result_type () const { return Region; }
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::Polygon, db::Polygon> &interactions, std::vector<std::unordered_set<db::Polygon> > &results, size_t max_vertex_count, double area_ratio) const;
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::PolygonRef, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::PolygonRef> > &results, size_t max_vertex_count, double area_ratio) const;
};
class DB_PUBLIC CompoundRegionOperationSecondaryNode
: public CompoundRegionOperationNode
@ -976,12 +994,14 @@ class DB_PUBLIC CompoundRegionProcessingOperationNode
: public CompoundRegionMultiInputOperationNode
{
public:
CompoundRegionProcessingOperationNode (PolygonProcessorBase *proc, CompoundRegionOperationNode *input, bool owns_proc = false);
CompoundRegionProcessingOperationNode (PolygonProcessorBase *proc, CompoundRegionOperationNode *input, bool owns_proc = false, db::Coord dist_adder = 0);
~CompoundRegionProcessingOperationNode ();
// specifies the result type
virtual ResultType result_type () const { return Region; }
virtual db::Coord dist () const { return m_dist_adder + CompoundRegionMultiInputOperationNode::dist (); }
virtual const TransformationReducer *vars () const { return mp_proc->vars (); }
virtual bool wants_variants () const { return mp_proc->wants_variants (); }
virtual bool wants_merged () const { return true; }
@ -992,6 +1012,7 @@ public:
private:
PolygonProcessorBase *mp_proc;
bool m_owns_proc;
db::Coord m_dist_adder;
void processed (db::Layout *, const db::Polygon &p, std::vector<db::Polygon> &res) const;
void processed (db::Layout *layout, const db::PolygonRef &p, std::vector<db::PolygonRef> &res) const;

View File

@ -1350,7 +1350,7 @@ Output *region_cop_impl (DeepRegion *region, db::CompoundRegionOperationNode &no
// Fall back to flat mode if one of the inputs is flat
std::vector<db::Region *> inputs = node.inputs ();
for (std::vector<db::Region *>::const_iterator i = inputs.begin (); i != inputs.end (); ++i) {
if (*i && ! dynamic_cast<const db::DeepRegion *> ((*i)->delegate ())) {
if (! is_subject_regionptr (*i) && ! dynamic_cast<const db::DeepRegion *> ((*i)->delegate ())) {
return 0;
}
}
@ -1368,8 +1368,12 @@ Output *region_cop_impl (DeepRegion *region, db::CompoundRegionOperationNode &no
std::vector<unsigned int> other_layers;
for (std::vector<db::Region *>::const_iterator i = inputs.begin (); i != inputs.end (); ++i) {
if (! *i) {
other_layers.push_back (polygons.layer ());
if (is_subject_regionptr (*i)) {
if (*i == subject_regionptr ()) {
other_layers.push_back (subject_idlayer ());
} else {
other_layers.push_back (foreign_idlayer ());
}
} else {
const db::DeepRegion *other_deep = dynamic_cast<const db::DeepRegion *> ((*i)->delegate ());
tl_assert (other_deep != 0);

View File

@ -264,6 +264,31 @@ private:
// ---------------------------------------------------------------------------------------------
/**
* @brief a utility to capture insert attempts of the wrong type into a box scanner
* These attempts can happen because the generic nature of the interaction detector code
*/
template <class T, class P>
void safe_insert2_into_box_scanner (db::box_scanner2 <T, P, T, P> &scanner, const T *t, const P &p)
{
scanner.insert2 (t, p);
}
template <class T1, class P1, class T2, class P2>
void safe_insert2_into_box_scanner (db::box_scanner2 <T1, P1, T2, P2> &scanner, const T2 *t, const P2 &p)
{
scanner.insert2 (t, p);
}
template <class T1, class P1, class T2, class P2>
void safe_insert2_into_box_scanner (db::box_scanner2 <T1, P1, T2, P2> &, const T1 *, const P1 &)
{
tl_assert (false);
}
// ---------------------------------------------------------------------------------------------
/**
* @brief Safe enlargement of a box
* Boxes must not vanish when augmented for overlapping queries. Hence we must not make
@ -744,12 +769,65 @@ public:
mp_result->add_interaction (id1, id2);
}
void same (unsigned int, unsigned int)
{
// ignore. Two shapes of a different kind can't be the same.
}
private:
shape_interactions<TS, TI> *mp_result;
db::Layout *mp_layout;
unsigned int m_intruder_layer_index;
};
template <class T>
struct interaction_registration_shape2shape<T, T>
: db::box_scanner_receiver2<T, unsigned int, T, unsigned int>
{
public:
interaction_registration_shape2shape (db::Layout *layout, shape_interactions<T, T> *result, unsigned int intruder_layer_index)
: mp_result (result), mp_layout (layout), m_intruder_layer_index (intruder_layer_index)
{
// nothing yet ..
}
void add (const T *ref1, unsigned int id1, const T *ref2, unsigned int id2)
{
if (! m_same.empty () && (m_same.find (std::make_pair (id1, id2)) != m_same.end () || m_same.find (std::make_pair (id2, id1)) != m_same.end ())) {
// ignore self-interactions
return;
}
if (!mp_result->has_subject_shape_id (id1)) {
mp_result->add_subject_shape (id1, *ref1);
}
if (!mp_result->has_intruder_shape_id (id2)) {
if (mp_layout) {
// In order to guarantee the refs come from the subject layout, we'd need to
// rewrite them
db::shape_reference_translator<T> rt (mp_layout);
mp_result->add_intruder_shape (id2, m_intruder_layer_index, rt (*ref2));
} else {
mp_result->add_intruder_shape (id2, m_intruder_layer_index, *ref2);
}
}
mp_result->add_interaction (id1, id2);
}
void same (unsigned int a, unsigned int b)
{
m_same.insert (std::make_pair (a, b));
}
private:
shape_interactions<T, T> *mp_result;
std::unordered_set<std::pair<unsigned int, unsigned int> > m_same;
db::Layout *mp_layout;
unsigned int m_intruder_layer_index;
};
template <class TS, class TI>
struct interaction_registration_shape1
: db::box_scanner_receiver2<TS, unsigned int, TI, unsigned int>
@ -758,7 +836,7 @@ public:
interaction_registration_shape1 (shape_interactions<TS, TI> *result, unsigned int intruder_layer_index)
: mp_result (result), m_intruder_layer_index (intruder_layer_index)
{
// nothing yet ..
// .. nothing yet ..
}
void add (const TS *ref1, unsigned int id1, const TI *ref2, unsigned int id2)
@ -946,8 +1024,8 @@ struct interaction_registration_inst2inst
public:
typedef std::pair<std::unordered_set<const db::CellInstArray *>, std::map<unsigned int, std::unordered_set<T> > > interaction_value_type;
interaction_registration_inst2inst (const db::Layout *subject_layout, unsigned int subject_layer, const db::Layout *intruder_layout, unsigned int intruder_layer, db::Coord dist, std::unordered_map<const db::CellInstArray *, interaction_value_type> *result)
: mp_subject_layout (subject_layout), mp_intruder_layout (intruder_layout), m_subject_layer (subject_layer), m_intruder_layer (intruder_layer), m_dist (dist), mp_result (result)
interaction_registration_inst2inst (const db::Layout *subject_layout, unsigned int subject_layer, const db::Layout *intruder_layout, unsigned int intruder_layer, bool foreign, db::Coord dist, std::unordered_map<const db::CellInstArray *, interaction_value_type> *result)
: mp_subject_layout (subject_layout), mp_intruder_layout (intruder_layout), m_subject_layer (subject_layer), m_intruder_layer (intruder_layer), m_dist (dist), mp_result (result), m_foreign (foreign)
{
// nothing yet ..
}
@ -959,7 +1037,7 @@ public:
if (mp_subject_layout != mp_intruder_layout || id1 != id2 || inst1->size () > 1) {
bool ignore = false;
if (mp_subject_layout == mp_intruder_layout && m_subject_layer == m_intruder_layer) {
if (mp_subject_layout == mp_intruder_layout && m_subject_layer == m_intruder_layer && ! m_foreign) {
if (m_interactions.find (std::make_pair (id2, id1)) != m_interactions.end ()) {
// for self interactions ignore the reverse interactions
ignore = true;
@ -981,6 +1059,7 @@ private:
db::Coord m_dist;
std::unordered_map<const db::CellInstArray *, std::pair<std::unordered_set<const db::CellInstArray *>, std::map<unsigned int, std::unordered_set<T> > > > *mp_result;
std::unordered_set<std::pair<unsigned int, unsigned int> > m_interactions;
bool m_foreign;
};
template <class T>
@ -1339,7 +1418,7 @@ void local_processor<TS, TI, TR>::compute_contexts (local_processor_contexts<TS,
std::map<unsigned int, const db::Shapes *> intruder_shapes;
if (intruder_cell) {
for (std::vector<unsigned int>::const_iterator l = contexts.intruder_layers ().begin (); l != contexts.intruder_layers ().end (); ++l) {
const db::Shapes *s = &intruder_cell->shapes (*l);
const db::Shapes *s = &intruder_cell->shapes (contexts.actual_intruder_layer (*l));
if (! s->empty ()) {
intruder_shapes.insert (std::make_pair (*l, s));
}
@ -1369,10 +1448,10 @@ void local_processor<TS, TI, TR>::compute_contexts (local_processor_contexts<TS,
// TODO: can we shortcut this if interactions is empty?
for (std::vector<unsigned int>::const_iterator il = contexts.intruder_layers ().begin (); il != contexts.intruder_layers ().end (); ++il) {
db::box_convert <db::CellInstArray, true> inst_bci (*mp_intruder_layout, *il);
db::box_convert <db::CellInstArray, true> inst_bci (*mp_intruder_layout, contexts.actual_intruder_layer (*il));
db::box_scanner2<db::CellInstArray, int, db::CellInstArray, int> scanner;
interaction_registration_inst2inst<TI> rec (mp_subject_layout, contexts.subject_layer (), mp_intruder_layout, *il, dist, &interactions);
interaction_registration_inst2inst<TI> rec (mp_subject_layout, contexts.subject_layer (), mp_intruder_layout, contexts.actual_intruder_layer (*il), contexts.is_foreign (*il), dist, &interactions);
unsigned int id = 0;
@ -1474,7 +1553,7 @@ void local_processor<TS, TI, TR>::compute_contexts (local_processor_contexts<TS,
for (std::vector<unsigned int>::const_iterator il = contexts.intruder_layers ().begin (); il != contexts.intruder_layers ().end (); ++il) {
db::box_convert <db::CellInst, true> inst_bcii (*mp_intruder_layout, *il);
db::box_convert <db::CellInst, true> inst_bcii (*mp_intruder_layout, contexts.actual_intruder_layer (*il));
for (std::unordered_set<const db::CellInstArray *>::const_iterator j = i->second.first.begin (); j != i->second.first.end (); ++j) {
for (db::CellInstArray::iterator k = (*j)->begin_touching (safe_box_enlarged (nbox, -1, -1), inst_bcii); ! k.at_end (); ++k) {
@ -1482,7 +1561,7 @@ void local_processor<TS, TI, TR>::compute_contexts (local_processor_contexts<TS,
// NOTE: no self-interactions
if (i->first != *j || tn != tk) {
// optimize the intruder instance so it will be as low as possible
std::pair<bool, db::CellInstArray> ei = effective_instance (contexts.subject_layer (), i->first->object ().cell_index (), *il, (*j)->object ().cell_index (), tni * tk, dist);
std::pair<bool, db::CellInstArray> ei = effective_instance (contexts.subject_layer (), i->first->object ().cell_index (), contexts.actual_intruder_layer (*il), (*j)->object ().cell_index (), tni * tk, dist);
if (ei.first) {
intruders_below.first.insert (ei.second);
}
@ -1740,9 +1819,9 @@ struct scan_shape2shape_different_layers
interaction_registration_shape2shape<TS, TI> rec (layout, &interactions, intruder_layer_index);
unsigned int id = subject_id0;
for (db::Shapes::shape_iterator i = subject_shapes->begin (shape_flags<TS> ()); !i.at_end (); ++i) {
for (db::Shapes::shape_iterator i = subject_shapes->begin (shape_flags<TS> ()); !i.at_end (); ++i, ++id) {
const TS *ref = i->basic_ptr (typename TS::tag ());
scanner.insert1 (ref, id++);
scanner.insert1 (ref, id);
}
// TODO: can we confine this search to the subject's (sized) bounding box?
@ -1752,11 +1831,26 @@ struct scan_shape2shape_different_layers
}
}
if (intruder_shapes) {
if (intruder_shapes == subject_shapes) {
// TODO: can we confine this search to the subject's (sized) bounding box?
// special case of intra-layer interactions ("foreign"): mark identical shapes as same so that shapes are not reported interacting with
// themselves.
unsigned int id = subject_id0;
for (db::Shapes::shape_iterator i = intruder_shapes->begin (shape_flags<TI> ()); !i.at_end (); ++i, ++id) {
unsigned int iid = interactions.next_id ();
scanner.insert2 (i->basic_ptr (typename TI::tag ()), iid);
rec.same (id, iid);
}
} else if (intruder_shapes) {
// TODO: can we confine this search to the subject's (sized) bounding box?
for (db::Shapes::shape_iterator i = intruder_shapes->begin (shape_flags<TI> ()); !i.at_end (); ++i) {
scanner.insert2 (i->basic_ptr (typename TI::tag ()), interactions.next_id ());
}
}
scanner.process (rec, dist, db::box_convert<TS> (), db::box_convert<TI> ());
@ -1793,9 +1887,12 @@ local_processor<TS, TI, TR>::compute_local_cell (const db::local_processor_conte
unsigned int il_index = 0;
for (std::vector<unsigned int>::const_iterator il = contexts.intruder_layers ().begin (); il != contexts.intruder_layers ().end (); ++il, ++il_index) {
unsigned int ail = contexts.actual_intruder_layer (*il);
bool foreign = contexts.is_foreign (*il);
const db::Shapes *intruder_shapes = 0;
if (intruder_cell) {
intruder_shapes = &intruder_cell->shapes (*il);
intruder_shapes = &intruder_cell->shapes (ail);
if (intruder_shapes->empty ()) {
intruder_shapes = 0;
}
@ -1803,14 +1900,14 @@ local_processor<TS, TI, TR>::compute_local_cell (const db::local_processor_conte
// local shapes vs. child cell
db::box_convert<db::CellInstArray, true> inst_bci (*mp_intruder_layout, *il);
db::box_convert<db::CellInstArray, true> inst_bci (*mp_intruder_layout, ail);
typename std::map<unsigned int, std::set<TI> >::const_iterator ipl = intruders.second.find (*il);
typename std::map<unsigned int, std::set<TI> >::const_iterator ipl = intruders.second.find (ail);
static std::set<TI> empty_intruders;
if (! subject_shapes->empty () && (intruder_shapes || ipl != intruders.second.end ())) {
if (subject_cell == intruder_cell && contexts.subject_layer () == *il) {
if (subject_cell == intruder_cell && contexts.subject_layer () == ail && !foreign) {
scan_shape2shape_same_layer<TS, TI> () (subject_shapes, subject_id0, ipl == intruders.second.end () ? empty_intruders : ipl->second, il_index, interactions, op->dist ());
@ -1826,7 +1923,7 @@ local_processor<TS, TI, TR>::compute_local_cell (const db::local_processor_conte
if (! subject_shapes->empty () && ! ((! intruder_cell || intruder_cell->begin ().at_end ()) && intruders.first.empty ())) {
db::box_scanner2<TS, int, db::CellInstArray, int> scanner;
interaction_registration_shape2inst<TS, TI> rec (mp_subject_layout, mp_intruder_layout, *il, il_index, op->dist (), &interactions);
interaction_registration_shape2inst<TS, TI> rec (mp_subject_layout, mp_intruder_layout, ail, il_index, op->dist (), &interactions);
unsigned int id = subject_id0;
for (db::Shapes::shape_iterator i = subject_shapes->begin (shape_flags<TS> ()); !i.at_end (); ++i) {
@ -1835,7 +1932,7 @@ local_processor<TS, TI, TR>::compute_local_cell (const db::local_processor_conte
unsigned int inst_id = 0;
if (subject_cell == intruder_cell && contexts.subject_layer () == *il) {
if (subject_cell == intruder_cell && contexts.subject_layer () == ail) {
// Same cell, same layer -> no shape to child instance interactions because this will be taken care of
// by the instances themselves (and their intruders). This also means, we prefer to deal with
@ -1884,12 +1981,19 @@ void
local_processor<TS, TI, TR>::run_flat (const db::Shapes *subject_shapes, const db::Shapes *intruders, const local_operation<TS, TI, TR> *op, db::Shapes *result_shapes) const
{
std::vector<generic_shape_iterator<TI> > is;
std::vector<bool> foreign;
if (intruders == subject_idptr () || intruders == foreign_idptr ()) {
is.push_back (generic_shape_iterator<TI> (subject_shapes));
foreign.push_back (intruders == foreign_idptr ());
} else {
is.push_back (generic_shape_iterator<TI> (intruders));
foreign.push_back (false);
}
std::vector<db::Shapes *> os;
os.push_back (result_shapes);
run_flat (generic_shape_iterator<TS> (subject_shapes), is, op, os);
run_flat (generic_shape_iterator<TS> (subject_shapes), is, foreign, op, os);
}
template <class TS, class TI, class TR>
@ -1898,11 +2002,21 @@ local_processor<TS, TI, TR>::run_flat (const db::Shapes *subject_shapes, const s
{
std::vector<generic_shape_iterator<TI> > is;
is.reserve (intruders.size ());
std::vector<bool> foreign;
foreign.reserve (intruders.size ());
for (std::vector<const db::Shapes *>::const_iterator i = intruders.begin (); i != intruders.end (); ++i) {
if (*i == subject_idptr () || *i == foreign_idptr ()) {
is.push_back (generic_shape_iterator<TI> (subject_shapes));
foreign.push_back (*i == foreign_idptr ());
} else {
is.push_back (generic_shape_iterator<TI> (*i));
foreign.push_back (false);
}
}
run_flat (generic_shape_iterator<TS> (subject_shapes), is, op, result_shapes);
run_flat (generic_shape_iterator<TS> (subject_shapes), is, foreign, op, result_shapes);
}
namespace
@ -1956,7 +2070,7 @@ private:
template <class TS, class TI, class TR>
void
local_processor<TS, TI, TR>::run_flat (const generic_shape_iterator<TS> &subjects, const std::vector<generic_shape_iterator<TI> > &intruders, const local_operation<TS, TI, TR> *op, const std::vector<db::Shapes *> &result_shapes) const
local_processor<TS, TI, TR>::run_flat (const generic_shape_iterator<TS> &subjects, const std::vector<generic_shape_iterator<TI> > &intruders, const std::vector<bool> &foreign, const local_operation<TS, TI, TR> *op, const std::vector<db::Shapes *> &result_shapes) const
{
if (subjects.at_end ()) {
return;
@ -2010,7 +2124,9 @@ local_processor<TS, TI, TR>::run_flat (const generic_shape_iterator<TS> &subject
unsigned int il_index = 0;
for (typename std::vector<generic_shape_iterator<TI> >::const_iterator il = intruders.begin (); il != intruders.end (); ++il, ++il_index) {
if (*il == subjects) {
bool ff = foreign.size () > il_index && foreign [il_index];
if (*il == subjects && ! ff) {
interaction_registration_shape1_scanner_combo<TS, TI> scanner (&interactions, il_index);
@ -2022,14 +2138,28 @@ local_processor<TS, TI, TR>::run_flat (const generic_shape_iterator<TS> &subject
} else {
db::box_scanner2<TS, int, TI, int> scanner;
db::box_scanner2<TS, unsigned int, TI, unsigned int> scanner;
interaction_registration_shape2shape<TS, TI> rec (0 /*layout*/, &interactions, il_index);
for (typename shape_interactions<TS, TI>::subject_iterator s = interactions.begin_subjects (); s != interactions.end_subjects (); ++s) {
scanner.insert1 (&s->second, s->first);
}
if (*il == subjects) {
// this is the case of intra-layer interactions ("foreign"): we pretend we have two layers and
// reject shape self-interactions by registering them as "same"
for (typename shape_interactions<TS, TI>::subject_iterator s = interactions.begin_subjects (); s != interactions.end_subjects (); ++s) {
unsigned int iid = interactions.next_id ();
safe_insert2_into_box_scanner (scanner, &s->second, iid);
rec.same (s->first, iid);
}
scanner.process (rec, dist, db::box_convert<TS> (), db::box_convert<TI> ());
} else {
addressable_shape_delivery<TI> ii ((*il).confined (common_box, true));
for (; !ii.at_end (); ++ii) {
scanner.insert2 (ii.operator-> (), interactions.next_id ());
@ -2038,6 +2168,8 @@ local_processor<TS, TI, TR>::run_flat (const generic_shape_iterator<TS> &subject
scanner.process (rec, dist, db::box_convert<TS> (), db::box_convert<TI> ());
}
}
}
} else {
@ -2058,7 +2190,9 @@ local_processor<TS, TI, TR>::run_flat (const generic_shape_iterator<TS> &subject
unsigned int il_index = 0;
for (typename std::vector<generic_shape_iterator<TI> >::const_iterator il = intruders.begin (); il != intruders.end (); ++il, ++il_index) {
if (*il == subjects) {
bool ff = foreign.size () > il_index && foreign [il_index];
if (*il == subjects && ! ff) {
interaction_registration_shape1_scanner_combo<TS, TI> scanner (&interactions, il_index);
@ -2073,17 +2207,35 @@ local_processor<TS, TI, TR>::run_flat (const generic_shape_iterator<TS> &subject
} else {
db::box_scanner2<TS, int, TI, int> scanner;
db::box_scanner2<TS, unsigned int, TI, unsigned int> scanner;
interaction_registration_shape2shape<TS, TI> rec (0 /*layout*/, &interactions, il_index);
addressable_shape_delivery<TS> is (subjects.confined (common_box, true));
unsigned int id = id_first;
if (*il == subjects) {
// this is the case of intra-layer interactions ("foreign"): we pretend we have two layers and
// reject shape self-interactions by registering them as "same"
addressable_shape_delivery<TS> is (subjects.confined (common_box, true));
unsigned int id = id_first;
for ( ; ! is.at_end (); ++is, ++id) {
unsigned int iid = interactions.next_id ();
scanner.insert1 (is.operator-> (), id);
safe_insert2_into_box_scanner (scanner, is.operator-> (), iid);
rec.same (id, iid);
}
scanner.process (rec, dist, db::box_convert<TS> (), db::box_convert<TI> ());
} else {
addressable_shape_delivery<TS> is (subjects.confined (common_box, true));
addressable_shape_delivery<TI> ii ((*il).confined (common_box, true));
unsigned int id = id_first;
for ( ; ! is.at_end (); ++is, ++id) {
scanner.insert1 (is.operator-> (), id);
}
addressable_shape_delivery<TI> ii ((*il).confined (common_box, true));
for (; !ii.at_end (); ++ii) {
scanner.insert2 (ii.operator-> (), interactions.next_id ());
}
@ -2091,6 +2243,8 @@ local_processor<TS, TI, TR>::run_flat (const generic_shape_iterator<TS> &subject
scanner.process (rec, dist, db::box_convert<TS> (), db::box_convert<TI> ());
}
}
}
}

View File

@ -48,6 +48,12 @@ template <class TS, class TI, class TR> class local_processor;
template <class TS, class TI, class TR> class local_processor_cell_context;
template <class TS, class TI, class TR> class local_processor_contexts;
inline const db::Shapes *subject_idptr () { return (const db::Shapes *) 0; }
inline const db::Shapes *foreign_idptr () { return (const db::Shapes *) 1; }
inline unsigned int subject_idlayer() { return std::numeric_limits<unsigned int>::max (); }
inline unsigned int foreign_idlayer() { return std::numeric_limits<unsigned int>::max () - 1; }
// TODO: move this somewhere else?
template <class TS, class TI>
class DB_PUBLIC shape_interactions
@ -289,6 +295,20 @@ public:
return m_intruder_layers;
}
inline unsigned int actual_intruder_layer (unsigned int l) const
{
if (l == foreign_idlayer () || l == subject_idlayer ()) {
return m_subject_layer;
} else {
return l;
}
}
inline bool is_foreign (unsigned int l) const
{
return l == foreign_idlayer ();
}
tl::Mutex &lock () const
{
return m_lock;
@ -386,7 +406,7 @@ public:
void run_flat (const db::Shapes *subject_shapes, const db::Shapes *intruders, const local_operation<TS, TI, TR> *op, db::Shapes *result_shapes) const;
void run_flat (const db::Shapes *subjects, const std::vector<const db::Shapes *> &intruders, const local_operation<TS, TI, TR> *op, const std::vector<db::Shapes *> &result_shapes) const;
void run_flat (const generic_shape_iterator<TS> &subjects, const std::vector<generic_shape_iterator<TI> > &intruders, const local_operation<TS, TI, TR> *op, const std::vector<db::Shapes *> &result_shapes) const;
void run_flat (const generic_shape_iterator<TS> &subjects, const std::vector<generic_shape_iterator<TI> > &intruders, const std::vector<bool> &foreign, const local_operation<TS, TI, TR> *op, const std::vector<db::Shapes *> &result_shapes) const;
void set_description (const std::string &d)
{

View File

@ -183,13 +183,13 @@ static db::CompoundRegionOperationNode *new_strange_polygons_filter (db::Compoun
static db::CompoundRegionOperationNode *new_smoothed (db::CompoundRegionOperationNode *input, db::Coord d)
{
check_non_null (input, "input");
return new db::CompoundRegionProcessingOperationNode (new db::SmoothingProcessor (d), input, true /*processor is owned*/);
return new db::CompoundRegionProcessingOperationNode (new db::SmoothingProcessor (d), input, true /*processor is owned*/, d);
}
static db::CompoundRegionOperationNode *new_rounded_corners (db::CompoundRegionOperationNode *input, double rinner, double router, unsigned int n)
{
check_non_null (input, "input");
return new db::CompoundRegionProcessingOperationNode (new db::RoundedCornersProcessor (rinner, router, n), input, true /*processor is owned*/);
return new db::CompoundRegionProcessingOperationNode (new db::RoundedCornersProcessor (rinner, router, n), input, true /*processor is owned*/, rinner /*dist adder*/);
}
static db::CompoundRegionOperationNode *new_case (const std::vector<db::CompoundRegionOperationNode *> &inputs)
@ -198,6 +198,12 @@ static db::CompoundRegionOperationNode *new_case (const std::vector<db::Compound
return new db::CompoundRegionLogicalCaseSelectOperationNode (inputs);
}
static db::CompoundRegionOperationNode *new_join (const std::vector<db::CompoundRegionOperationNode *> &inputs)
{
check_non_null (inputs, "inputs");
return new db::CompoundRegionJoinOperationNode (inputs);
}
static db::CompoundRegionOperationNode *new_count_filter (db::CompoundRegionOperationNode *input, bool invert, size_t min_count, size_t max_count)
{
return new db::CompoundRegionCountFilterNode (input, invert, min_count, max_count);
@ -206,7 +212,7 @@ static db::CompoundRegionOperationNode *new_count_filter (db::CompoundRegionOper
static db::CompoundRegionOperationNode *new_corners_as_rectangles (db::CompoundRegionOperationNode *input, double angle_start, double angle_end, db::Coord dim = 1)
{
check_non_null (input, "input");
return new db::CompoundRegionProcessingOperationNode (new db::CornersAsRectangles (angle_start, angle_end, dim), input, true /*processor is owned*/);
return new db::CompoundRegionProcessingOperationNode (new db::CornersAsRectangles (angle_start, angle_end, dim), input, true /*processor is owned*/, dim /*dist adder*/);
}
static db::CompoundRegionOperationNode *new_corners_as_dots (db::CompoundRegionOperationNode *input, double angle_start, double angle_end)
@ -263,7 +269,7 @@ static db::CompoundRegionOperationNode *new_polygon_breaker (db::CompoundRegionO
static db::CompoundRegionOperationNode *new_sized (db::CompoundRegionOperationNode *input, db::Coord dx, db::Coord dy, unsigned int mode)
{
check_non_null (input, "input");
return new db::CompoundRegionProcessingOperationNode (new db::PolygonSizer (dx, dy, mode), input, true /*processor is owned*/);
return new db::CompoundRegionProcessingOperationNode (new db::PolygonSizer (dx, dy, mode), input, true /*processor is owned*/, std::max (0, std::max (dx, dy)) /*dist adder*/);
}
static db::CompoundRegionOperationNode *new_merged (db::CompoundRegionOperationNode *input, bool min_coherence, unsigned int min_wc)
@ -545,6 +551,9 @@ Class<db::CompoundRegionOperationNode> decl_CompoundRegionOperationNode ("db", "
"@param router The outer corner radius."
"@param n The number if points per full circle."
) +
gsi::constructor ("new_join", &new_join, gsi::arg ("inputs"),
"@brief Creates a node that joins the inputs.\n"
) +
gsi::constructor ("new_case", &new_case, gsi::arg ("inputs"),
"@brief Creates a 'switch ladder' (case statement) compound operation node.\n"
"\n"

View File

@ -860,3 +860,49 @@ TEST(15d_JoinAndMerged)
{
run_test15 (_this, true);
}
void run_test16 (tl::TestBase *_this, bool deep)
{
db::Layout ly;
{
std::string fn (tl::testsrc ());
fn += "/testdata/drc/compound_16.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly);
}
db::RegionCheckOptions check_options;
check_options.metrics = db::Projection;
db::DeepShapeStore dss;
db::Region r, r2;
prep_layer (ly, 1, r, dss, deep);
prep_layer (ly, 2, r2, dss, deep);
db::CompoundRegionOperationPrimaryNode *primary = new db::CompoundRegionOperationPrimaryNode ();
db::CompoundRegionOperationForeignNode *foreign = new db::CompoundRegionOperationForeignNode ();
db::CompoundRegionProcessingOperationNode *sized = new db::CompoundRegionProcessingOperationNode (new db::PolygonSizer (600, 600, 2), foreign, true /*processor is owned*/, 600 /*dist adder*/);
db::CompoundRegionGeometricalBoolOperationNode geo_bool (db::CompoundRegionGeometricalBoolOperationNode::And, primary, sized);
db::Region res1 = r.cop_to_region (geo_bool);
unsigned int l1000 = ly.get_layer (db::LayerProperties (1000, 0));
res1.insert_into (&ly, *ly.begin_top_down (), l1000);
CHECKPOINT();
db::compare_layouts (_this, ly, make_au ("16", deep));
}
TEST(16_JoinAndMerged)
{
run_test16 (_this, false);
}
TEST(16d_JoinAndMerged)
{
run_test16 (_this, true);
}

View File

@ -58,7 +58,13 @@ class DRCOpNode
if ! other.is_a?(DRCOpNode)
raise("Second argument to #{op.to_s} must be a DRC expression")
end
DRCOpNodeBool::new(@engine, op, self, other)
if op == :+
a = self.is_a?(DRCOpNodeJoin) ? self.children : [ self ]
b = other.is_a?(DRCOpNodeJoin) ? other.children : [ other ]
return DRCOpNodeJoin::new(@engine, a + b)
else
return DRCOpNodeBool::new(@engine, op, self, other)
end
end
# %DRC%
@ -181,6 +187,35 @@ CODE
DRCOpNodeAreaFilter::new(@engine, self)
end
# %DRC%
# @name count
# @brief Selects a expression result based on the number of (local) shapes
# @synopsis count (in condition)
#
# This operation is used in conditions to select expression results based on their
# count. "count" is used as a method on a expression. It will evaluate the expression locally
# and return the original result if the shape count in the result is matching the condition.
#
# See \drc for more details about comparison specs.
#
# Note that the expression is evaluated locally: for each primary shape, the expression is
# evaluated and the count of the resulting edge, edge pair or polygon set is taken.
# As the primary input will always have a single item (the local shape), using "count" on
# primary does not really make sense. It can be used on derived expressions however.
#
# The following example selects triangles:
#
# @code
# out = in.drc(if_any(corners.count == 3))
# @/code
#
# Note "if_any" which selects the primary shape if the argument evaluates to a non-empty
# result. Without "if_any" three corners are returned for each triangle.
def count
DRCOpNodeCountFilter::new(@engine, self)
end
# %DRC%
# @name perimeter
# @brief Selects the primary shape if the perimeter is meeting the condition
@ -595,6 +630,40 @@ CODE
return DRCOpNodeFilter::new(@engine, self, :new_edges, "edges")
end
# %DRC%
# @name merged
# @brief Returns the merged input polygons, optionally selecting multi-overlap
# @synopsis merged
# @synopsis merged(min_count)
#
# This operation will act on polygons. Without a min_count argument, the merged
# polygons will be returned.
#
# With a min_count argument, the result will include only those parts where more
# than the given number of polygons overlap. As the primary input is merged already,
# it will always contribute as one.
def merged(*args)
@engine._context("merged") do
min_wc = 0
if args.size > 1
raise("merged: Method requires no or one value")
end
if args.size == 1
min_wc = @engine._make_numeric_value(args[0])
min_wc = [ 0, (min_wc - 1).to_i ].max
end
min_coherence = true
DRCOpNodeFilter::new(@engine, self, :new_merged, "merged", min_coherence, min_wc)
end
end
# ....
def sized(*args)
@ -744,6 +813,30 @@ class DRCOpNodeLogicalBool < DRCOpNode
end
class DRCOpNodeJoin < DRCOpNode
attr_accessor :children
def initialize(engine, op, a, b)
super(engine)
self.children = [a, b]
self.description = "Join #{op.to_s}"
end
def dump(indent)
return indent + self.description + "\n" + self.children.collect { |c| c.dump(" " + indent) }.join("\n")
end
def do_create_node(cache)
nodes = self.children.collect { |c| c.create_node(cache) }
if nodes.collect(:result_type).sort.uniq.size > 1
raise("All inputs to the + operator need to have the same type")
end
RBA::CompoundRegionOperationNode::new_join(*nodes)
end
end
class DRCOpNodeBool < DRCOpNode
attr_accessor :children
@ -762,7 +855,6 @@ class DRCOpNodeBool < DRCOpNode
def do_create_node(cache)
bool_op = { :& => RBA::CompoundRegionOperationNode::GeometricalOp::And,
:+ => RBA::CompoundRegionOperationNode::GeometricalOp::Or,
:| => RBA::CompoundRegionOperationNode::GeometricalOp::Or,
:- => RBA::CompoundRegionOperationNode::GeometricalOp::Not,
:^ => RBA::CompoundRegionOperationNode::GeometricalOp::Xor }[self.op]
@ -935,6 +1027,39 @@ class DRCOpNodeWithCompare < DRCOpNode
end
class DRCOpNodeCountFilter < DRCOpNodeWithCompare
attr_accessor :input
attr_accessor :inverted
def initialize(engine, input)
super(engine)
self.input = input
self.inverted = false
self.description = "count"
end
def _description_for_dump
self.inverted ? "count" : "not_count"
end
def do_create_node(cache)
args = [ self.input.create_node(cache), self.inverse ]
args << (self.gt ? @engine._make_numeric_value(self.gt) + 1 : (self.ge ? @engine._make_numeric_value(self.ge) : 0))
if self.lt || self.le
args << self.lt ? @engine._make_numeric_value(self.lt) : @engine._make_numeric_value(self.le) - 1
end
RBA::CompoundRegionOperationNode::new_count_filter(*args)
end
def inverted
res = self.dup
res.inverted = !res.inverted
return res
end
end
class DRCOpNodeAreaFilter < DRCOpNodeWithCompare
attr_accessor :input
@ -953,9 +1078,9 @@ class DRCOpNodeAreaFilter < DRCOpNodeWithCompare
def do_create_node(cache)
args = [ self.input.create_node(cache), self.inverse ]
args << (self.gt ? make_area_value(self.gt) + 1 : (self.ge ? make_area_value(self.ge) : 0))
args << (self.gt ? @engine._make_area_value(self.gt) + 1 : (self.ge ? @engine._make_area_value(self.ge) : 0))
if self.lt || self.le
args << self.lt ? make_area_value(self.lt) : make_area_value(self.le) - 1
args << self.lt ? @engine._make_area_value(self.lt) : @engine._make_area_value(self.le) - 1
end
RBA::CompoundRegionOperationNode::new_area_filter(*args)
end

View File

@ -2246,6 +2246,11 @@ CODE
self._prep_area_value(v)
end
def _make_numeric_value(v)
self._check_numeric(v)
v
end
private
def _make_string(v)

BIN
testdata/drc/compound_16.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/compound_au16.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/compound_au16d.gds vendored Normal file

Binary file not shown.