mirror of https://github.com/KLayout/klayout.git
WIP: a new concept for complex DRC - 'foreign' subjects
This commit is contained in:
parent
6dd190e3af
commit
9812ff7901
|
|
@ -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 ();
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
is.push_back (generic_shape_iterator<TI> (intruders));
|
||||
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) {
|
||||
is.push_back (generic_shape_iterator<TI> (*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,20 +2138,36 @@ 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);
|
||||
}
|
||||
|
||||
addressable_shape_delivery<TI> ii ((*il).confined (common_box, true));
|
||||
for (; !ii.at_end (); ++ii) {
|
||||
scanner.insert2 (ii.operator-> (), interactions.next_id ());
|
||||
}
|
||||
if (*il == subjects) {
|
||||
|
||||
scanner.process (rec, dist, db::box_convert<TS> (), db::box_convert<TI> ());
|
||||
// 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 ());
|
||||
}
|
||||
|
||||
scanner.process (rec, dist, db::box_convert<TS> (), db::box_convert<TI> ());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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,23 +2207,43 @@ 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);
|
||||
}
|
||||
for (; !ii.at_end (); ++ii) {
|
||||
scanner.insert2 (ii.operator-> (), interactions.next_id ());
|
||||
}
|
||||
|
||||
scanner.process (rec, dist, db::box_convert<TS> (), db::box_convert<TI> ());
|
||||
|
||||
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 ());
|
||||
}
|
||||
|
||||
scanner.process (rec, dist, db::box_convert<TS> (), db::box_convert<TI> ());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue