mirror of https://github.com/KLayout/klayout.git
Hierarchical implementation of polygon vs. edge interact
This commit is contained in:
parent
78617930dd
commit
6e35e80963
|
|
@ -300,117 +300,6 @@ AsIfFlatRegion::filtered (const PolygonFilterBase &filter) const
|
|||
return new_region.release ();
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A helper class for the region to edge interaction functionality
|
||||
*
|
||||
* Note: This special scanner uses pointers to two different objects: edges and polygons.
|
||||
* It uses odd value pointers to indicate pointers to polygons and even value pointers to indicate
|
||||
* pointers to edges.
|
||||
*
|
||||
* There is a special box converter which is able to sort that out as well.
|
||||
*/
|
||||
template <class OutputContainer>
|
||||
class region_to_edge_interaction_filter
|
||||
: public db::box_scanner_receiver<char, size_t>
|
||||
{
|
||||
public:
|
||||
region_to_edge_interaction_filter (OutputContainer &output)
|
||||
: mp_output (&output), m_inverse (false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
region_to_edge_interaction_filter (OutputContainer &output, const db::RegionIterator &polygons)
|
||||
: mp_output (&output), m_inverse (true)
|
||||
{
|
||||
for (db::RegionIterator p = polygons; ! p.at_end (); ++p) {
|
||||
m_seen.insert (&*p);
|
||||
}
|
||||
}
|
||||
|
||||
void add (const char *o1, size_t p1, const char *o2, size_t p2)
|
||||
{
|
||||
const db::Edge *e = 0;
|
||||
const db::Polygon *p = 0;
|
||||
|
||||
// Note: edges have property 0 and have even-valued pointers.
|
||||
// Polygons have property 1 and odd-valued pointers.
|
||||
if (p1 == 0 && p2 == 1) {
|
||||
e = reinterpret_cast<const db::Edge *> (o1);
|
||||
p = reinterpret_cast<const db::Polygon *> (o2 - 1);
|
||||
} else if (p1 == 1 && p2 == 0) {
|
||||
e = reinterpret_cast<const db::Edge *> (o2);
|
||||
p = reinterpret_cast<const db::Polygon *> (o1 - 1);
|
||||
}
|
||||
|
||||
if (e && p && (m_seen.find (p) == m_seen.end ()) != m_inverse) {
|
||||
|
||||
// A polygon and an edge interact if the edge is either inside completely
|
||||
// of at least one edge of the polygon intersects with the edge
|
||||
bool interacts = false;
|
||||
if (p->box ().contains (e->p1 ()) && db::inside_poly (p->begin_edge (), e->p1 ()) >= 0) {
|
||||
interacts = true;
|
||||
} else {
|
||||
for (db::Polygon::polygon_edge_iterator pe = p->begin_edge (); ! pe.at_end () && ! interacts; ++pe) {
|
||||
if ((*pe).intersect (*e)) {
|
||||
interacts = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (interacts) {
|
||||
if (m_inverse) {
|
||||
m_seen.erase (p);
|
||||
} else {
|
||||
m_seen.insert (p);
|
||||
mp_output->insert (*p);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void fill_output ()
|
||||
{
|
||||
for (std::set<const db::Polygon *>::const_iterator p = m_seen.begin (); p != m_seen.end (); ++p) {
|
||||
mp_output->insert (**p);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
OutputContainer *mp_output;
|
||||
std::set<const db::Polygon *> m_seen;
|
||||
bool m_inverse;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A special box converter that splits the pointers into polygon and edge pointers
|
||||
*/
|
||||
struct EdgeOrRegionBoxConverter
|
||||
{
|
||||
typedef db::Box box_type;
|
||||
|
||||
db::Box operator() (const char &c) const
|
||||
{
|
||||
// Note: edges have property 0 and have even-valued pointers.
|
||||
// Polygons have property 1 and odd-valued pointers.
|
||||
const char *cp = &c;
|
||||
if ((size_t (cp) & 1) == 1) {
|
||||
// it's a polygon
|
||||
return (reinterpret_cast<const db::Polygon *> (cp - 1))->box ();
|
||||
} else {
|
||||
// it's an edge
|
||||
const db::Edge *e = reinterpret_cast<const db::Edge *> (cp);
|
||||
return db::Box (e->p1 (), e->p2 ());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse) const
|
||||
{
|
||||
|
|
@ -424,30 +313,31 @@ AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse)
|
|||
return clone ();
|
||||
}
|
||||
|
||||
db::box_scanner<char, size_t> scanner (report_progress (), progress_desc ());
|
||||
scanner.reserve (size () + other.size ());
|
||||
db::box_scanner2<db::Polygon, size_t, db::Edge, size_t> scanner (report_progress (), progress_desc ());
|
||||
scanner.reserve1 (size ());
|
||||
scanner.reserve2 (other.size ());
|
||||
|
||||
std::auto_ptr<FlatRegion> output (new FlatRegion (false));
|
||||
region_to_edge_interaction_filter<Shapes> filter (output->raw_polygons (), inverse);
|
||||
|
||||
AddressablePolygonDelivery p (begin_merged (), has_valid_merged_polygons ());
|
||||
|
||||
for ( ; ! p.at_end (); ++p) {
|
||||
scanner.insert ((char *) p.operator-> () + 1, 1);
|
||||
scanner.insert1 (p.operator-> (), 0);
|
||||
if (inverse) {
|
||||
filter.preset (p.operator-> ());
|
||||
}
|
||||
}
|
||||
|
||||
AddressableEdgeDelivery e (other.addressable_edges ());
|
||||
|
||||
for ( ; ! e.at_end (); ++e) {
|
||||
scanner.insert ((char *) e.operator-> (), 0);
|
||||
scanner.insert2 (e.operator-> (), 0);
|
||||
}
|
||||
|
||||
std::auto_ptr<FlatRegion> output (new FlatRegion (false));
|
||||
EdgeOrRegionBoxConverter bc;
|
||||
scanner.process (filter, 1, db::box_convert<db::Polygon> (), db::box_convert<db::Edge> ());
|
||||
|
||||
if (! inverse) {
|
||||
region_to_edge_interaction_filter<Shapes> filter (output->raw_polygons ());
|
||||
scanner.process (filter, 1, bc);
|
||||
} else {
|
||||
region_to_edge_interaction_filter<Shapes> filter (output->raw_polygons (), RegionIterator (begin_merged ()));
|
||||
scanner.process (filter, 1, bc);
|
||||
if (inverse) {
|
||||
filter.fill_output ();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,9 +27,75 @@
|
|||
#include "dbCommon.h"
|
||||
|
||||
#include "dbRegionDelegate.h"
|
||||
#include "dbPolygon.h"
|
||||
#include "dbEdge.h"
|
||||
#include "dbBoxScanner.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace db {
|
||||
|
||||
/**
|
||||
* @brief A helper class for the region to edge interaction functionality
|
||||
*/
|
||||
template <class OutputContainer>
|
||||
class DB_PUBLIC region_to_edge_interaction_filter
|
||||
: public db::box_scanner_receiver2<db::Polygon, size_t, db::Edge, size_t>
|
||||
{
|
||||
public:
|
||||
region_to_edge_interaction_filter (OutputContainer &output, bool inverse)
|
||||
: mp_output (&output), m_inverse (inverse)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void preset (const db::Polygon *poly)
|
||||
{
|
||||
m_seen.insert (poly);
|
||||
}
|
||||
|
||||
void add (const db::Polygon *p, size_t, const db::Edge *e, size_t)
|
||||
{
|
||||
if ((m_seen.find (p) == m_seen.end ()) != m_inverse) {
|
||||
|
||||
// A polygon and an edge interact if the edge is either inside completely
|
||||
// of at least one edge of the polygon intersects with the edge
|
||||
bool interacts = false;
|
||||
if (p->box ().contains (e->p1 ()) && db::inside_poly (p->begin_edge (), e->p1 ()) >= 0) {
|
||||
interacts = true;
|
||||
} else {
|
||||
for (db::Polygon::polygon_edge_iterator pe = p->begin_edge (); ! pe.at_end () && ! interacts; ++pe) {
|
||||
if ((*pe).intersect (*e)) {
|
||||
interacts = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (interacts) {
|
||||
if (m_inverse) {
|
||||
m_seen.erase (p);
|
||||
} else {
|
||||
m_seen.insert (p);
|
||||
mp_output->insert (*p);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void fill_output ()
|
||||
{
|
||||
for (std::set<const db::Polygon *>::const_iterator p = m_seen.begin (); p != m_seen.end (); ++p) {
|
||||
mp_output->insert (**p);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
OutputContainer *mp_output;
|
||||
std::set<const db::Polygon *> m_seen;
|
||||
bool m_inverse;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Provides default flat implementations
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1328,11 +1328,93 @@ private:
|
|||
mutable db::EdgeProcessor m_ep;
|
||||
};
|
||||
|
||||
struct ResultInserter
|
||||
{
|
||||
ResultInserter (db::Layout *layout, std::unordered_set<db::PolygonRef> &result)
|
||||
: mp_layout (layout), mp_result (&result)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void insert (const db::Polygon &p)
|
||||
{
|
||||
(*mp_result).insert (db::PolygonRef (p, mp_layout->shape_repository ()));
|
||||
}
|
||||
|
||||
private:
|
||||
db::Layout *mp_layout;
|
||||
std::unordered_set<db::PolygonRef> *mp_result;
|
||||
};
|
||||
|
||||
class InteractingWithEdgeLocalOperation
|
||||
: public local_operation<db::PolygonRef, db::Edge, db::PolygonRef>
|
||||
{
|
||||
public:
|
||||
InteractingWithEdgeLocalOperation (bool inverse)
|
||||
: m_inverse (inverse)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual void compute_local (db::Layout *layout, const shape_interactions<db::PolygonRef, db::Edge> &interactions, std::unordered_set<db::PolygonRef> &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const
|
||||
{
|
||||
m_scanner.clear ();
|
||||
|
||||
ResultInserter inserter (layout, result);
|
||||
region_to_edge_interaction_filter<ResultInserter> filter (inserter, m_inverse);
|
||||
|
||||
for (shape_interactions<db::PolygonRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
for (shape_interactions<db::PolygonRef, db::Edge>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
|
||||
m_scanner.insert2 (& interactions.intruder_shape (*j), 0);
|
||||
}
|
||||
}
|
||||
|
||||
std::list<db::Polygon> heap;
|
||||
for (shape_interactions<db::PolygonRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
||||
|
||||
const db::PolygonRef &subject = interactions.subject_shape (i->first);
|
||||
heap.push_back (subject.obj ().transformed (subject.trans ()));
|
||||
|
||||
m_scanner.insert1 (&heap.back (), 0);
|
||||
if (m_inverse) {
|
||||
filter.preset (&heap.back ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
m_scanner.process (filter, 1, db::box_convert<db::Polygon> (), db::box_convert<db::Edge> ());
|
||||
if (m_inverse) {
|
||||
filter.fill_output ();
|
||||
}
|
||||
}
|
||||
|
||||
virtual on_empty_intruder_mode on_empty_intruder_hint () const
|
||||
{
|
||||
if (!m_inverse) {
|
||||
return Drop;
|
||||
} else {
|
||||
return Copy;
|
||||
}
|
||||
}
|
||||
|
||||
virtual std::string description () const
|
||||
{
|
||||
return tl::to_string (tr ("Select regions by their geometric relation (interacting, inside, outside ..)"));
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_inverse;
|
||||
mutable db::box_scanner2<db::Polygon, size_t, db::Edge, size_t> m_scanner;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const
|
||||
{
|
||||
// with these flag set to true, the resulting polygons are broken again.
|
||||
bool split_after = false;
|
||||
|
||||
const db::DeepRegion *other_deep = dynamic_cast<const db::DeepRegion *> (other.delegate ());
|
||||
if (! other_deep) {
|
||||
return db::AsIfFlatRegion::selected_interacting_generic (other, mode, touching, inverse);
|
||||
|
|
@ -1347,24 +1429,52 @@ DeepRegion::selected_interacting_generic (const Region &other, int mode, bool to
|
|||
db::local_processor<db::PolygonRef, db::PolygonRef, db::PolygonRef> proc (const_cast<db::Layout *> (&m_deep_layer.layout ()), const_cast<db::Cell *> (&m_deep_layer.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ());
|
||||
proc.set_base_verbosity (base_verbosity ());
|
||||
proc.set_threads (m_deep_layer.store ()->threads ());
|
||||
#if defined(SPLIT )
|
||||
// with these settings, the resulting polygons are broken again ...
|
||||
proc.set_area_ratio (m_deep_layer.store ()->max_area_ratio ());
|
||||
proc.set_max_vertex_count (m_deep_layer.store ()->max_vertex_count ());
|
||||
#endif
|
||||
if (split_after) {
|
||||
proc.set_area_ratio (m_deep_layer.store ()->max_area_ratio ());
|
||||
proc.set_max_vertex_count (m_deep_layer.store ()->max_vertex_count ());
|
||||
}
|
||||
|
||||
proc.run (&op, m_merged_polygons.layer (), other_deep->merged_deep_layer ().layer (), dl_out.layer ());
|
||||
proc.run (&op, m_merged_polygons.layer (), other_deep->deep_layer ().layer (), dl_out.layer ());
|
||||
|
||||
db::DeepRegion *res = new db::DeepRegion (dl_out);
|
||||
res->set_is_merged (true);
|
||||
if (! split_after) {
|
||||
res->set_is_merged (true);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::selected_interacting_generic (const Edges &other, bool inverse) const
|
||||
{
|
||||
// TODO: implement hierarchically
|
||||
return db::AsIfFlatRegion::selected_interacting_generic (other, inverse);
|
||||
// with these flag set to true, the resulting polygons are broken again.
|
||||
bool split_after = false;
|
||||
|
||||
const db::DeepEdges *other_deep = dynamic_cast<const db::DeepEdges *> (other.delegate ());
|
||||
if (! other_deep) {
|
||||
return db::AsIfFlatRegion::selected_interacting_generic (other, inverse);
|
||||
}
|
||||
|
||||
ensure_merged_polygons_valid ();
|
||||
|
||||
DeepLayer dl_out (m_deep_layer.derived ());
|
||||
|
||||
db::InteractingWithEdgeLocalOperation op (inverse);
|
||||
|
||||
db::local_processor<db::PolygonRef, db::Edge, db::PolygonRef> proc (const_cast<db::Layout *> (&m_deep_layer.layout ()), const_cast<db::Cell *> (&m_deep_layer.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ());
|
||||
proc.set_base_verbosity (base_verbosity ());
|
||||
proc.set_threads (m_deep_layer.store ()->threads ());
|
||||
if (split_after) {
|
||||
proc.set_area_ratio (m_deep_layer.store ()->max_area_ratio ());
|
||||
proc.set_max_vertex_count (m_deep_layer.store ()->max_vertex_count ());
|
||||
}
|
||||
|
||||
proc.run (&op, m_merged_polygons.layer (), other_deep->deep_layer ().layer (), dl_out.layer ());
|
||||
|
||||
db::DeepRegion *res = new db::DeepRegion (dl_out);
|
||||
if (! split_after) {
|
||||
res->set_is_merged (true);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -237,6 +237,30 @@ private:
|
|||
Trans m_trans;
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Safe enlargement of a box
|
||||
* Boxes must not vanish when augmented for overlapping queries. Hence we must not make
|
||||
* the boxes shrinked too much on enlarge.
|
||||
*/
|
||||
db::Box safe_box_enlarged (const db::Box &box, db::Coord dx, db::Coord dy)
|
||||
{
|
||||
if (box.empty ()) {
|
||||
return box;
|
||||
} else {
|
||||
db::Coord w2 = db::Coord (box.width () / 2);
|
||||
db::Coord h2 = db::Coord (box.height () / 2);
|
||||
if (dx + w2 < 0) {
|
||||
dx = -w2;
|
||||
}
|
||||
if (dy + h2 < 0) {
|
||||
dy = -h2;
|
||||
}
|
||||
return box.enlarged (db::Vector (dx, dy));
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// LocalProcessorCellContext implementation
|
||||
|
||||
|
|
@ -723,7 +747,7 @@ public:
|
|||
// Find all instance array members that potentially interact with the shape and use
|
||||
// add_shapes_from_intruder_inst on them
|
||||
db::Box ref_box = db::box_convert<TS> () (*ref);
|
||||
for (db::CellInstArray::iterator n = inst->begin_touching (ref_box.enlarged (db::Vector (m_dist - 1, m_dist - 1)), inst_bc); !n.at_end (); ++n) {
|
||||
for (db::CellInstArray::iterator n = inst->begin_touching (safe_box_enlarged (ref_box, m_dist - 1, m_dist - 1), inst_bc); !n.at_end (); ++n) {
|
||||
db::ICplxTrans tn = inst->complex_trans (*n);
|
||||
db::Box region = ref_box.transformed (tn.inverted ()).enlarged (db::Vector (m_dist, m_dist)) & intruder_cell.bbox (m_intruder_layer).enlarged (db::Vector (m_dist, m_dist));
|
||||
if (! region.empty ()) {
|
||||
|
|
@ -794,7 +818,7 @@ instances_interact (const db::Layout *layout1, const db::CellInstArray *inst1, u
|
|||
|
||||
// TODO: in some cases, it may be possible to optimize this for arrays
|
||||
|
||||
for (db::CellInstArray::iterator k = inst2->begin_touching (ibox1.enlarged (db::Vector (-1, -1)), inst2_bc); ! k.at_end (); ++k) {
|
||||
for (db::CellInstArray::iterator k = inst2->begin_touching (safe_box_enlarged (ibox1, -1, -1), inst2_bc); ! k.at_end (); ++k) {
|
||||
|
||||
if (inst1 == inst2 && *n == *k) {
|
||||
// skip self-interactions - this is handled inside the cell
|
||||
|
|
@ -887,7 +911,7 @@ instance_shape_interacts (const db::Layout *layout, const db::CellInstArray *ins
|
|||
db::box_convert <db::CellInst, true> inst_bc (*layout, layer);
|
||||
db::Box rbox = db::box_convert<T> () (ref);
|
||||
|
||||
for (db::CellInstArray::iterator n = inst->begin_touching (rbox.enlarged (db::Vector (dist - 1, dist - 1)), inst_bc); ! n.at_end (); ++n) {
|
||||
for (db::CellInstArray::iterator n = inst->begin_touching (safe_box_enlarged (rbox, dist - 1, dist - 1), inst_bc); ! n.at_end (); ++n) {
|
||||
|
||||
db::ICplxTrans tn = inst->complex_trans (*n);
|
||||
db::Box cbox = (tn * cell.bbox (layer)).enlarged (db::Vector (dist, dist)) & rbox.enlarged (db::Vector (dist, dist));
|
||||
|
|
@ -1293,7 +1317,7 @@ void local_processor<TS, TI, TR>::compute_contexts (local_processor_contexts<TS,
|
|||
// TODO: in some cases, it may be possible to optimize this for arrays
|
||||
|
||||
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 (nbox.enlarged (db::Vector (-1, -1)), inst_bcii); ! k.at_end (); ++k) {
|
||||
for (db::CellInstArray::iterator k = (*j)->begin_touching (safe_box_enlarged (nbox, -1, -1), inst_bcii); ! k.at_end (); ++k) {
|
||||
db::ICplxTrans tk = (*j)->complex_trans (*k);
|
||||
// NOTE: no self-interactions
|
||||
if (i->first != *j || tn != tk) {
|
||||
|
|
@ -1568,7 +1592,20 @@ local_processor<TS, TI, TR>::compute_local_cell (const db::local_processor_conte
|
|||
|
||||
}
|
||||
|
||||
op->compute_local (mp_subject_layout, interactions, result, m_max_vertex_count, m_area_ratio);
|
||||
if (interactions.begin () != interactions.end ()) {
|
||||
|
||||
if (interactions.begin_intruders () == interactions.end_intruders ()) {
|
||||
|
||||
typename local_operation<TS, TI, TR>::on_empty_intruder_mode eh = op->on_empty_intruder_hint ();
|
||||
if (eh == local_operation<TS, TI, TR>::Drop) {
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
op->compute_local (mp_subject_layout, interactions, result, m_max_vertex_count, m_area_ratio);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
template class DB_PUBLIC local_processor<db::PolygonRef, db::PolygonRef, db::PolygonRef>;
|
||||
|
|
|
|||
|
|
@ -54,6 +54,8 @@ public:
|
|||
typedef std::unordered_map<unsigned int, std::vector<unsigned int> > container;
|
||||
typedef container::const_iterator iterator;
|
||||
typedef container::value_type::second_type::const_iterator iterator2;
|
||||
typedef typename std::unordered_map<unsigned int, TS>::const_iterator subject_iterator;
|
||||
typedef typename std::unordered_map<unsigned int, TI>::const_iterator intruder_iterator;
|
||||
|
||||
shape_interactions ();
|
||||
|
||||
|
|
@ -67,6 +69,26 @@ public:
|
|||
return m_interactions.end ();
|
||||
}
|
||||
|
||||
subject_iterator begin_subjects () const
|
||||
{
|
||||
return m_subject_shapes.begin ();
|
||||
}
|
||||
|
||||
subject_iterator end_subjects () const
|
||||
{
|
||||
return m_subject_shapes.end ();
|
||||
}
|
||||
|
||||
intruder_iterator begin_intruders () const
|
||||
{
|
||||
return m_intruder_shapes.begin ();
|
||||
}
|
||||
|
||||
intruder_iterator end_intruders () const
|
||||
{
|
||||
return m_intruder_shapes.end ();
|
||||
}
|
||||
|
||||
bool has_intruder_shape_id (unsigned int id) const;
|
||||
bool has_subject_shape_id (unsigned int id) const;
|
||||
void add_intruder_shape (unsigned int id, const TI &shape);
|
||||
|
|
|
|||
|
|
@ -781,31 +781,50 @@ TEST(14_Interacting)
|
|||
db::Region r2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss);
|
||||
db::Region r6 (db::RecursiveShapeIterator (ly, top_cell, l6), dss);
|
||||
|
||||
db::Layout target;
|
||||
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
|
||||
{
|
||||
db::Layout target;
|
||||
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r2.selected_interacting (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r2.selected_not_interacting (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), r2.selected_inside (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), r2.selected_not_inside (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), r2.selected_outside (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (15, 0)), r2.selected_not_outside (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (16, 0)), r2.selected_overlapping (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (17, 0)), r2.selected_not_overlapping (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r2.selected_interacting (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r2.selected_not_interacting (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), r2.selected_inside (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), r2.selected_not_inside (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (14, 0)), r2.selected_outside (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (15, 0)), r2.selected_not_outside (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (16, 0)), r2.selected_overlapping (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (17, 0)), r2.selected_not_overlapping (r1));
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), r6.selected_interacting (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), r6.selected_not_interacting (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (22, 0)), r6.selected_inside (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (23, 0)), r6.selected_not_inside (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (24, 0)), r6.selected_outside (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (25, 0)), r6.selected_not_outside (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (26, 0)), r6.selected_overlapping (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (27, 0)), r6.selected_not_overlapping (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), r6.selected_interacting (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), r6.selected_not_interacting (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (22, 0)), r6.selected_inside (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (23, 0)), r6.selected_not_inside (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (24, 0)), r6.selected_outside (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (25, 0)), r6.selected_not_outside (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (26, 0)), r6.selected_overlapping (r1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (27, 0)), r6.selected_not_overlapping (r1));
|
||||
|
||||
EXPECT_EQ (r2.selected_interacting (r1).is_merged (), true);
|
||||
EXPECT_EQ (r2.selected_interacting (r1).is_merged (), true);
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au14.gds");
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au14a.gds");
|
||||
}
|
||||
|
||||
db::Edges r1e = r1.edges ();
|
||||
|
||||
{
|
||||
db::Layout target;
|
||||
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r6);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r1e);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), r6.selected_interacting (r1e));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), r6.selected_not_interacting (r1e));
|
||||
|
||||
EXPECT_EQ (r6.selected_interacting (r1e).is_merged (), true);
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au14b.gds");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(15_Filtered)
|
||||
|
|
|
|||
Loading…
Reference in New Issue