mirror of https://github.com/KLayout/klayout.git
commit
10a8d719b8
|
|
@ -1037,7 +1037,11 @@ AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons,
|
||||||
{
|
{
|
||||||
#if defined(USE_LOCAL_PROCESSOR)
|
#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);
|
EdgeRelationFilter check (rel, d, options.metrics);
|
||||||
check.set_include_zero (false);
|
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 ()) {
|
if (other == subject_regionptr () || other == foreign_regionptr ()) {
|
||||||
foreign.push_back (other == foreign_regionptr ());
|
foreign.push_back (other == foreign_regionptr ());
|
||||||
others.push_back (begin_merged ());
|
others.push_back (begin_merged ());
|
||||||
|
other_is_merged = primary_is_merged;
|
||||||
} else {
|
} else {
|
||||||
foreign.push_back (false);
|
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
|
// NOTE: whole edges needs both inputs merged
|
||||||
others.push_back (other->begin_merged ());
|
others.push_back (other->begin_merged ());
|
||||||
other_is_merged = true;
|
other_is_merged = true;
|
||||||
|
|
@ -1072,7 +1079,7 @@ AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons,
|
||||||
has_other = true;
|
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::unique_ptr<FlatEdgePairs> output (new FlatEdgePairs ());
|
||||||
std::vector<db::Shapes *> results;
|
std::vector<db::Shapes *> results;
|
||||||
|
|
|
||||||
|
|
@ -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
|
db::ICplxTrans MagnificationReducer::reduce (const db::ICplxTrans &trans) const
|
||||||
{
|
{
|
||||||
return db::ICplxTrans (trans.mag ());
|
return db::ICplxTrans (trans.mag ());
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,16 @@ struct DB_PUBLIC OrientationReducer
|
||||||
db::Trans reduce (const db::Trans &trans) const;
|
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
|
* @brief A magnification reducer
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -1555,10 +1555,13 @@ CompoundRegionCheckOperationNode::CompoundRegionCheckOperationNode (CompoundRegi
|
||||||
m_check.set_max_projection (options.max_projection);
|
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)
|
: 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 ();
|
m_has_other = other->has_external_inputs ();
|
||||||
|
// @@@ needs a concept to deal with merged/non-merged inputs
|
||||||
m_is_other_merged = other->is_merged ();
|
m_is_other_merged = other->is_merged ();
|
||||||
|
|
||||||
set_description ("check");
|
set_description ("check");
|
||||||
|
|
@ -1585,7 +1588,9 @@ CompoundRegionCheckOperationNode::computed_dist () const
|
||||||
void
|
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
|
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);
|
tl_assert (results.size () == 1);
|
||||||
if (results.front ().empty ()) {
|
if (results.front ().empty ()) {
|
||||||
|
|
@ -1601,7 +1606,9 @@ CompoundRegionCheckOperationNode::do_compute_local (CompoundRegionOperationCache
|
||||||
void
|
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
|
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);
|
tl_assert (results.size () == 1);
|
||||||
if (results.front ().empty ()) {
|
if (results.front ().empty ()) {
|
||||||
|
|
|
||||||
|
|
@ -1647,16 +1647,23 @@ DeepRegion::run_check (db::edge_relation_type rel, bool different_polygons, cons
|
||||||
unsigned int other_layer = 0;
|
unsigned int other_layer = 0;
|
||||||
bool other_is_merged = true;
|
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 ()) {
|
if (other == subject_regionptr ()) {
|
||||||
other_layer = subject_idlayer ();
|
other_layer = subject_idlayer ();
|
||||||
|
other_is_merged = primary_is_merged;
|
||||||
} else if (other == foreign_regionptr ()) {
|
} else if (other == foreign_regionptr ()) {
|
||||||
other_layer = foreign_idlayer ();
|
other_layer = foreign_idlayer ();
|
||||||
|
other_is_merged = primary_is_merged;
|
||||||
} else {
|
} else {
|
||||||
other_deep = dynamic_cast<const db::DeepRegion *> (other->delegate ());
|
other_deep = dynamic_cast<const db::DeepRegion *> (other->delegate ());
|
||||||
if (! other_deep) {
|
if (! other_deep) {
|
||||||
return db::AsIfFlatRegion::run_check (rel, different_polygons, other, d, options);
|
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
|
// NOTE: whole edges needs both inputs merged
|
||||||
other_layer = other_deep->merged_deep_layer ().layer ();
|
other_layer = other_deep->merged_deep_layer ().layer ();
|
||||||
other_is_merged = true;
|
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);
|
EdgeRelationFilter check (rel, d, options.metrics);
|
||||||
check.set_include_zero (false);
|
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 ()));
|
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 ()),
|
db::local_processor<db::PolygonRef, db::PolygonRef, db::EdgePair> proc (const_cast<db::Layout *> (&polygons.layout ()),
|
||||||
const_cast<db::Cell *> (&polygons.initial_cell ()),
|
const_cast<db::Cell *> (&polygons.initial_cell ()),
|
||||||
|
|
|
||||||
|
|
@ -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
|
// Edge to Edge relation implementation
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -246,6 +246,76 @@ private:
|
||||||
EdgeAngleChecker m_checker;
|
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
|
* @brief A predicate defining edge a interacts with b
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -252,9 +252,16 @@ namespace std
|
||||||
h = hfunc_coord (o.bgn_ext (), h);
|
h = hfunc_coord (o.bgn_ext (), h);
|
||||||
h = hfunc_coord (o.end_ext (), h);
|
h = hfunc_coord (o.end_ext (), h);
|
||||||
h = hfunc_coord (o.width (), 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) {
|
for (typename db::path<C>::iterator p = o.begin (); p != o.end (); ++p) {
|
||||||
|
if (--n == 0) {
|
||||||
|
h = hfunc (o.points (), h);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
h = hfunc (*p, h);
|
h = hfunc (*p, h);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -280,9 +287,16 @@ namespace std
|
||||||
template <class C>
|
template <class C>
|
||||||
size_t hfunc (const db::polygon_contour<C> &o, size_t h)
|
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) {
|
for (typename db::polygon_contour<C>::simple_iterator i = o.begin (); i != o.end (); ++i) {
|
||||||
|
if (--n == 0) {
|
||||||
|
h = hfunc (o.size (), h);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
h = hfunc (*i, h);
|
h = hfunc (*i, h);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -309,9 +323,16 @@ namespace std
|
||||||
size_t hfunc (const db::polygon<C> &o, size_t h)
|
size_t hfunc (const db::polygon<C> &o, size_t h)
|
||||||
{
|
{
|
||||||
h = hfunc (o.hull (), 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) {
|
for (size_t i = 0; i < o.holes (); ++i) {
|
||||||
|
if (--n == 0) {
|
||||||
|
h = hfunc (o.holes (), h);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
h = hfunc (o.hole (int (i)), h);
|
h = hfunc (o.hole (int (i)), h);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -189,15 +189,22 @@ public:
|
||||||
typedef typename Ref::shape_type shape_type;
|
typedef typename Ref::shape_type shape_type;
|
||||||
typedef typename Ref::trans_type ref_trans_type;
|
typedef typename Ref::trans_type ref_trans_type;
|
||||||
|
|
||||||
shape_reference_translator_with_trans_from_shape_ref (db::Layout *target_layout, const Trans &trans)
|
shape_reference_translator_with_trans_from_shape_ref (db::Layout *target_layout)
|
||||||
: mp_layout (target_layout), m_trans (trans), m_ref_trans (trans), m_bare_trans (Trans (m_ref_trans.inverted ()) * trans)
|
: mp_layout (target_layout)
|
||||||
{
|
{
|
||||||
// .. nothing yet ..
|
// .. 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
|
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 ()) {
|
if (m != m_cache.end ()) {
|
||||||
|
|
||||||
return Ref (m->second.first, ref_trans_type (m_trans * Trans (ref.trans ())) * m->second.second);
|
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);
|
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);
|
return Ref (ptr, ref_trans_type (m_trans * Trans (ref.trans ())) * red_trans);
|
||||||
|
|
||||||
|
|
@ -226,7 +233,7 @@ private:
|
||||||
Trans m_trans;
|
Trans m_trans;
|
||||||
ref_trans_type m_ref_trans;
|
ref_trans_type m_ref_trans;
|
||||||
Trans m_bare_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>
|
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_from_shape_ref<db::PolygonRef, Trans>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
shape_reference_translator_with_trans (db::Layout *target_layout, const Trans &trans)
|
shape_reference_translator_with_trans (db::Layout *target_layout)
|
||||||
: shape_reference_translator_with_trans_from_shape_ref<db::PolygonRef, Trans> (target_layout, trans)
|
: shape_reference_translator_with_trans_from_shape_ref<db::PolygonRef, Trans> (target_layout)
|
||||||
{
|
{
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
@ -247,12 +254,16 @@ class shape_reference_translator_with_trans
|
||||||
public:
|
public:
|
||||||
typedef Sh shape_type;
|
typedef Sh shape_type;
|
||||||
|
|
||||||
shape_reference_translator_with_trans (db::Layout * /*target_layout*/, const Trans &trans)
|
shape_reference_translator_with_trans (db::Layout * /*target_layout*/)
|
||||||
: m_trans (trans)
|
|
||||||
{
|
{
|
||||||
// .. nothing yet ..
|
// .. nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_trans (const Trans &trans)
|
||||||
|
{
|
||||||
|
m_trans = trans;
|
||||||
|
}
|
||||||
|
|
||||||
shape_type operator() (const shape_type &s) const
|
shape_type operator() (const shape_type &s) const
|
||||||
{
|
{
|
||||||
return s.transformed (m_trans);
|
return s.transformed (m_trans);
|
||||||
|
|
@ -353,13 +364,20 @@ local_processor_cell_context<TS, TI, TR>::propagate (unsigned int output_layer,
|
||||||
return;
|
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) {
|
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_context != 0);
|
||||||
tl_assert (d->parent != 0);
|
tl_assert (d->parent != 0);
|
||||||
|
|
||||||
db::Layout *subject_layout = d->parent->layout ();
|
if (subject_layout != d->parent->layout ()) {
|
||||||
shape_reference_translator_with_trans<TR, db::ICplxTrans> rt (subject_layout, d->cell_inst);
|
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;
|
std::vector<TR> new_refs;
|
||||||
new_refs.reserve (res.size ());
|
new_refs.reserve (res.size ());
|
||||||
for (typename std::unordered_set<TR>::const_iterator r = res.begin (); r != res.end (); ++r) {
|
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;
|
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)
|
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 ..
|
// nothing yet ..
|
||||||
}
|
}
|
||||||
|
|
@ -1195,6 +1213,7 @@ private:
|
||||||
unsigned int m_subject_layer;
|
unsigned int m_subject_layer;
|
||||||
db::Coord m_dist;
|
db::Coord m_dist;
|
||||||
interactions_type *mp_result;
|
interactions_type *mp_result;
|
||||||
|
db::shape_reference_translator_with_trans<TI, db::ICplxTrans> m_rt;
|
||||||
|
|
||||||
void
|
void
|
||||||
collect_instance_shape_interactions (const db::CellInstArray *inst, unsigned int layer, const TI &ref, db::Coord dist)
|
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 ()) {
|
if (! cbox.empty ()) {
|
||||||
|
|
||||||
db::ICplxTrans tni = tn.inverted ();
|
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;
|
std::set<TI> *shapes = 0;
|
||||||
|
|
||||||
|
|
@ -1223,7 +1242,7 @@ private:
|
||||||
if (! shapes) {
|
if (! shapes) {
|
||||||
shapes = & (*mp_result) [std::make_pair (cell.cell_index (), tn)].second [layer];
|
shapes = & (*mp_result) [std::make_pair (cell.cell_index (), tn)].second [layer];
|
||||||
}
|
}
|
||||||
shapes->insert (rt (ref));
|
shapes->insert (m_rt (ref));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3076,6 +3076,7 @@ public:
|
||||||
typedef typename Poly::coord_type coord_type;
|
typedef typename Poly::coord_type coord_type;
|
||||||
typedef typename Poly::point_type point_type;
|
typedef typename Poly::point_type point_type;
|
||||||
typedef typename Poly::box_type box_type;
|
typedef typename Poly::box_type box_type;
|
||||||
|
typedef typename Poly::edge_type edge_type;
|
||||||
typedef Trans trans_type;
|
typedef Trans trans_type;
|
||||||
typedef Poly polygon_type;
|
typedef Poly polygon_type;
|
||||||
typedef db::polygon_edge_iterator<Poly, trans_type> polygon_edge_iterator;
|
typedef db::polygon_edge_iterator<Poly, trans_type> polygon_edge_iterator;
|
||||||
|
|
|
||||||
|
|
@ -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
|
// TODO: move to generic header
|
||||||
static bool interact (const db::Box &box, const db::Edge &e)
|
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>
|
template <class PolygonType>
|
||||||
void
|
void
|
||||||
poly2poly_check<PolygonType>::process ()
|
poly2poly_check<PolygonType>::process ()
|
||||||
|
|
|
||||||
|
|
@ -310,6 +310,7 @@ class DB_PUBLIC poly2poly_check
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef typename PolygonType::box_type box_type;
|
typedef typename PolygonType::box_type box_type;
|
||||||
|
typedef typename PolygonType::edge_type edge_type;
|
||||||
|
|
||||||
poly2poly_check (Edge2EdgeCheckBase &output);
|
poly2poly_check (Edge2EdgeCheckBase &output);
|
||||||
poly2poly_check ();
|
poly2poly_check ();
|
||||||
|
|
@ -321,6 +322,8 @@ public:
|
||||||
void connect (Edge2EdgeCheckBase &output);
|
void connect (Edge2EdgeCheckBase &output);
|
||||||
void enter (const PolygonType &o, size_t p);
|
void enter (const PolygonType &o, size_t p);
|
||||||
void enter (const PolygonType &o, size_t p, const box_type &search_box);
|
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 ();
|
void process ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -122,8 +122,8 @@ static bool shields_interaction (const db::EdgePair &ep, const P &poly)
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class TS, class TI>
|
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)
|
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_has_other (has_other), m_other_is_merged (other_is_merged), m_options (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 ..
|
// .. 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);
|
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);
|
poly2poly_check<TS> poly_check (edge_check);
|
||||||
|
|
||||||
std::list<TS> heap;
|
|
||||||
std::unordered_set<TI> polygons;
|
std::unordered_set<TI> polygons;
|
||||||
|
std::unordered_set<TS> spolygons;
|
||||||
|
|
||||||
|
db::EdgeProcessor ep;
|
||||||
|
ep.set_base_verbosity (50);
|
||||||
|
|
||||||
std::set<unsigned int> ids;
|
std::set<unsigned int> ids;
|
||||||
for (typename shape_interactions<TS, TI>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
for (auto 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 j = i->second.begin (); j != i->second.end (); ++j) {
|
||||||
ids.insert (*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::Vector e (edge_check.distance (), edge_check.distance ());
|
||||||
|
|
||||||
db::Box subject_box;
|
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));
|
subject_box += db::box_convert<TS> () (interactions.subject_shape (i->first));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (edge_check.requires_different_layers ()) {
|
if (edge_check.requires_different_layers ()) {
|
||||||
db::Box intruder_box;
|
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);
|
intruder_box += db::box_convert<TI> () (interactions.intruder_shape (*id).second);
|
||||||
}
|
}
|
||||||
common_box = subject_box.enlarged (e) & intruder_box.enlarged (e);
|
common_box = subject_box.enlarged (e) & intruder_box.enlarged (e);
|
||||||
|
|
@ -245,7 +248,10 @@ check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, const shape
|
||||||
if (m_has_other) {
|
if (m_has_other) {
|
||||||
|
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
for (typename shape_interactions<TS, TI>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
|
||||||
|
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);
|
const TS &subject = interactions.subject_shape (i->first);
|
||||||
if (! take_all) {
|
if (! take_all) {
|
||||||
poly_check.enter (subject, n, common_box);
|
poly_check.enter (subject, n, common_box);
|
||||||
|
|
@ -255,6 +261,39 @@ check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, const shape
|
||||||
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
|
// merge the intruders to remove inner edges
|
||||||
|
|
||||||
if (ids.empty ()) {
|
if (ids.empty ()) {
|
||||||
|
|
@ -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
|
// 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
|
// the processor. Reason: the search range is limited, hence not all necessary components may have been
|
||||||
// captured.
|
// captured.
|
||||||
db::EdgeProcessor ep;
|
|
||||||
ep.set_base_verbosity (50);
|
|
||||||
|
|
||||||
ep.clear ();
|
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;
|
const TI &is = interactions.intruder_shape (*id).second;
|
||||||
for (typename TI::polygon_edge_iterator e = is.begin_edge (); ! e.at_end (); ++e) {
|
for (auto e = is.begin_edge (); ! e.at_end (); ++e) {
|
||||||
ep.insert (*e, i);
|
ep.insert (*e, nn);
|
||||||
}
|
}
|
||||||
++i;
|
++nn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @@@ Use edges directly
|
||||||
polygons.clear ();
|
polygons.clear ();
|
||||||
|
|
||||||
db::polygon_ref_generator<TI> ps (layout, polygons);
|
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);
|
ep.process (pg, op);
|
||||||
|
|
||||||
n = 1;
|
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) {
|
if (! take_all) {
|
||||||
poly_check.enter (*o, n, common_box);
|
poly_check.enter (*o, n, common_box);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -300,7 +338,7 @@ check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, const shape
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
n = 1;
|
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) {
|
if (! take_all) {
|
||||||
poly_check.enter (interactions.intruder_shape (*id).second, n, common_box);
|
poly_check.enter (interactions.intruder_shape (*id).second, n, common_box);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -313,14 +351,19 @@ check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, const shape
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
if (m_is_merged || (interactions.size () == 1 && ids.empty () && interactions.subject_shape (interactions.begin ()->first).is_box ())) {
|
||||||
|
|
||||||
|
// no merge required
|
||||||
|
|
||||||
// NOTE: we need to eliminate identical shapes from intruders and subjects because those will shield
|
// NOTE: we need to eliminate identical shapes from intruders and subjects because those will shield
|
||||||
|
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
|
std::unordered_set<TI> subjects;
|
||||||
|
|
||||||
for (typename shape_interactions<TS, TI>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
|
for (auto i = interactions.begin (); i != interactions.end (); ++i) {
|
||||||
// we can't directly insert because TS may be != TI
|
// we can't directly insert because TS may be != TI
|
||||||
const TS &ts = interactions.subject_shape (i->first);
|
const TS &ts = interactions.subject_shape (i->first);
|
||||||
insert_into_hash (polygons, ts);
|
insert_into_hash (subjects, ts);
|
||||||
if (! take_all) {
|
if (! take_all) {
|
||||||
poly_check.enter (ts, n, common_box);
|
poly_check.enter (ts, n, common_box);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -331,16 +374,132 @@ check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, const shape
|
||||||
|
|
||||||
n = 1;
|
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) {
|
||||||
const TI &ti = interactions.intruder_shape (*id).second;
|
const TI &ti = interactions.intruder_shape (*id).second;
|
||||||
if (polygons.find (ti) == polygons.end ()) {
|
if (subjects.find (ti) == subjects.end ()) {
|
||||||
if (! take_all) {
|
if (! take_all) {
|
||||||
poly_check.enter (ti, n, common_box);
|
poly_check.enter (ti, n, common_box);
|
||||||
} else {
|
} else {
|
||||||
poly_check.enter (ti, n);
|
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;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -197,6 +197,19 @@ struct DB_PUBLIC RegionCheckOptions
|
||||||
* @brief Specifies whether to produce negative output
|
* @brief Specifies whether to produce negative output
|
||||||
*/
|
*/
|
||||||
bool negative;
|
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>
|
template <class TS, class TI>
|
||||||
|
|
@ -204,7 +217,7 @@ class check_local_operation
|
||||||
: public local_operation<TS, TI, db::EdgePair>
|
: public local_operation<TS, TI, db::EdgePair>
|
||||||
{
|
{
|
||||||
public:
|
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 db::Coord dist () const;
|
||||||
virtual OnEmptyIntruderHint on_empty_intruder_hint () const;
|
virtual OnEmptyIntruderHint on_empty_intruder_hint () const;
|
||||||
|
|
@ -216,6 +229,7 @@ public:
|
||||||
private:
|
private:
|
||||||
EdgeRelationFilter m_check;
|
EdgeRelationFilter m_check;
|
||||||
bool m_different_polygons;
|
bool m_different_polygons;
|
||||||
|
bool m_is_merged;
|
||||||
bool m_has_other;
|
bool m_has_other;
|
||||||
bool m_other_is_merged;
|
bool m_other_is_merged;
|
||||||
db::RegionCheckOptions m_options;
|
db::RegionCheckOptions m_options;
|
||||||
|
|
|
||||||
|
|
@ -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)
|
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");
|
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,
|
db::RegionCheckOptions (whole_edges,
|
||||||
metrics,
|
metrics,
|
||||||
ignore_angle.is_nil () ? 90 : ignore_angle.to_double (),
|
ignore_angle.is_nil () ? 90 : ignore_angle.to_double (),
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
|
|
||||||
#include "gsiDecl.h"
|
#include "gsiDecl.h"
|
||||||
|
#include "gsiEnums.h"
|
||||||
|
|
||||||
#include "dbEdgePairs.h"
|
#include "dbEdgePairs.h"
|
||||||
#include "dbEdges.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);
|
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)
|
static db::EdgePairs with_angle_both1 (const db::EdgePairs *r, double a, bool inverse)
|
||||||
{
|
{
|
||||||
db::EdgeOrientationFilter f (a, 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);
|
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)
|
static db::EdgePairs with_internal_angle1 (const db::EdgePairs *r, double a, bool inverse)
|
||||||
{
|
{
|
||||||
db::InternalAngleEdgePairFilter f (a, 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"
|
"This will filter edge pairs with at least one horizontal edge:\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@code\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"
|
"@/code\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This method has been added in version 0.27.1.\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 "
|
"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"
|
"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"
|
"\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"
|
"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"),
|
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"
|
"@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 "
|
"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"
|
"This will filter edge pairs with at least one horizontal edge:\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@code\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"
|
"@/code\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This method has been added in version 0.27.1.\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 "
|
"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"
|
"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"
|
"\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"
|
"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"),
|
method_ext ("with_area", with_area1, gsi::arg ("area"), gsi::arg ("inverse"),
|
||||||
"@brief Filters the edge pairs by the enclosed area\n"
|
"@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 "
|
"Filters the edge pairs in the edge pair collection by enclosed area. If \"inverse\" is false, only "
|
||||||
|
|
|
||||||
|
|
@ -212,6 +212,12 @@ static db::Edges with_angle2 (const db::Edges *r, double amin, double amax, bool
|
||||||
return r->filtered (f);
|
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)
|
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,
|
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."
|
"This method has been introduced in version 0.26."
|
||||||
) +
|
) +
|
||||||
method_ext ("with_length", with_length1, gsi::arg ("length"), gsi::arg ("inverse"),
|
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 "
|
"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 which have the given length are returned. If \"inverse\" is true, "
|
||||||
"edges not having the given length are returned.\n"
|
"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"),
|
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 "
|
"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 "
|
"edges which have a length larger or equal to \"min_length\" and less than \"max_length\" are "
|
||||||
"returned. If \"inverse\" is true, "
|
"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"
|
"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"),
|
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 "
|
"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 which have the given angle to the x-axis are returned. If \"inverse\" is true, "
|
||||||
"edges not having the given angle are returned.\n"
|
"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"
|
"This will select horizontal edges:\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@code\n"
|
"@code\n"
|
||||||
"horizontal = edges.with_orientation(0, false)\n"
|
"horizontal = edges.with_angle(0, false)\n"
|
||||||
"@/code\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),
|
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 "
|
"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 "
|
"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, "
|
"returned. If \"inverse\" is true, "
|
||||||
|
|
@ -648,6 +654,17 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
|
||||||
"\n"
|
"\n"
|
||||||
"The two \"include..\" arguments have been added in version 0.27."
|
"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"),
|
method ("insert", (void (db::Edges::*)(const db::Edge &)) &db::Edges::insert, gsi::arg ("edge"),
|
||||||
"@brief Inserts an edge\n"
|
"@brief Inserts an edge\n"
|
||||||
"\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"
|
"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 ());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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(min .. max)</tt></li>
|
||||||
<li><tt>layer.with_angle(value)</tt></li>
|
<li><tt>layer.with_angle(value)</tt></li>
|
||||||
<li><tt>layer.with_angle(min, max)</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>
|
</ul>
|
||||||
<p>
|
<p>
|
||||||
When called on an edge layer, the method selects edges by their angle,
|
When called on an edge layer, the method selects edges by their angle,
|
||||||
|
|
@ -3320,6 +3323,10 @@ ep2 = edge_pairs.with_angle(90, both)
|
||||||
</pre>
|
</pre>
|
||||||
</p><p>
|
</p><p>
|
||||||
A method delivering all objects not matching the angle criterion is <a href="#without_angle">without_angle</a>.
|
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>
|
</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>
|
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>
|
</p><p>
|
||||||
|
|
@ -3334,6 +3341,17 @@ The following images demonstrate some use cases of <a href="#with_angle">with_an
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</p><p>
|
</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.
|
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.
|
This feature has been deprecated. Use <a href="#corners">corners</a> instead.
|
||||||
</p>
|
</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(min .. max)</tt></li>
|
||||||
<li><tt>layer.without_angle(value)</tt></li>
|
<li><tt>layer.without_angle(value)</tt></li>
|
||||||
<li><tt>layer.without_angle(min, max)</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>
|
</ul>
|
||||||
<p>
|
<p>
|
||||||
The method basically is the inverse of <a href="#with_angle">with_angle</a>. It selects all edges
|
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
|
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.
|
edge pairs by the angles of their edges.
|
||||||
</p><p>
|
</p><p>
|
||||||
A note on the "both" modifier (without_angle called on edge pairs): "both" means that
|
A note on the "both" modifier (without_angle called on edge pairs): "both" means that
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,18 @@ module DRC
|
||||||
DRCBothEdges::new
|
DRCBothEdges::new
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def ortho
|
||||||
|
DRCOrthoEdges::new
|
||||||
|
end
|
||||||
|
|
||||||
|
def diagonal_only
|
||||||
|
DRCDiagonalOnlyEdges::new
|
||||||
|
end
|
||||||
|
|
||||||
|
def diagonal
|
||||||
|
DRCDiagonalEdges::new
|
||||||
|
end
|
||||||
|
|
||||||
def shift(x, y)
|
def shift(x, y)
|
||||||
self._context("shift") do
|
self._context("shift") do
|
||||||
RBA::DCplxTrans::new(RBA::DVector::new(_make_value(x) * self.dbu, _make_value(y) * self.dbu))
|
RBA::DCplxTrans::new(RBA::DVector::new(_make_value(x) * self.dbu, _make_value(y) * self.dbu))
|
||||||
|
|
|
||||||
|
|
@ -864,7 +864,10 @@ CODE
|
||||||
# @synopsis layer.with_angle(min .. max)
|
# @synopsis layer.with_angle(min .. max)
|
||||||
# @synopsis layer.with_angle(value)
|
# @synopsis layer.with_angle(value)
|
||||||
# @synopsis layer.with_angle(min, max)
|
# @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,
|
# When called on an edge layer, the method selects edges by their angle,
|
||||||
# measured against the horizontal axis in the mathematical sense.
|
# measured against the horizontal axis in the mathematical sense.
|
||||||
|
|
@ -893,6 +896,10 @@ CODE
|
||||||
# @/code
|
# @/code
|
||||||
#
|
#
|
||||||
# A method delivering all objects not matching the angle criterion is \without_angle.
|
# 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:
|
# The following images demonstrate some use cases of \with_angle and \without_angle:
|
||||||
#
|
#
|
||||||
|
|
@ -907,6 +914,17 @@ CODE
|
||||||
# @/tr
|
# @/tr
|
||||||
# @/table
|
# @/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.
|
# 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.
|
# This feature has been deprecated. Use \corners instead.
|
||||||
|
|
||||||
|
|
@ -916,11 +934,16 @@ CODE
|
||||||
# @synopsis layer.without_angle(min .. max)
|
# @synopsis layer.without_angle(min .. max)
|
||||||
# @synopsis layer.without_angle(value)
|
# @synopsis layer.without_angle(value)
|
||||||
# @synopsis layer.without_angle(min, max)
|
# @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
|
# 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
|
# 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.
|
# edge pairs by the angles of their edges.
|
||||||
#
|
#
|
||||||
# A note on the "both" modifier (without_angle called on edge pairs): "both" means that
|
# 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|
|
args = args.select do |a|
|
||||||
if a.is_a?(DRCBothEdges)
|
if a.is_a?(DRCBothEdges)
|
||||||
if !self.data.is_a?(RBA::EdgePairs)
|
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
|
end
|
||||||
f = :with_#{f}_both
|
f = :with_#{f}_both
|
||||||
false
|
false
|
||||||
|
|
@ -998,6 +1021,11 @@ CODE
|
||||||
a = args[0]
|
a = args[0]
|
||||||
if a.is_a?(Range)
|
if a.is_a?(Range)
|
||||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, result_class, f, a.begin, a.end, #{inv.inspect}))
|
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
|
else
|
||||||
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, result_class, f, a, #{inv.inspect}))
|
DRCLayer::new(@engine, @engine._tcmd(self.data, 0, result_class, f, a, #{inv.inspect}))
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,31 @@ module DRC
|
||||||
end
|
end
|
||||||
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
|
class DRCBothEdges
|
||||||
end
|
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
|
# A wrapper for the padding modes of with_density
|
||||||
class DRCDensityPadding
|
class DRCDensityPadding
|
||||||
attr_accessor :value
|
attr_accessor :value
|
||||||
|
|
|
||||||
|
|
@ -1328,3 +1328,13 @@ TEST(55d_drccount)
|
||||||
run_test (_this, "55", true);
|
run_test (_this, "55", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(56_angle_classes)
|
||||||
|
{
|
||||||
|
run_test (_this, "56", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(56d_angle_classes)
|
||||||
|
{
|
||||||
|
run_test (_this, "56", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -225,13 +225,13 @@ static size_t index_from_attr (const std::pair<const Attr *, const Attr *> &attr
|
||||||
size_t
|
size_t
|
||||||
SingleIndexedNetlistModel::circuit_count () const
|
SingleIndexedNetlistModel::circuit_count () const
|
||||||
{
|
{
|
||||||
return mp_netlist->circuit_count ();
|
return mp_netlist ? mp_netlist->circuit_count () : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
SingleIndexedNetlistModel::top_circuit_count () const
|
SingleIndexedNetlistModel::top_circuit_count () const
|
||||||
{
|
{
|
||||||
return mp_netlist->top_circuit_count ();
|
return mp_netlist ? mp_netlist->top_circuit_count () : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -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, 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, "")
|
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
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -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(100, 200, true).to_s, "(100,0;100,50)")
|
||||||
assert_equal(r.with_length(nil, 100, false).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
|
end
|
||||||
|
|
||||||
# interact
|
# interact
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue