Merge pull request #1188 from KLayout/wip

Wip
This commit is contained in:
Matthias Köfferlein 2022-11-25 07:49:59 +01:00 committed by GitHub
commit 10a8d719b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 796 additions and 94 deletions

View File

@ -1037,7 +1037,11 @@ AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons,
{
#if defined(USE_LOCAL_PROCESSOR)
db::RegionIterator polygons (begin_merged ());
bool needs_merged_primary = different_polygons || options.needs_merged ();
needs_merged_primary = true; // @@@
db::RegionIterator polygons (needs_merged_primary ? begin_merged () : begin ());
bool primary_is_merged = ! merged_semantics () || needs_merged_primary || is_merged ();
EdgeRelationFilter check (rel, d, options.metrics);
check.set_include_zero (false);
@ -1059,9 +1063,12 @@ AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons,
if (other == subject_regionptr () || other == foreign_regionptr ()) {
foreign.push_back (other == foreign_regionptr ());
others.push_back (begin_merged ());
other_is_merged = primary_is_merged;
} else {
foreign.push_back (false);
if (options.whole_edges) {
if (! other->merged_semantics ()) {
other_is_merged = true;
} else if (options.whole_edges) {
// NOTE: whole edges needs both inputs merged
others.push_back (other->begin_merged ());
other_is_merged = true;
@ -1072,7 +1079,7 @@ AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons,
has_other = true;
}
db::check_local_operation<db::Polygon, db::Polygon> op (check, different_polygons, has_other, other_is_merged, options);
db::check_local_operation<db::Polygon, db::Polygon> op (check, different_polygons, primary_is_merged, has_other, other_is_merged, options);
std::unique_ptr<FlatEdgePairs> output (new FlatEdgePairs ());
std::vector<db::Shapes *> results;

View File

@ -45,6 +45,26 @@ db::Trans OrientationReducer::reduce (const db::Trans &trans) const
// ------------------------------------------------------------------------------------------
db::ICplxTrans OrthogonalTransformationReducer::reduce (const db::ICplxTrans &trans) const
{
if (trans.is_ortho ()) {
return db::ICplxTrans ();
} else {
db::ICplxTrans res;
double a = trans.angle ();
double a90 = floor (a / 90.0 + 0.5) * 90.0;
res.angle (a - a90);
return res;
}
}
db::Trans OrthogonalTransformationReducer::reduce (const db::Trans &trans) const
{
return db::Trans ();
}
// ------------------------------------------------------------------------------------------
db::ICplxTrans MagnificationReducer::reduce (const db::ICplxTrans &trans) const
{
return db::ICplxTrans (trans.mag ());

View File

@ -69,6 +69,16 @@ struct DB_PUBLIC OrientationReducer
db::Trans reduce (const db::Trans &trans) const;
};
/**
* @brief A reducer for invariance against orthogonal transformations (rotations of multiple of 90 degree)
*/
struct DB_PUBLIC OrthogonalTransformationReducer
: public TransformationReducer
{
db::ICplxTrans reduce (const db::ICplxTrans &trans) const;
db::Trans reduce (const db::Trans &trans) const;
};
/**
* @brief A magnification reducer
*

View File

@ -1555,10 +1555,13 @@ CompoundRegionCheckOperationNode::CompoundRegionCheckOperationNode (CompoundRegi
m_check.set_max_projection (options.max_projection);
}
CompoundRegionCheckOperationNode::CompoundRegionCheckOperationNode (CompoundRegionOperationNode * /*input*/, CompoundRegionOperationNode *other, db::edge_relation_type rel, bool different_polygons, db::Coord d, const db::RegionCheckOptions &options)
CompoundRegionCheckOperationNode::CompoundRegionCheckOperationNode (CompoundRegionOperationNode *input, CompoundRegionOperationNode *other, db::edge_relation_type rel, bool different_polygons, db::Coord d, const db::RegionCheckOptions &options)
: CompoundRegionMultiInputOperationNode (other), m_check (rel, d, options.metrics), m_different_polygons (different_polygons), m_options (options)
{
tl_assert (input == 0); // input is a dummy parameter
m_has_other = other->has_external_inputs ();
// @@@ needs a concept to deal with merged/non-merged inputs
m_is_other_merged = other->is_merged ();
set_description ("check");
@ -1585,7 +1588,9 @@ CompoundRegionCheckOperationNode::computed_dist () const
void
CompoundRegionCheckOperationNode::do_compute_local (CompoundRegionOperationCache * /*cache*/, 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
{
db::check_local_operation<db::Polygon, db::Polygon> op (m_check, m_different_polygons, m_has_other, m_is_other_merged, m_options);
// @@@ needs a concept to deal with merged/non-merged primary
bool is_merged = true;
db::check_local_operation<db::Polygon, db::Polygon> op (m_check, m_different_polygons, is_merged, m_has_other, m_is_other_merged, m_options);
tl_assert (results.size () == 1);
if (results.front ().empty ()) {
@ -1601,7 +1606,9 @@ CompoundRegionCheckOperationNode::do_compute_local (CompoundRegionOperationCache
void
CompoundRegionCheckOperationNode::do_compute_local (CompoundRegionOperationCache * /*cache*/, 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
{
db::check_local_operation<db::PolygonRef, db::PolygonRef> op (m_check, m_different_polygons, m_has_other, m_is_other_merged, m_options);
// @@@ needs a concept to deal with merged/non-merged primary
bool is_merged = true;
db::check_local_operation<db::PolygonRef, db::PolygonRef> op (m_check, m_different_polygons, is_merged, m_has_other, m_is_other_merged, m_options);
tl_assert (results.size () == 1);
if (results.front ().empty ()) {

View File

@ -1647,16 +1647,23 @@ DeepRegion::run_check (db::edge_relation_type rel, bool different_polygons, cons
unsigned int other_layer = 0;
bool other_is_merged = true;
bool needs_merged_primary = different_polygons || options.needs_merged ();
bool primary_is_merged = ! merged_semantics () || needs_merged_primary || is_merged ();
if (other == subject_regionptr ()) {
other_layer = subject_idlayer ();
other_is_merged = primary_is_merged;
} else if (other == foreign_regionptr ()) {
other_layer = foreign_idlayer ();
other_is_merged = primary_is_merged;
} else {
other_deep = dynamic_cast<const db::DeepRegion *> (other->delegate ());
if (! other_deep) {
return db::AsIfFlatRegion::run_check (rel, different_polygons, other, d, options);
}
if (options.whole_edges) {
if (! other->merged_semantics ()) {
other_is_merged = true;
} else if (options.whole_edges) {
// NOTE: whole edges needs both inputs merged
other_layer = other_deep->merged_deep_layer ().layer ();
other_is_merged = true;
@ -1666,7 +1673,7 @@ DeepRegion::run_check (db::edge_relation_type rel, bool different_polygons, cons
}
}
const db::DeepLayer &polygons = merged_deep_layer ();
const db::DeepLayer &polygons = needs_merged_primary ? merged_deep_layer () : deep_layer ();
EdgeRelationFilter check (rel, d, options.metrics);
check.set_include_zero (false);
@ -1677,7 +1684,7 @@ DeepRegion::run_check (db::edge_relation_type rel, bool different_polygons, cons
std::unique_ptr<db::DeepEdgePairs> res (new db::DeepEdgePairs (polygons.derived ()));
db::CheckLocalOperation op (check, different_polygons, other_deep != 0, other_is_merged, options);
db::CheckLocalOperation op (check, different_polygons, primary_is_merged, other_deep != 0, other_is_merged, options);
db::local_processor<db::PolygonRef, db::PolygonRef, db::EdgePair> proc (const_cast<db::Layout *> (&polygons.layout ()),
const_cast<db::Cell *> (&polygons.initial_cell ()),

View File

@ -274,6 +274,73 @@ EdgeOrientationFilter::selected (const db::Edge &edge) const
}
}
// -------------------------------------------------------------------------------------------------------------
// SpecialEdgeOrientationFilter implementation
SpecialEdgeOrientationFilter::SpecialEdgeOrientationFilter (FilterType type, bool inverse)
: m_type (type), m_inverse (inverse)
{
// .. nothing yet ..
}
static EdgeAngleChecker s_ortho_checkers [] = {
EdgeAngleChecker (0.0, true, 0.0, true),
EdgeAngleChecker (90.0, true, 90.0, true)
};
static EdgeAngleChecker s_diagonal_checkers [] = {
EdgeAngleChecker (-45.0, true, -45.0, true),
EdgeAngleChecker (45.0, true, 45.0, true)
};
static EdgeAngleChecker s_orthodiagonal_checkers [] = {
EdgeAngleChecker (-45.0, true, -45.0, true),
EdgeAngleChecker (0.0, true, 0.0, true),
EdgeAngleChecker (45.0, true, 45.0, true),
EdgeAngleChecker (90.0, true, 90.0, true)
};
bool
SpecialEdgeOrientationFilter::selected (const db::Edge &edge) const
{
const EdgeAngleChecker *eb, *ee;
switch (m_type) {
case Ortho:
eb = s_ortho_checkers;
ee = s_ortho_checkers + sizeof (s_ortho_checkers) / sizeof (s_ortho_checkers [0]);
break;
case Diagonal:
eb = s_diagonal_checkers;
ee = s_diagonal_checkers + sizeof (s_diagonal_checkers) / sizeof (s_diagonal_checkers [0]);
break;
case OrthoDiagonal:
default:
eb = s_orthodiagonal_checkers;
ee = s_orthodiagonal_checkers + sizeof (s_orthodiagonal_checkers) / sizeof (s_orthodiagonal_checkers [0]);
break;
}
db::Vector en, ev;
en = db::Vector (edge.ortho_length (), 0);
// NOTE: this edge normalization confines the angle to a range between (-90 .. 90] (-90 excluded).
// A horizontal edge has 0 degree, a vertical one has 90 degree.
if (edge.dx () < 0 || (edge.dx () == 0 && edge.dy () < 0)) {
ev = -edge.d ();
} else {
ev = edge.d ();
}
for (auto ec = eb; ec != ee; ++ec) {
if ((*ec) (en, ev)) {
return ! m_inverse;
}
}
return m_inverse;
}
// -------------------------------------------------------------------------------------------------------------
// Edge to Edge relation implementation

View File

@ -246,6 +246,76 @@ private:
EdgeAngleChecker m_checker;
};
/**
* @brief An edge orientation filter for use with Edges::filter or Edges::filtered
*
* This filter renders edges with special orientations.
*/
struct DB_PUBLIC SpecialEdgeOrientationFilter
: public EdgeFilterBase
{
enum FilterType {
Ortho = 0, // 0 and 90 degree
Diagonal = 1, // -45 and 45 degree
OrthoDiagonal = 2 // both Ortho and Diagonal
};
/**
* @brief Constructor
*
* @param type The type of filter
*/
SpecialEdgeOrientationFilter (FilterType type, bool inverse);
/**
* @brief Returns true if the edge orientation matches the criterion
*/
virtual bool selected (const db::Edge &edge) const;
/**
* @brief Returns true if all edge orientations match the criterion
*/
virtual bool selected (const std::unordered_set<db::Edge> &edges) const
{
for (std::unordered_set<db::Edge>::const_iterator e = edges.begin (); e != edges.end (); ++e) {
if (! selected (*e)) {
return false;
}
}
return true;
}
/**
* @brief This filter is not isotropic
*/
virtual const TransformationReducer *vars () const
{
return &m_vars;
}
/**
* @brief Requires merged input
*/
virtual bool requires_raw_input () const
{
return false;
}
/**
* @brief Wants to build variants
*/
virtual bool wants_variants () const
{
return true;
}
private:
FilterType m_type;
bool m_inverse;
db::OrthogonalTransformationReducer m_vars;
};
/**
* @brief A predicate defining edge a interacts with b
*/

View File

@ -252,8 +252,15 @@ namespace std
h = hfunc_coord (o.bgn_ext (), h);
h = hfunc_coord (o.end_ext (), h);
h = hfunc_coord (o.width (), h);
// NOTE: using too many points for the hash function just slows down the code.
unsigned int n = 20;
for (typename db::path<C>::iterator p = o.begin (); p != o.end (); ++p) {
h = hfunc (*p, h);
if (--n == 0) {
h = hfunc (o.points (), h);
break;
} else {
h = hfunc (*p, h);
}
}
return h;
}
@ -280,8 +287,15 @@ namespace std
template <class C>
size_t hfunc (const db::polygon_contour<C> &o, size_t h)
{
// NOTE: using too many points for the hash function just slows down the code.
unsigned int n = 20;
for (typename db::polygon_contour<C>::simple_iterator i = o.begin (); i != o.end (); ++i) {
h = hfunc (*i, h);
if (--n == 0) {
h = hfunc (o.size (), h);
break;
} else {
h = hfunc (*i, h);
}
}
return h;
}
@ -309,8 +323,15 @@ namespace std
size_t hfunc (const db::polygon<C> &o, size_t h)
{
h = hfunc (o.hull (), h);
// NOTE: using too many points for the hash function just slows down the code.
unsigned int n = 20;
for (size_t i = 0; i < o.holes (); ++i) {
h = hfunc (o.hole (int (i)), h);
if (--n == 0) {
h = hfunc (o.holes (), h);
break;
} else {
h = hfunc (o.hole (int (i)), h);
}
}
return h;
}

View File

@ -189,15 +189,22 @@ public:
typedef typename Ref::shape_type shape_type;
typedef typename Ref::trans_type ref_trans_type;
shape_reference_translator_with_trans_from_shape_ref (db::Layout *target_layout, const Trans &trans)
: mp_layout (target_layout), m_trans (trans), m_ref_trans (trans), m_bare_trans (Trans (m_ref_trans.inverted ()) * trans)
shape_reference_translator_with_trans_from_shape_ref (db::Layout *target_layout)
: mp_layout (target_layout)
{
// .. nothing yet ..
}
void set_trans (const Trans &trans)
{
m_trans = trans;
m_ref_trans = ref_trans_type (trans);
m_bare_trans = Trans (m_ref_trans.inverted ()) * trans;
}
Ref operator() (const Ref &ref) const
{
typename std::unordered_map<const shape_type *, std::pair<const shape_type *, ref_trans_type> >::const_iterator m = m_cache.find (ref.ptr ());
auto m = m_cache.find (std::make_pair (ref.ptr (), m_bare_trans));
if (m != m_cache.end ()) {
return Ref (m->second.first, ref_trans_type (m_trans * Trans (ref.trans ())) * m->second.second);
@ -214,7 +221,7 @@ public:
ptr = mp_layout->shape_repository ().repository (typename shape_type::tag ()).insert (sh);
}
m_cache[ref.ptr ()] = std::make_pair (ptr, red_trans);
m_cache[std::make_pair (ref.ptr (), m_bare_trans)] = std::make_pair (ptr, red_trans);
return Ref (ptr, ref_trans_type (m_trans * Trans (ref.trans ())) * red_trans);
@ -226,7 +233,7 @@ private:
Trans m_trans;
ref_trans_type m_ref_trans;
Trans m_bare_trans;
mutable std::unordered_map<const shape_type *, std::pair<const shape_type *, ref_trans_type> > m_cache;
mutable std::unordered_map<std::pair<const shape_type *, Trans>, std::pair<const shape_type *, ref_trans_type> > m_cache;
};
template <class Trans>
@ -234,8 +241,8 @@ class shape_reference_translator_with_trans<db::PolygonRef, Trans>
: public shape_reference_translator_with_trans_from_shape_ref<db::PolygonRef, Trans>
{
public:
shape_reference_translator_with_trans (db::Layout *target_layout, const Trans &trans)
: shape_reference_translator_with_trans_from_shape_ref<db::PolygonRef, Trans> (target_layout, trans)
shape_reference_translator_with_trans (db::Layout *target_layout)
: shape_reference_translator_with_trans_from_shape_ref<db::PolygonRef, Trans> (target_layout)
{
// .. nothing yet ..
}
@ -247,12 +254,16 @@ class shape_reference_translator_with_trans
public:
typedef Sh shape_type;
shape_reference_translator_with_trans (db::Layout * /*target_layout*/, const Trans &trans)
: m_trans (trans)
shape_reference_translator_with_trans (db::Layout * /*target_layout*/)
{
// .. nothing yet ..
}
void set_trans (const Trans &trans)
{
m_trans = trans;
}
shape_type operator() (const shape_type &s) const
{
return s.transformed (m_trans);
@ -331,11 +342,11 @@ template <class TS, class TI, class TR>
local_processor_cell_context<TS, TI, TR> &
local_processor_cell_context<TS, TI, TR>::operator= (const local_processor_cell_context &other)
{
if (this != &other) {
m_propagated = other.m_propagated;
m_drops = other.m_drops;
}
return *this;
if (this != &other) {
m_propagated = other.m_propagated;
m_drops = other.m_drops;
}
return *this;
}
template <class TS, class TI, class TR>
@ -353,13 +364,20 @@ local_processor_cell_context<TS, TI, TR>::propagate (unsigned int output_layer,
return;
}
db::Layout *subject_layout = 0;
shape_reference_translator_with_trans<TR, db::ICplxTrans> rt (subject_layout);
for (typename std::vector<local_processor_cell_drop<TS, TI, TR> >::const_iterator d = m_drops.begin (); d != m_drops.end (); ++d) {
tl_assert (d->parent_context != 0);
tl_assert (d->parent != 0);
db::Layout *subject_layout = d->parent->layout ();
shape_reference_translator_with_trans<TR, db::ICplxTrans> rt (subject_layout, d->cell_inst);
if (subject_layout != d->parent->layout ()) {
subject_layout = d->parent->layout ();
rt = shape_reference_translator_with_trans<TR, db::ICplxTrans> (subject_layout);
}
rt.set_trans (d->cell_inst);
std::vector<TR> new_refs;
new_refs.reserve (res.size ());
for (typename std::unordered_set<TR>::const_iterator r = res.begin (); r != res.end (); ++r) {
@ -1180,7 +1198,7 @@ public:
typedef std::unordered_map<std::pair<db::cell_index_type, db::ICplxTrans>, interactions_value_type> interactions_type;
interaction_registration_inst2shape (db::Layout *subject_layout, unsigned int subject_layer, db::Coord dist, interactions_type *result)
: mp_subject_layout (subject_layout), m_subject_layer (subject_layer), m_dist (dist), mp_result (result)
: mp_subject_layout (subject_layout), m_subject_layer (subject_layer), m_dist (dist), mp_result (result), m_rt (subject_layout)
{
// nothing yet ..
}
@ -1195,6 +1213,7 @@ private:
unsigned int m_subject_layer;
db::Coord m_dist;
interactions_type *mp_result;
db::shape_reference_translator_with_trans<TI, db::ICplxTrans> m_rt;
void
collect_instance_shape_interactions (const db::CellInstArray *inst, unsigned int layer, const TI &ref, db::Coord dist)
@ -1211,7 +1230,7 @@ private:
if (! cbox.empty ()) {
db::ICplxTrans tni = tn.inverted ();
db::shape_reference_translator_with_trans<TI, db::ICplxTrans> rt (mp_subject_layout, tni);
m_rt.set_trans (tni);
std::set<TI> *shapes = 0;
@ -1223,7 +1242,7 @@ private:
if (! shapes) {
shapes = & (*mp_result) [std::make_pair (cell.cell_index (), tn)].second [layer];
}
shapes->insert (rt (ref));
shapes->insert (m_rt (ref));
}
}

View File

@ -3076,6 +3076,7 @@ public:
typedef typename Poly::coord_type coord_type;
typedef typename Poly::point_type point_type;
typedef typename Poly::box_type box_type;
typedef typename Poly::edge_type edge_type;
typedef Trans trans_type;
typedef Poly polygon_type;
typedef db::polygon_edge_iterator<Poly, trans_type> polygon_edge_iterator;

View File

@ -468,6 +468,14 @@ poly2poly_check<PolygonType>::enter (const PolygonType &o, size_t p)
}
}
template <class PolygonType>
void
poly2poly_check<PolygonType>::enter (const poly2poly_check<PolygonType>::edge_type &e, size_t p)
{
m_edge_heap.push_back (e);
m_scanner.insert (& m_edge_heap.back (), p);
}
// TODO: move to generic header
static bool interact (const db::Box &box, const db::Edge &e)
{
@ -496,6 +504,16 @@ poly2poly_check<PolygonType>::enter (const PolygonType &o, size_t p, const poly2
}
}
template <class PolygonType>
void
poly2poly_check<PolygonType>::enter (const poly2poly_check<PolygonType>::edge_type &e, size_t p, const poly2poly_check<PolygonType>::box_type &box)
{
if (! box.empty () && interact (box, e)) {
m_edge_heap.push_back (e);
m_scanner.insert (& m_edge_heap.back (), p);
}
}
template <class PolygonType>
void
poly2poly_check<PolygonType>::process ()

View File

@ -310,6 +310,7 @@ class DB_PUBLIC poly2poly_check
{
public:
typedef typename PolygonType::box_type box_type;
typedef typename PolygonType::edge_type edge_type;
poly2poly_check (Edge2EdgeCheckBase &output);
poly2poly_check ();
@ -321,6 +322,8 @@ public:
void connect (Edge2EdgeCheckBase &output);
void enter (const PolygonType &o, size_t p);
void enter (const PolygonType &o, size_t p, const box_type &search_box);
void enter (const edge_type &o, size_t p);
void enter (const edge_type &o, size_t p, const box_type &search_box);
void process ();
private:

View File

@ -122,8 +122,8 @@ static bool shields_interaction (const db::EdgePair &ep, const P &poly)
}
template <class TS, class TI>
check_local_operation<TS, TI>::check_local_operation (const EdgeRelationFilter &check, bool different_polygons, bool has_other, bool other_is_merged, const db::RegionCheckOptions &options)
: m_check (check), m_different_polygons (different_polygons), m_has_other (has_other), m_other_is_merged (other_is_merged), m_options (options)
check_local_operation<TS, TI>::check_local_operation (const EdgeRelationFilter &check, bool different_polygons, bool is_merged, bool has_other, bool other_is_merged, const db::RegionCheckOptions &options)
: m_check (check), m_different_polygons (different_polygons), m_is_merged (is_merged), m_has_other (has_other), m_other_is_merged (other_is_merged), m_options (options)
{
// .. nothing yet ..
}
@ -208,12 +208,15 @@ check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, const shape
edge2edge_check_negative_or_positive<std::unordered_set<db::EdgePair> > edge_check (m_check, result, intra_polygon_result, m_options.negative, m_different_polygons, m_has_other, m_options.shielded, symmetric_edge_pairs);
poly2poly_check<TS> poly_check (edge_check);
std::list<TS> heap;
std::unordered_set<TI> polygons;
std::unordered_set<TS> spolygons;
db::EdgeProcessor ep;
ep.set_base_verbosity (50);
std::set<unsigned int> ids;
for (typename shape_interactions<TS, TI>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (typename shape_interactions<TS, TI>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
for (auto j = i->second.begin (); j != i->second.end (); ++j) {
ids.insert (*j);
}
}
@ -226,13 +229,13 @@ check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, const shape
db::Vector e (edge_check.distance (), edge_check.distance ());
db::Box subject_box;
for (typename shape_interactions<TS, TI>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
subject_box += db::box_convert<TS> () (interactions.subject_shape (i->first));
}
if (edge_check.requires_different_layers ()) {
db::Box intruder_box;
for (std::set<unsigned int>::const_iterator id = ids.begin (); id != ids.end (); ++id) {
for (auto id = ids.begin (); id != ids.end (); ++id) {
intruder_box += db::box_convert<TI> () (interactions.intruder_shape (*id).second);
}
common_box = subject_box.enlarged (e) & intruder_box.enlarged (e);
@ -245,14 +248,50 @@ check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, const shape
if (m_has_other) {
size_t n = 0;
for (typename shape_interactions<TS, TI>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
const TS &subject = interactions.subject_shape (i->first);
if (! take_all) {
poly_check.enter (subject, n, common_box);
} else {
poly_check.enter (subject, n);
if (m_is_merged || (interactions.size () == 1 && interactions.subject_shape (interactions.begin ()->first).is_box ())) {
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
const TS &subject = interactions.subject_shape (i->first);
if (! take_all) {
poly_check.enter (subject, n, common_box);
} else {
poly_check.enter (subject, n);
}
n += 2;
}
n += 2;
} else {
// merge needed for the subject shapes
ep.clear ();
size_t nn = 0;
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
const TS &is = interactions.subject_shape (i->first);
for (typename TS::polygon_edge_iterator e = is.begin_edge (); ! e.at_end (); ++e) {
ep.insert (*e, nn);
}
++nn;
}
spolygons.clear ();
db::polygon_ref_generator<TS> ps (layout, spolygons);
db::PolygonGenerator pg (ps, false /*don't resolve holes*/, false);
db::SimpleMerge op (1 /*wc>0*/);
ep.process (pg, op);
for (auto o = spolygons.begin (); o != spolygons.end (); ++o) {
if (! take_all) {
poly_check.enter (*o, n, common_box);
} else {
poly_check.enter (*o, n);
}
n += 2;
}
}
// merge the intruders to remove inner edges
@ -266,20 +305,19 @@ check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, const shape
// NOTE: this local merge is not necessarily giving the same results than a global merge before running
// the processor. Reason: the search range is limited, hence not all necessary components may have been
// captured.
db::EdgeProcessor ep;
ep.set_base_verbosity (50);
ep.clear ();
size_t i = 0;
size_t nn = 0;
for (std::set<unsigned int>::const_iterator id = ids.begin (); id != ids.end (); ++id) {
for (auto id = ids.begin (); id != ids.end (); ++id) {
const TI &is = interactions.intruder_shape (*id).second;
for (typename TI::polygon_edge_iterator e = is.begin_edge (); ! e.at_end (); ++e) {
ep.insert (*e, i);
for (auto e = is.begin_edge (); ! e.at_end (); ++e) {
ep.insert (*e, nn);
}
++i;
++nn;
}
// @@@ Use edges directly
polygons.clear ();
db::polygon_ref_generator<TI> ps (layout, polygons);
@ -288,7 +326,7 @@ check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, const shape
ep.process (pg, op);
n = 1;
for (typename std::unordered_set<TI>::const_iterator o = polygons.begin (); o != polygons.end (); ++o) {
for (auto o = polygons.begin (); o != polygons.end (); ++o) {
if (! take_all) {
poly_check.enter (*o, n, common_box);
} else {
@ -300,7 +338,7 @@ check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, const shape
} else {
n = 1;
for (std::set<unsigned int>::const_iterator id = ids.begin (); id != ids.end (); ++id) {
for (auto id = ids.begin (); id != ids.end (); ++id) {
if (! take_all) {
poly_check.enter (interactions.intruder_shape (*id).second, n, common_box);
} else {
@ -313,34 +351,155 @@ check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, const shape
} else {
// NOTE: we need to eliminate identical shapes from intruders and subjects because those will shield
if (m_is_merged || (interactions.size () == 1 && ids.empty () && interactions.subject_shape (interactions.begin ()->first).is_box ())) {
size_t n = 0;
// no merge required
for (typename shape_interactions<TS, TI>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
// we can't directly insert because TS may be != TI
const TS &ts = interactions.subject_shape (i->first);
insert_into_hash (polygons, ts);
if (! take_all) {
poly_check.enter (ts, n, common_box);
} else {
poly_check.enter (ts, n);
}
n += 2;
}
// NOTE: we need to eliminate identical shapes from intruders and subjects because those will shield
n = 1;
size_t n = 0;
std::unordered_set<TI> subjects;
for (std::set<unsigned int>::const_iterator id = ids.begin (); id != ids.end (); ++id) {
const TI &ti = interactions.intruder_shape (*id).second;
if (polygons.find (ti) == polygons.end ()) {
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
// we can't directly insert because TS may be != TI
const TS &ts = interactions.subject_shape (i->first);
insert_into_hash (subjects, ts);
if (! take_all) {
poly_check.enter (ti, n, common_box);
poly_check.enter (ts, n, common_box);
} else {
poly_check.enter (ti, n);
poly_check.enter (ts, n);
}
n += 2;
}
n = 1;
for (auto id = ids.begin (); id != ids.end (); ++id) {
const TI &ti = interactions.intruder_shape (*id).second;
if (subjects.find (ti) == subjects.end ()) {
if (! take_all) {
poly_check.enter (ti, n, common_box);
} else {
poly_check.enter (ti, n);
}
}
}
} else if (ids.empty ()) {
// merge needed for the subject shapes - no intruders present so this is the simple case
size_t n = 0;
ep.clear ();
size_t nn = 0;
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
const TS &ts = interactions.subject_shape (i->first);
for (auto e = ts.begin_edge (); ! e.at_end (); ++e) {
ep.insert (*e, nn);
}
++nn;
}
// @@@ Use edges directly
spolygons.clear ();
db::polygon_ref_generator<TS> ps (layout, spolygons);
db::PolygonGenerator pg (ps, false /*don't resolve holes*/, false);
db::SimpleMerge op (1 /*wc>0*/);
ep.process (pg, op);
for (auto o = spolygons.begin (); o != spolygons.end (); ++o) {
if (! take_all) {
poly_check.enter (*o, n, common_box);
} else {
poly_check.enter (*o, n);
}
n += 2;
}
} else {
// merge needed for the subject and intruder shapes - we merge both and then
// separate edges into those from the subject and those from intruder shapes.
ep.clear ();
size_t nn = 0;
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
const TS &ts = interactions.subject_shape (i->first);
for (auto e = ts.begin_edge (); ! e.at_end (); ++e) {
ep.insert (*e, nn);
}
++nn;
}
for (auto id = ids.begin (); id != ids.end (); ++id) {
const TI &ti = interactions.intruder_shape (*id).second;
for (auto e = ti.begin_edge (); ! e.at_end (); ++e) {
ep.insert (*e, nn);
}
++nn;
}
std::vector<typename TS::edge_type> edges;
db::EdgeContainer ee (edges);
db::SimpleMerge op (1 /*wc>0*/);
ep.process (ee, op);
ep.clear ();
std::vector<typename TS::edge_type> subject_edges;
size_t sz = 0;
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
const TS &ts = interactions.subject_shape (i->first);
sz += ts.vertices ();
}
subject_edges.reserve (sz);
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
const TS &ts = interactions.subject_shape (i->first);
for (auto e = ts.begin_edge (); ! e.at_end (); ++e) {
subject_edges.push_back (*e);
}
}
for (size_t n = 0; n <= 1; ++n) {
std::set<typename TI::edge_type> partial_edges;
EdgeBooleanClusterCollector<std::set<typename TI::edge_type> > cluster_collector (&partial_edges, n == 0 ? db::EdgeAnd : db::EdgeNot);
db::box_scanner<typename TI::edge_type, size_t> scanner;
scanner.reserve (edges.size () + subject_edges.size ());
for (auto i = edges.begin (); i != edges.end (); ++i) {
if (! i->is_degenerate ()) {
scanner.insert (i.operator-> (), 0);
}
}
for (auto i = subject_edges.begin (); i != subject_edges.end (); ++i) {
if (! i->is_degenerate ()) {
scanner.insert (i.operator-> (), 1);
}
}
scanner.process (cluster_collector, 1, db::box_convert<typename TI::edge_type> ());
for (auto e = partial_edges.begin (); e != partial_edges.end (); ++e) {
if (! take_all) {
poly_check.enter (*e, n, common_box);
} else {
poly_check.enter (*e, n);
}
}
}
}
}

View File

@ -197,6 +197,19 @@ struct DB_PUBLIC RegionCheckOptions
* @brief Specifies whether to produce negative output
*/
bool negative;
/**
* @brief Gets a value indicating whether merged primary input is required
*/
bool needs_merged () const
{
return negative
|| rect_filter != NoRectFilter
|| opposite_filter != NoOppositeFilter
|| max_projection != std::numeric_limits<distance_type>::max ()
|| min_projection != 0
|| whole_edges;
}
};
template <class TS, class TI>
@ -204,7 +217,7 @@ class check_local_operation
: public local_operation<TS, TI, db::EdgePair>
{
public:
check_local_operation (const EdgeRelationFilter &check, bool different_polygons, bool has_other, bool other_is_merged, const db::RegionCheckOptions &options);
check_local_operation (const EdgeRelationFilter &check, bool different_polygons, bool is_merged, bool has_other, bool other_is_merged, const db::RegionCheckOptions &options);
virtual db::Coord dist () const;
virtual OnEmptyIntruderHint on_empty_intruder_hint () const;
@ -216,6 +229,7 @@ public:
private:
EdgeRelationFilter m_check;
bool m_different_polygons;
bool m_is_merged;
bool m_has_other;
bool m_other_is_merged;
db::RegionCheckOptions m_options;

View File

@ -390,7 +390,7 @@ static db::CompoundRegionOperationNode *new_edge_pair_to_second_edges (db::Compo
static db::CompoundRegionOperationNode *new_check_node (db::CompoundRegionOperationNode *other, db::edge_relation_type rel, bool different_polygons, db::Coord d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection, bool shielded, db::OppositeFilter opposite_filter, db::RectFilter rect_filter, bool negative)
{
check_non_null (other, "other");
return new db::CompoundRegionCheckOperationNode (new_primary (), other, rel, different_polygons, d,
return new db::CompoundRegionCheckOperationNode (0, other, rel, different_polygons, d,
db::RegionCheckOptions (whole_edges,
metrics,
ignore_angle.is_nil () ? 90 : ignore_angle.to_double (),

View File

@ -22,6 +22,7 @@
#include "gsiDecl.h"
#include "gsiEnums.h"
#include "dbEdgePairs.h"
#include "dbEdges.h"
@ -232,6 +233,13 @@ static db::EdgePairs with_angle2 (const db::EdgePairs *r, double amin, double am
return r->filtered (ef);
}
static db::EdgePairs with_angle3 (const db::EdgePairs *r, db::SpecialEdgeOrientationFilter::FilterType type, bool inverse)
{
db::SpecialEdgeOrientationFilter f (type, inverse);
db::EdgeFilterBasedEdgePairFilter ef (&f, true /*one must match*/);
return r->filtered (ef);
}
static db::EdgePairs with_angle_both1 (const db::EdgePairs *r, double a, bool inverse)
{
db::EdgeOrientationFilter f (a, inverse);
@ -246,6 +254,13 @@ static db::EdgePairs with_angle_both2 (const db::EdgePairs *r, double amin, doub
return r->filtered (ef);
}
static db::EdgePairs with_angle_both3 (const db::EdgePairs *r, db::SpecialEdgeOrientationFilter::FilterType type, bool inverse)
{
db::SpecialEdgeOrientationFilter f (type, inverse);
db::EdgeFilterBasedEdgePairFilter ef (&f, false /*both must match*/);
return r->filtered (ef);
}
static db::EdgePairs with_internal_angle1 (const db::EdgePairs *r, double a, bool inverse)
{
db::InternalAngleEdgePairFilter f (a, inverse);
@ -661,7 +676,15 @@ Class<db::EdgePairs> decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs",
"This will filter edge pairs with at least one horizontal edge:\n"
"\n"
"@code\n"
"horizontal = edge_pairs.with_orientation(0, false)\n"
"horizontal = edge_pairs.with_angle(0, false)\n"
"@/code\n"
"\n"
"Note that the inverse @b result @/b of \\with_angle is delivered by \\with_angle_both with the inverse flag set as edge pairs are unselected when both edges fail to meet the criterion.\n"
"I.e\n"
"\n"
"@code\n"
"result = edge_pairs.with_angle(0, false)\n"
"others = edge_pairs.with_angle_both(0, true)\n"
"@/code\n"
"\n"
"This method has been added in version 0.27.1.\n"
@ -675,8 +698,35 @@ Class<db::EdgePairs> decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs",
"With \"include_min_angle\" set to true (the default), the minimum angle is included in the criterion while with false, the "
"minimum angle itself is not included. Same for \"include_max_angle\" where the default is false, meaning the maximum angle is not included in the range.\n"
"\n"
"Note that the inverse @b result @/b of \\with_angle is delivered by \\with_angle_both with the inverse flag set as edge pairs are unselected when both edges fail to meet the criterion.\n"
"I.e\n"
"\n"
"@code\n"
"result = edge_pairs.with_angle(0, 45, false)\n"
"others = edge_pairs.with_angle_both(0, 45, true)\n"
"@/code\n"
"\n"
"This method has been added in version 0.27.1.\n"
) +
method_ext ("with_angle", with_angle3, gsi::arg ("type"), gsi::arg ("inverse"),
"@brief Filter the edge pairs by orientation of their edges\n"
"Filters the edge pairs in the edge pair collection by orientation. If \"inverse\" is false, only "
"edge pairs with at least one edge having an angle of the given type are returned. If \"inverse\" is true, "
"edge pairs not fulfilling this criterion are returned.\n"
"\n"
"This version allows specifying an edge type instead of an angle. Edge types include multiple distinct orientations "
"and are specified using one of the \\Edges#OrthoEdges, \\Edges#DiagonalEdges or \\Edges#OrthoDiagonalEdges types.\n"
"\n"
"Note that the inverse @b result @/b of \\with_angle is delivered by \\with_angle_both with the inverse flag set as edge pairs are unselected when both edges fail to meet the criterion.\n"
"I.e\n"
"\n"
"@code\n"
"result = edge_pairs.with_angle(RBA::Edges::Ortho, false)\n"
"others = edge_pairs.with_angle_both(RBA::Edges::Ortho, true)\n"
"@/code\n"
"\n"
"This method has been added in version 0.28.\n"
) +
method_ext ("with_angle_both", with_angle_both1, gsi::arg ("angle"), gsi::arg ("inverse"),
"@brief Filter the edge pairs by orientation of both of their edges\n"
"Filters the edge pairs in the edge pair collection by orientation. If \"inverse\" is false, only "
@ -686,7 +736,15 @@ Class<db::EdgePairs> decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs",
"This will filter edge pairs with at least one horizontal edge:\n"
"\n"
"@code\n"
"horizontal = edge_pairs.with_orientation(0, false)\n"
"horizontal = edge_pairs.with_angle_both(0, false)\n"
"@/code\n"
"\n"
"Note that the inverse @b result @/b of \\with_angle_both is delivered by \\with_angle with the inverse flag set as edge pairs are unselected when one edge fails to meet the criterion.\n"
"I.e\n"
"\n"
"@code\n"
"result = edge_pairs.with_angle_both(0, false)\n"
"others = edge_pairs.with_angle(0, true)\n"
"@/code\n"
"\n"
"This method has been added in version 0.27.1.\n"
@ -700,8 +758,35 @@ Class<db::EdgePairs> decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs",
"With \"include_min_angle\" set to true (the default), the minimum angle is included in the criterion while with false, the "
"minimum angle itself is not included. Same for \"include_max_angle\" where the default is false, meaning the maximum angle is not included in the range.\n"
"\n"
"Note that the inverse @b result @/b of \\with_angle_both is delivered by \\with_angle with the inverse flag set as edge pairs are unselected when one edge fails to meet the criterion.\n"
"I.e\n"
"\n"
"@code\n"
"result = edge_pairs.with_angle_both(0, 45, false)\n"
"others = edge_pairs.with_angle(0, 45, true)\n"
"@/code\n"
"\n"
"This method has been added in version 0.27.1.\n"
) +
method_ext ("with_angle_both", with_angle_both3, gsi::arg ("type"), gsi::arg ("inverse"),
"@brief Filter the edge pairs by orientation of their edges\n"
"Filters the edge pairs in the edge pair collection by orientation. If \"inverse\" is false, only "
"edge pairs with both edges having an angle of the given type are returned. If \"inverse\" is true, "
"edge pairs not fulfilling this criterion for both edges are returned.\n"
"\n"
"This version allows specifying an edge type instead of an angle. Edge types include multiple distinct orientations "
"and are specified using one of the \\Edges#OrthoEdges, \\Edges#DiagonalEdges or \\Edges#OrthoDiagonalEdges types.\n"
"\n"
"Note that the inverse @b result @/b of \\with_angle_both is delivered by \\with_angle with the inverse flag set as edge pairs are unselected when one edge fails to meet the criterion.\n"
"I.e\n"
"\n"
"@code\n"
"result = edge_pairs.with_angle_both(RBA::Edges::Ortho, false)\n"
"others = edge_pairs.with_angle(RBA::Edges::Ortho, true)\n"
"@/code\n"
"\n"
"This method has been added in version 0.28.\n"
) +
method_ext ("with_area", with_area1, gsi::arg ("area"), gsi::arg ("inverse"),
"@brief Filters the edge pairs by the enclosed area\n"
"Filters the edge pairs in the edge pair collection by enclosed area. If \"inverse\" is false, only "

View File

@ -212,6 +212,12 @@ static db::Edges with_angle2 (const db::Edges *r, double amin, double amax, bool
return r->filtered (f);
}
static db::Edges with_angle3 (const db::Edges *r, db::SpecialEdgeOrientationFilter::FilterType type, bool inverse)
{
db::SpecialEdgeOrientationFilter f (type, inverse);
return r->filtered (f);
}
static db::EdgePairs width2 (const db::Edges *r, db::Edges::coord_type d, bool whole_edges, db::metrics_type metrics, const tl::Variant &ignore_angle, const tl::Variant &min_projection, const tl::Variant &max_projection)
{
return r->width_check (d, db::EdgesCheckOptions (whole_edges,
@ -609,13 +615,13 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
"This method has been introduced in version 0.26."
) +
method_ext ("with_length", with_length1, gsi::arg ("length"), gsi::arg ("inverse"),
"@brief Filter the edges by length\n"
"@brief Filters the edges by length\n"
"Filters the edges in the edge collection by length. If \"inverse\" is false, only "
"edges which have the given length are returned. If \"inverse\" is true, "
"edges not having the given length are returned.\n"
) +
method_ext ("with_length", with_length2, gsi::arg ("min_length"), gsi::arg ("max_length"), gsi::arg ("inverse"),
"@brief Filter the edges by length\n"
"@brief Filters the edges by length\n"
"Filters the edges in the edge collection by length. If \"inverse\" is false, only "
"edges which have a length larger or equal to \"min_length\" and less than \"max_length\" are "
"returned. If \"inverse\" is true, "
@ -625,7 +631,7 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
"If you don't want to specify a lower or upper limit, pass nil to that parameter.\n"
) +
method_ext ("with_angle", with_angle1, gsi::arg ("angle"), gsi::arg ("inverse"),
"@brief Filter the edges by orientation\n"
"@brief Filters the edges by orientation\n"
"Filters the edges in the edge collection by orientation. If \"inverse\" is false, only "
"edges which have the given angle to the x-axis are returned. If \"inverse\" is true, "
"edges not having the given angle are returned.\n"
@ -633,11 +639,11 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
"This will select horizontal edges:\n"
"\n"
"@code\n"
"horizontal = edges.with_orientation(0, false)\n"
"horizontal = edges.with_angle(0, false)\n"
"@/code\n"
) +
method_ext ("with_angle", with_angle2, gsi::arg ("min_angle"), gsi::arg ("max_angle"), gsi::arg ("inverse"), gsi::arg ("include_min_angle", true), gsi::arg ("include_max_angle", false),
"@brief Filter the edges by orientation\n"
"@brief Filters the edges by orientation\n"
"Filters the edges in the edge collection by orientation. If \"inverse\" is false, only "
"edges which have an angle to the x-axis larger or equal to \"min_angle\" (depending on \"include_min_angle\") and equal or less than \"max_angle\" (depending on \"include_max_angle\") are "
"returned. If \"inverse\" is true, "
@ -648,6 +654,17 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
"\n"
"The two \"include..\" arguments have been added in version 0.27."
) +
method_ext ("with_angle", with_angle3, gsi::arg ("type"), gsi::arg ("inverse"),
"@brief Filters the edges by orientation type\n"
"Filters the edges in the edge collection by orientation. If \"inverse\" is false, only "
"edges which have an angle of the given type are returned. If \"inverse\" is true, "
"edges which do not conform to this criterion are returned.\n"
"\n"
"This version allows specifying an edge type instead of an angle. Edge types include multiple distinct orientations "
"and are specified using one of the \\OrthoEdges, \\DiagonalEdges or \\OrthoDiagonalEdges types.\n"
"\n"
"This method has been added in version 0.28.\n"
) +
method ("insert", (void (db::Edges::*)(const db::Edge &)) &db::Edges::insert, gsi::arg ("edge"),
"@brief Inserts an edge\n"
"\n"
@ -1749,5 +1766,23 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
"This class has been introduced in version 0.23.\n"
);
gsi::EnumIn<db::Edges, db::SpecialEdgeOrientationFilter::FilterType> decl_EdgesEdgeFilterType ("db", "EdgeType",
gsi::enum_const ("OrthoEdges", db::SpecialEdgeOrientationFilter::Ortho,
"@brief Horizontal and vertical edges are selected\n"
) +
gsi::enum_const ("DiagonalEdges", db::SpecialEdgeOrientationFilter::Diagonal,
"@brief Diagonal edges are selected (-45 and 45 degree)\n"
) +
gsi::enum_const ("OrthoDiagonalEdges", db::SpecialEdgeOrientationFilter::OrthoDiagonal,
"@brief Diagonal or orthogonal edges are selected (0, 90, -45 and 45 degree)\n"
),
"@brief This enum specifies the the edge type for edge angle filters.\n"
"\n"
"This enum was introduced in version 0.28.\n"
);
// Inject the db::SpecialEdgeOrientationFilter::FilterType declarations into Edges:
gsi::ClassExt<db::Edges> decl_EdgesEdgeFilterType_into_parent (decl_EdgesEdgeFilterType.defs ());
}

View File

@ -3290,7 +3290,10 @@ Shielding is enabled by default, but can be switched off with the "transparent"
<li><tt>layer.with_angle(min .. max)</tt></li>
<li><tt>layer.with_angle(value)</tt></li>
<li><tt>layer.with_angle(min, max)</tt></li>
<li><tt>edge_pair_layer.with_angle(min, max [, both])</tt></li>
<li><tt>layer.with_angle(ortho)</tt></li>
<li><tt>layer.with_angle(diagonal)</tt></li>
<li><tt>layer.with_angle(diagonal_only)</tt></li>
<li><tt>edge_pair_layer.with_angle(... [, both])</tt></li>
</ul>
<p>
When called on an edge layer, the method selects edges by their angle,
@ -3303,7 +3306,7 @@ an angle of 90 degee. The angle range is from -90 (exclusive) to 90 degree (incl
The first version of this method selects
edges with a angle larger or equal to min and less than max (but not equal).
The second version selects edges with exactly the given angle. The third
version is identical to the first one.
version is identical to the first one.
</p><p>
When called on an edge pair layer, this method selects edge pairs with one or both edges
meeting the angle criterion. In this case an additional argument is accepted which can be
@ -3320,6 +3323,10 @@ ep2 = edge_pairs.with_angle(90, both)
</pre>
</p><p>
A method delivering all objects not matching the angle criterion is <a href="#without_angle">without_angle</a>.
Note that for edge pairs, in order to get the inverse result, you have to add or drop "both"
on <a href="#without_angle">without_angle</a>. This is because <a href="#without_angle">without_angle</a> without both returns edge pairs where
one edge does not match the criterion. The logical opposite of "one edge matches" however is
"both edges do not match".
</p><p>
The following images demonstrate some use cases of <a href="#with_angle">with_angle</a> and <a href="#without_angle:">without_angle:</a>
</p><p>
@ -3334,6 +3341,17 @@ The following images demonstrate some use cases of <a href="#with_angle">with_an
</tr>
</table>
</p><p>
Specifying "ortho", "diagonal" or "diagonal_only" instead of the angle values will select
0 and 90 degree edges (ortho), -45 and 45 degree edges (diagonal_only) and both types (diagonal).
This simplifies the implementation of selectors for manhattan or half-manhattan features:
</p><p>
<pre>
ortho_edges = edges.with_angle(ortho)
# which is equivalent to, but more efficient as:
ortho_edges = edges.with_angle(0) + edges.with_angle(90)
</pre>
</p><p>
Note that in former versions, with_angle could be used on polygon layers selecting corners with specific angles.
This feature has been deprecated. Use <a href="#corners">corners</a> instead.
</p>
@ -3663,12 +3681,17 @@ This method is available for polygon layers only.
<li><tt>layer.without_angle(min .. max)</tt></li>
<li><tt>layer.without_angle(value)</tt></li>
<li><tt>layer.without_angle(min, max)</tt></li>
<li><tt>edge_pair_layer.without_angle(min, max [, both])</tt></li>
<li><tt>layer.without_angle(ortho)</tt></li>
<li><tt>layer.without_angle(diagonal)</tt></li>
<li><tt>layer.without_angle(diagonal_only)</tt></li>
<li><tt>edge_pair_layer.without_angle(... [, both])</tt></li>
</ul>
<p>
The method basically is the inverse of <a href="#with_angle">with_angle</a>. It selects all edges
of the edge layer or corners of the polygons which do not have the given angle (second form) or whose angle
is not inside the given interval (first and third form). When called on edge pairs, it selects
is not inside the given interval (first and third form) or of the given type (other forms).
</p><p>
When called on edge pairs, it selects
edge pairs by the angles of their edges.
</p><p>
A note on the "both" modifier (without_angle called on edge pairs): "both" means that

View File

@ -77,6 +77,18 @@ module DRC
DRCBothEdges::new
end
def ortho
DRCOrthoEdges::new
end
def diagonal_only
DRCDiagonalOnlyEdges::new
end
def diagonal
DRCDiagonalEdges::new
end
def shift(x, y)
self._context("shift") do
RBA::DCplxTrans::new(RBA::DVector::new(_make_value(x) * self.dbu, _make_value(y) * self.dbu))

View File

@ -864,7 +864,10 @@ CODE
# @synopsis layer.with_angle(min .. max)
# @synopsis layer.with_angle(value)
# @synopsis layer.with_angle(min, max)
# @synopsis edge_pair_layer.with_angle(min, max [, both])
# @synopsis layer.with_angle(ortho)
# @synopsis layer.with_angle(diagonal)
# @synopsis layer.with_angle(diagonal_only)
# @synopsis edge_pair_layer.with_angle(... [, both])
#
# When called on an edge layer, the method selects edges by their angle,
# measured against the horizontal axis in the mathematical sense.
@ -876,7 +879,7 @@ CODE
# The first version of this method selects
# edges with a angle larger or equal to min and less than max (but not equal).
# The second version selects edges with exactly the given angle. The third
# version is identical to the first one.
# version is identical to the first one.
#
# When called on an edge pair layer, this method selects edge pairs with one or both edges
# meeting the angle criterion. In this case an additional argument is accepted which can be
@ -893,6 +896,10 @@ CODE
# @/code
#
# A method delivering all objects not matching the angle criterion is \without_angle.
# Note that for edge pairs, in order to get the inverse result, you have to add or drop "both"
# on \without_angle. This is because \without_angle without both returns edge pairs where
# one edge does not match the criterion. The logical opposite of "one edge matches" however is
# "both edges do not match".
#
# The following images demonstrate some use cases of \with_angle and \without_angle:
#
@ -907,6 +914,17 @@ CODE
# @/tr
# @/table
#
# Specifying "ortho", "diagonal" or "diagonal_only" instead of the angle values will select
# 0 and 90 degree edges (ortho), -45 and 45 degree edges (diagonal_only) and both types (diagonal).
# This simplifies the implementation of selectors for manhattan or half-manhattan features:
#
# @code
# ortho_edges = edges.with_angle(ortho)
#
# # which is equivalent to, but more efficient as:
# ortho_edges = edges.with_angle(0) + edges.with_angle(90)
# @/code
#
# Note that in former versions, with_angle could be used on polygon layers selecting corners with specific angles.
# This feature has been deprecated. Use \corners instead.
@ -916,11 +934,16 @@ CODE
# @synopsis layer.without_angle(min .. max)
# @synopsis layer.without_angle(value)
# @synopsis layer.without_angle(min, max)
# @synopsis edge_pair_layer.without_angle(min, max [, both])
# @synopsis layer.without_angle(ortho)
# @synopsis layer.without_angle(diagonal)
# @synopsis layer.without_angle(diagonal_only)
# @synopsis edge_pair_layer.without_angle(... [, both])
#
# The method basically is the inverse of \with_angle. It selects all edges
# of the edge layer or corners of the polygons which do not have the given angle (second form) or whose angle
# is not inside the given interval (first and third form). When called on edge pairs, it selects
# is not inside the given interval (first and third form) or of the given type (other forms).
#
# When called on edge pairs, it selects
# edge pairs by the angles of their edges.
#
# A note on the "both" modifier (without_angle called on edge pairs): "both" means that
@ -981,7 +1004,7 @@ CODE
args = args.select do |a|
if a.is_a?(DRCBothEdges)
if !self.data.is_a?(RBA::EdgePairs)
raise("'both' keyword only available for edge pair layers")
raise("'both' keyword is only available for edge pair layers")
end
f = :with_#{f}_both
false
@ -998,6 +1021,11 @@ CODE
a = args[0]
if a.is_a?(Range)
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, result_class, f, a.begin, a.end, #{inv.inspect}))
elsif a.is_a?(DRCOrthoEdges) || a.is_a?(DRCDiagonalOnlyEdges) || a.is_a?(DRCDiagonalEdges)
if self.data.is_a?(RBA::Region)
raise("'ortho', 'diagonal' or 'diagonal_only' keyword is only available for edge or edge pair layers")
end
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, result_class, f, a.value, #{inv.inspect}))
else
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, result_class, f, a, #{inv.inspect}))
end

View File

@ -16,10 +16,31 @@ module DRC
end
end
# A wrapper for the "both edges" flag for EdgePair#with_length or EdgePair#with_angle
# A wrapper for the "both edges" flag for EdgePairs#with_length or EdgePairs#with_angle
class DRCBothEdges
end
# A wrapper for the "ortho edges" flag for Edges#with_angle or EdgePairs#with_angle
class DRCOrthoEdges
def value
RBA::Edges::OrthoEdges
end
end
# A wrapper for the "diagonal only edges" flag for Edges#with_angle or EdgePairs#with_angle
class DRCDiagonalOnlyEdges
def value
RBA::Edges::DiagonalEdges
end
end
# A wrapper for the "diagonal edges" flag for Edges#with_angle or EdgePairs#with_angle
class DRCDiagonalEdges
def value
RBA::Edges::OrthoDiagonalEdges
end
end
# A wrapper for the padding modes of with_density
class DRCDensityPadding
attr_accessor :value

View File

@ -1328,3 +1328,13 @@ TEST(55d_drccount)
run_test (_this, "55", true);
}
TEST(56_angle_classes)
{
run_test (_this, "56", false);
}
TEST(56d_angle_classes)
{
run_test (_this, "56", true);
}

View File

@ -225,13 +225,13 @@ static size_t index_from_attr (const std::pair<const Attr *, const Attr *> &attr
size_t
SingleIndexedNetlistModel::circuit_count () const
{
return mp_netlist->circuit_count ();
return mp_netlist ? mp_netlist->circuit_count () : 0;
}
size_t
SingleIndexedNetlistModel::top_circuit_count () const
{
return mp_netlist->top_circuit_count ();
return mp_netlist ? mp_netlist->top_circuit_count () : 0;
}
size_t

31
testdata/drc/drcSimpleTests_56.drc vendored Normal file
View File

@ -0,0 +1,31 @@
source $drc_test_source
target $drc_test_target
if $drc_test_deep
deep
end
l1 = input(1, 0)
l1.output(1, 0)
l1e = l1.edges
l1e.with_angle(ortho).output(100, 0)
l1e.without_angle(ortho).output(101, 0)
l1e.with_angle(diagonal).output(102, 0)
l1e.without_angle(diagonal).output(103, 0)
l1e.with_angle(diagonal_only).output(104, 0)
l1e.without_angle(diagonal_only).output(105, 0)
l1ee = l1.width(100.um, projection)
l1ee.output(10, 0)
l1ee.with_angle(ortho).output(200, 0)
l1ee.without_angle(ortho).output(201, 0)
l1ee.with_angle(diagonal).output(202, 0)
l1ee.without_angle(diagonal).output(203, 0)
l1ee.with_angle(diagonal_only).output(204, 0)
l1ee.without_angle(diagonal_only).output(205, 0)
l1ee.with_angle(ortho, both).output(210, 0)

BIN
testdata/drc/drcSimpleTests_56.gds vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au56.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcSimpleTests_au56d.gds vendored Normal file

Binary file not shown.

View File

@ -303,6 +303,27 @@ class DBEdgePairs_TestClass < TestBase
assert_equal(r1.with_internal_angle(0, 45, false, true, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(20,10;30,0)")
assert_equal(r1.with_internal_angle(0, 45, true, true, true).to_s, "")
ep1 = RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 10), RBA::Edge::new(10, 0, 20, 0))
ep2 = RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 10), RBA::Edge::new(10, 0, 20, 10))
ep3 = RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 20), RBA::Edge::new(10, 20, 10, 0))
ep4 = RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 10), RBA::Edge::new(10, 0, 15, 10))
r = RBA::EdgePairs::new([ ep1, ep2, ep3, ep4 ])
assert_equal(r.with_angle(RBA::Edges::OrthoEdges, false).to_s, "(0,0;0,10)/(10,0;20,0);(0,0;0,10)/(10,0;20,10);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;15,10)")
assert_equal(r.with_angle(RBA::Edges::OrthoEdges, true).to_s, "(0,0;0,10)/(10,0;20,10);(0,0;0,10)/(10,0;15,10)")
assert_equal(r.with_angle(RBA::Edges::DiagonalEdges, false).to_s, "(0,0;0,10)/(10,0;20,10)")
assert_equal(r.with_angle(RBA::Edges::DiagonalEdges, true).to_s, "(0,0;0,10)/(10,0;20,0);(0,0;0,10)/(10,0;20,10);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;15,10)")
assert_equal(r.with_angle(RBA::Edges::OrthoDiagonalEdges, false).to_s, "(0,0;0,10)/(10,0;20,0);(0,0;0,10)/(10,0;20,10);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;15,10)")
assert_equal(r.with_angle(RBA::Edges::OrthoDiagonalEdges, true).to_s, "(0,0;0,10)/(10,0;15,10)")
assert_equal(r.with_angle_both(RBA::Edges::OrthoEdges, false).to_s, "(0,0;0,10)/(10,0;20,0);(0,0;0,20)/(10,20;10,0)")
assert_equal(r.with_angle_both(RBA::Edges::OrthoEdges, true).to_s, "")
assert_equal(r.with_angle_both(RBA::Edges::DiagonalEdges, false).to_s, "")
assert_equal(r.with_angle_both(RBA::Edges::DiagonalEdges, true).to_s, "(0,0;0,10)/(10,0;20,0);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;15,10)")
assert_equal(r.with_angle_both(RBA::Edges::OrthoDiagonalEdges, false).to_s, "(0,0;0,10)/(10,0;20,0);(0,0;0,10)/(10,0;20,10);(0,0;0,20)/(10,20;10,0)")
assert_equal(r.with_angle_both(RBA::Edges::OrthoDiagonalEdges, true).to_s, "")
end
end

View File

@ -474,6 +474,19 @@ class DBEdges_TestClass < TestBase
assert_equal(r.with_length(100, 200, true).to_s, "(100,0;100,50)")
assert_equal(r.with_length(nil, 100, false).to_s, "(100,0;100,50)")
r = RBA::Edges::new
r.insert(RBA::Edge::new(0, 0, 100, 0))
r.insert(RBA::Edge::new(100, 0, 100, 50))
r.insert(RBA::Edge::new(0, 0, 100, 100))
r.insert(RBA::Edge::new(0, 0, 100, -100))
r.insert(RBA::Edge::new(0, 0, 100, 120))
assert_equal(r.with_angle(RBA::Edges::OrthoEdges, false).to_s, "(0,0;100,0);(100,0;100,50)")
assert_equal(r.with_angle(RBA::Edges::OrthoEdges, true).to_s, "(0,0;100,100);(0,0;100,-100);(0,0;100,120)")
assert_equal(r.with_angle(RBA::Edges::DiagonalEdges, false).to_s, "(0,0;100,100);(0,0;100,-100)")
assert_equal(r.with_angle(RBA::Edges::DiagonalEdges, true).to_s, "(0,0;100,0);(100,0;100,50);(0,0;100,120)")
assert_equal(r.with_angle(RBA::Edges::OrthoDiagonalEdges, false).to_s, "(0,0;100,0);(100,0;100,50);(0,0;100,100);(0,0;100,-100)")
assert_equal(r.with_angle(RBA::Edges::OrthoDiagonalEdges, true).to_s, "(0,0;100,120)")
end
# interact