mirror of https://github.com/KLayout/klayout.git
New *_sum quantifiers, doc enhancements, bug fixing
This commit is contained in:
parent
80d0229b7c
commit
80996a77fb
|
|
@ -14,7 +14,7 @@ def create_ref(mod, s)
|
|||
"<a href=\"/" + $loc + "/" + $1.downcase + "_ref_" + $2.downcase + ".xml\">#{s}</a>"
|
||||
elsif s =~ /(.*)#(.*)/
|
||||
if $2 != ""
|
||||
"<a href=\"/" + $loc + "/" + mod.downcase + "_ref_" + $1.downcase + ".xml#" + $2 + "\">#{s}</a>"
|
||||
"<a href=\"/" + $loc + "/" + mod.downcase + "_ref_" + $1.downcase + ".xml#" + $2 + "\">" + ($1 == "global" ? $2 : s) + "</a>"
|
||||
else
|
||||
"<a href=\"/" + $loc + "/" + mod.downcase + "_ref_" + $1.downcase + ".xml\">#{$1}</a>"
|
||||
end
|
||||
|
|
@ -23,6 +23,22 @@ def create_ref(mod, s)
|
|||
end
|
||||
end
|
||||
|
||||
def create_link(mod, s)
|
||||
if s =~ /(.*)::(.*)#(.*)/
|
||||
"<link href=\"/" + $loc + "/" + $1.downcase + "_ref_" + $2.downcase + ".xml#" + $3 + "\"/>"
|
||||
elsif s =~ /(.*)::(.*)/
|
||||
"<link href=\"/" + $loc + "/" + $1.downcase + "_ref_" + $2.downcase + ".xml\"/>"
|
||||
elsif s =~ /(.*)#(.*)/
|
||||
if $2 != ""
|
||||
"<link href=\"/" + $loc + "/" + mod.downcase + "_ref_" + $1.downcase + ".xml#" + $2 + "\"/>"
|
||||
else
|
||||
"<link href=\"/" + $loc + "/" + mod.downcase + "_ref_" + $1.downcase + ".xml\"/>"
|
||||
end
|
||||
else
|
||||
"<link href=\"#" + s + "\"/>"
|
||||
end
|
||||
end
|
||||
|
||||
def create_class_doc_ref(s)
|
||||
"<class_doc href=\"" + s + "\">#{s}</class_doc>"
|
||||
end
|
||||
|
|
@ -32,6 +48,7 @@ def escape(mod, s)
|
|||
gsub("<", "<").
|
||||
gsub(">", ">").
|
||||
gsub(/\\([\w:#]+)/) { create_ref(mod, $1) }.
|
||||
gsub(/\\\\([\w:#]+)/) { create_link(mod, $1) }.
|
||||
gsub(/RBA::([\w#]+)/) { create_class_doc_ref($1) }
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1046,15 +1046,14 @@ void region_cop_impl (AsIfFlatRegion *region, db::Shapes *output_to, db::Compoun
|
|||
db::local_processor<db::Polygon, db::Polygon, TR> proc;
|
||||
proc.set_base_verbosity (region->base_verbosity ());
|
||||
|
||||
bool needs_merged = node.wants_merged ();
|
||||
db::RegionIterator polygons (needs_merged ? region->begin_merged () : region->begin ());
|
||||
db::RegionIterator polygons (region->begin_merged ());
|
||||
|
||||
std::vector<generic_shape_iterator<db::Polygon> > others;
|
||||
std::vector<bool> foreign;
|
||||
std::vector<db::Region *> inputs = node.inputs ();
|
||||
for (std::vector<db::Region *>::const_iterator i = inputs.begin (); i != inputs.end (); ++i) {
|
||||
if (*i == subject_regionptr () || *i == foreign_regionptr ()) {
|
||||
others.push_back (needs_merged ? region->begin_merged () : region->begin ());
|
||||
others.push_back (region->begin_merged ());
|
||||
foreign.push_back (*i == foreign_regionptr ());
|
||||
} else {
|
||||
others.push_back ((*i)->begin ());
|
||||
|
|
|
|||
|
|
@ -428,17 +428,6 @@ CompoundRegionMultiInputOperationNode::wants_variants () const
|
|||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
CompoundRegionMultiInputOperationNode::wants_merged () const
|
||||
{
|
||||
for (tl::shared_collection<CompoundRegionOperationNode>::const_iterator i = m_children.begin (); i != m_children.end (); ++i) {
|
||||
if (i->wants_merged ()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
|
||||
CompoundRegionLogicalBoolOperationNode::CompoundRegionLogicalBoolOperationNode (LogicalOp op, bool invert, const std::vector<CompoundRegionOperationNode *> &inputs)
|
||||
|
|
@ -1188,8 +1177,8 @@ template void CompoundRegionJoinOperationNode::implement_compute_local<db::Polyg
|
|||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
|
||||
CompoundRegionFilterOperationNode::CompoundRegionFilterOperationNode (PolygonFilterBase *filter, CompoundRegionOperationNode *input, bool owns_filter)
|
||||
: CompoundRegionMultiInputOperationNode (input), mp_filter (filter), m_owns_filter (owns_filter)
|
||||
CompoundRegionFilterOperationNode::CompoundRegionFilterOperationNode (PolygonFilterBase *filter, CompoundRegionOperationNode *input, bool owns_filter, bool sum_of_set)
|
||||
: CompoundRegionMultiInputOperationNode (input), mp_filter (filter), m_owns_filter (owns_filter), m_sum_of_set (sum_of_set)
|
||||
{
|
||||
set_description ("filter");
|
||||
}
|
||||
|
|
@ -1214,22 +1203,10 @@ CompoundRegionFilterOperationNode::do_compute_local (db::Layout *layout, const s
|
|||
implement_compute_local (layout, interactions, results, max_vertex_count, area_ratio);
|
||||
}
|
||||
|
||||
bool
|
||||
CompoundRegionFilterOperationNode::is_selected (const db::Polygon &p) const
|
||||
{
|
||||
return mp_filter->selected (p);
|
||||
}
|
||||
|
||||
bool
|
||||
CompoundRegionFilterOperationNode::is_selected (const db::PolygonRef &p) const
|
||||
{
|
||||
return mp_filter->selected (p.obj ().transformed (p.trans ()));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
|
||||
CompoundRegionEdgeFilterOperationNode::CompoundRegionEdgeFilterOperationNode (EdgeFilterBase *filter, CompoundRegionOperationNode *input, bool owns_filter)
|
||||
: CompoundRegionMultiInputOperationNode (input), mp_filter (filter), m_owns_filter (owns_filter)
|
||||
CompoundRegionEdgeFilterOperationNode::CompoundRegionEdgeFilterOperationNode (EdgeFilterBase *filter, CompoundRegionOperationNode *input, bool owns_filter, bool sum_of)
|
||||
: CompoundRegionMultiInputOperationNode (input), mp_filter (filter), m_owns_filter (owns_filter), m_sum_of (sum_of)
|
||||
{
|
||||
set_description ("filter");
|
||||
}
|
||||
|
|
@ -1254,12 +1231,6 @@ CompoundRegionEdgeFilterOperationNode::do_compute_local (db::Layout *layout, con
|
|||
implement_compute_local (layout, interactions, results, max_vertex_count, area_ratio);
|
||||
}
|
||||
|
||||
bool
|
||||
CompoundRegionEdgeFilterOperationNode::is_selected (const db::Edge &p) const
|
||||
{
|
||||
return mp_filter->selected (p);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
|
||||
CompoundRegionEdgePairFilterOperationNode::CompoundRegionEdgePairFilterOperationNode (EdgePairFilterBase *filter, CompoundRegionOperationNode *input, bool owns_filter)
|
||||
|
|
@ -1622,12 +1593,6 @@ CompoundRegionCheckOperationNode::computed_dist () const
|
|||
return m_check.distance ();
|
||||
}
|
||||
|
||||
bool
|
||||
CompoundRegionCheckOperationNode::wants_merged () const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CompoundRegionCheckOperationNode::do_compute_local (db::Layout *layout, const shape_interactions<db::Polygon, db::Polygon> &interactions, std::vector<std::unordered_set<db::EdgePair> > &results, size_t max_vertex_count, double area_ratio) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -147,11 +147,6 @@ public:
|
|||
*/
|
||||
virtual bool wants_variants () const { return false; }
|
||||
|
||||
/**
|
||||
* @brief Returns true, if the processor wants to have merged primary inputs
|
||||
*/
|
||||
virtual bool wants_merged () const { return false; }
|
||||
|
||||
void compute_local (db::Layout *layout, const shape_interactions<db::Polygon, db::Polygon> &interactions, std::vector<std::unordered_set<db::Polygon> > &results, size_t max_vertex_count, double area_ratio) const
|
||||
{
|
||||
implement_compute_local (layout, interactions, results, max_vertex_count, area_ratio);
|
||||
|
|
@ -413,7 +408,6 @@ public:
|
|||
|
||||
virtual const TransformationReducer *vars () const;
|
||||
virtual bool wants_variants () const;
|
||||
virtual bool wants_merged () const;
|
||||
|
||||
virtual void invalidate_cache () const;
|
||||
|
||||
|
|
@ -641,7 +635,6 @@ public:
|
|||
virtual const db::TransformationReducer *vars () const { return mp_vars; }
|
||||
virtual bool wants_variants () const { return m_wants_variants; }
|
||||
virtual db::Coord computed_dist () const { return m_op->dist (); }
|
||||
virtual bool wants_merged () const { return true; }
|
||||
|
||||
virtual std::vector<db::Region *> inputs () const
|
||||
{
|
||||
|
|
@ -892,7 +885,7 @@ class DB_PUBLIC CompoundRegionFilterOperationNode
|
|||
: public CompoundRegionMultiInputOperationNode
|
||||
{
|
||||
public:
|
||||
CompoundRegionFilterOperationNode (PolygonFilterBase *filter, CompoundRegionOperationNode *input, bool owns_filter = false);
|
||||
CompoundRegionFilterOperationNode (PolygonFilterBase *filter, CompoundRegionOperationNode *input, bool owns_filter = false, bool sum_of_set = false);
|
||||
~CompoundRegionFilterOperationNode ();
|
||||
|
||||
// specifies the result type
|
||||
|
|
@ -903,14 +896,11 @@ public:
|
|||
|
||||
virtual const TransformationReducer *vars () const { return mp_filter->vars (); }
|
||||
virtual bool wants_variants () const { return mp_filter->wants_variants (); }
|
||||
virtual bool wants_merged () const { return true; }
|
||||
|
||||
private:
|
||||
PolygonFilterBase *mp_filter;
|
||||
bool m_owns_filter;
|
||||
|
||||
bool is_selected (const db::Polygon &p) const;
|
||||
bool is_selected (const db::PolygonRef &p) const;
|
||||
bool m_sum_of_set;
|
||||
|
||||
template <class T>
|
||||
void implement_compute_local (db::Layout *layout, const shape_interactions<T, T> &interactions, std::vector<std::unordered_set<T> > &results, size_t max_vertex_count, double area_ratio) const
|
||||
|
|
@ -920,9 +910,15 @@ private:
|
|||
|
||||
child (0)->compute_local (layout, interactions, one, max_vertex_count, area_ratio);
|
||||
|
||||
for (typename std::unordered_set<T>::const_iterator p = one.front ().begin (); p != one.front ().end (); ++p) {
|
||||
if (is_selected (*p)) {
|
||||
results.front ().insert (*p);
|
||||
if (m_sum_of_set) {
|
||||
if (mp_filter->selected_set (one.front ())) {
|
||||
results.front ().insert (one.front ().begin (), one.front ().end ());
|
||||
}
|
||||
} else {
|
||||
for (typename std::unordered_set<T>::const_iterator p = one.front ().begin (); p != one.front ().end (); ++p) {
|
||||
if (mp_filter->selected (*p)) {
|
||||
results.front ().insert (*p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -932,7 +928,7 @@ class DB_PUBLIC CompoundRegionEdgeFilterOperationNode
|
|||
: public CompoundRegionMultiInputOperationNode
|
||||
{
|
||||
public:
|
||||
CompoundRegionEdgeFilterOperationNode (EdgeFilterBase *filter, CompoundRegionOperationNode *input, bool owns_filter = false);
|
||||
CompoundRegionEdgeFilterOperationNode (EdgeFilterBase *filter, CompoundRegionOperationNode *input, bool owns_filter = false, bool sum_of = false);
|
||||
~CompoundRegionEdgeFilterOperationNode ();
|
||||
|
||||
// specifies the result type
|
||||
|
|
@ -943,13 +939,11 @@ public:
|
|||
|
||||
virtual const TransformationReducer *vars () const { return mp_filter->vars (); }
|
||||
virtual bool wants_variants () const { return mp_filter->wants_variants (); }
|
||||
virtual bool wants_merged () const { return true; }
|
||||
|
||||
private:
|
||||
EdgeFilterBase *mp_filter;
|
||||
bool m_owns_filter;
|
||||
|
||||
bool is_selected (const db::Edge &p) const;
|
||||
bool m_sum_of;
|
||||
|
||||
template <class T>
|
||||
void implement_compute_local (db::Layout *layout, const shape_interactions<T, T> &interactions, std::vector<std::unordered_set<db::Edge> > &results, size_t max_vertex_count, double area_ratio) const
|
||||
|
|
@ -959,9 +953,15 @@ private:
|
|||
|
||||
child (0)->compute_local (layout, interactions, one, max_vertex_count, area_ratio);
|
||||
|
||||
for (typename std::unordered_set<db::Edge>::const_iterator p = one.front ().begin (); p != one.front ().end (); ++p) {
|
||||
if (is_selected (*p)) {
|
||||
results.front ().insert (*p);
|
||||
if (m_sum_of) {
|
||||
if (mp_filter->selected (one.front ())) {
|
||||
results.front ().insert (one.front ().begin (), one.front ().end ());
|
||||
}
|
||||
} else {
|
||||
for (typename std::unordered_set<db::Edge>::const_iterator p = one.front ().begin (); p != one.front ().end (); ++p) {
|
||||
if (mp_filter->selected (*p)) {
|
||||
results.front ().insert (*p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -982,7 +982,6 @@ public:
|
|||
|
||||
virtual const TransformationReducer *vars () const { return mp_filter->vars (); }
|
||||
virtual bool wants_variants () const { return mp_filter->wants_variants (); }
|
||||
virtual bool wants_merged () const { return true; }
|
||||
|
||||
private:
|
||||
EdgePairFilterBase *mp_filter;
|
||||
|
|
@ -1020,7 +1019,6 @@ public:
|
|||
|
||||
virtual const TransformationReducer *vars () const { return mp_proc->vars (); }
|
||||
virtual bool wants_variants () const { return mp_proc->wants_variants (); }
|
||||
virtual bool wants_merged () const { return ! mp_proc->requires_raw_input (); }
|
||||
|
||||
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::Polygon, db::Polygon> &interactions, std::vector<std::unordered_set<db::Polygon> > &results, size_t max_vertex_count, double area_ratio) const;
|
||||
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::PolygonRef, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::PolygonRef> > &results, size_t max_vertex_count, double area_ratio) const;
|
||||
|
|
@ -1147,7 +1145,6 @@ public:
|
|||
|
||||
virtual const TransformationReducer *vars () const { return mp_proc->vars (); }
|
||||
virtual bool wants_variants () const { return mp_proc->wants_variants (); }
|
||||
virtual bool wants_merged () const { return true; }
|
||||
|
||||
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::Polygon, db::Polygon> &interactions, std::vector<std::unordered_set<db::Polygon> > &results, size_t max_vertex_count, double area_ratio) const;
|
||||
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::PolygonRef, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::PolygonRef> > &results, size_t max_vertex_count, double area_ratio) const;
|
||||
|
|
@ -1188,7 +1185,6 @@ public:
|
|||
|
||||
virtual const TransformationReducer *vars () const { return mp_proc->vars (); }
|
||||
virtual bool wants_variants () const { return mp_proc->wants_variants (); }
|
||||
virtual bool wants_merged () const { return true; }
|
||||
|
||||
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::Polygon, db::Polygon> &interactions, std::vector<std::unordered_set<db::Edge> > &results, size_t max_vertex_count, double area_ratio) const;
|
||||
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::PolygonRef, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::Edge> > &results, size_t max_vertex_count, double area_ratio) const;
|
||||
|
|
@ -1228,7 +1224,6 @@ public:
|
|||
|
||||
virtual const TransformationReducer *vars () const { return mp_proc->vars (); }
|
||||
virtual bool wants_variants () const { return mp_proc->wants_variants (); }
|
||||
virtual bool wants_merged () const { return true; }
|
||||
|
||||
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::Polygon, db::Polygon> &interactions, std::vector<std::unordered_set<db::Polygon> > &results, size_t max_vertex_count, double area_ratio) const;
|
||||
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::PolygonRef, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::PolygonRef> > &results, size_t max_vertex_count, double area_ratio) const;
|
||||
|
|
@ -1269,7 +1264,6 @@ public:
|
|||
|
||||
virtual const TransformationReducer *vars () const { return mp_proc->vars (); }
|
||||
virtual bool wants_variants () const { return mp_proc->wants_variants (); }
|
||||
virtual bool wants_merged () const { return true; }
|
||||
|
||||
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::Polygon, db::Polygon> &interactions, std::vector<std::unordered_set<db::Edge> > &results, size_t max_vertex_count, double area_ratio) const;
|
||||
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::PolygonRef, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::Edge> > &results, size_t max_vertex_count, double area_ratio) const;
|
||||
|
|
@ -1307,7 +1301,6 @@ public:
|
|||
|
||||
virtual const TransformationReducer *vars () const { return mp_proc->vars (); }
|
||||
virtual bool wants_variants () const { return mp_proc->wants_variants (); }
|
||||
virtual bool wants_merged () const { return true; }
|
||||
|
||||
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::Polygon, db::Polygon> &interactions, std::vector<std::unordered_set<db::Edge> > &results, size_t max_vertex_count, double area_ratio) const;
|
||||
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::PolygonRef, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::Edge> > &results, size_t max_vertex_count, double area_ratio) const;
|
||||
|
|
@ -1358,7 +1351,6 @@ public:
|
|||
|
||||
virtual const TransformationReducer *vars () const { return mp_proc->vars (); }
|
||||
virtual bool wants_variants () const { return mp_proc->wants_variants (); }
|
||||
virtual bool wants_merged () const { return true; }
|
||||
|
||||
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::Polygon, db::Polygon> &interactions, std::vector<std::unordered_set<db::EdgePair> > &results, size_t max_vertex_count, double area_ratio) const;
|
||||
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::PolygonRef, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::EdgePair> > &results, size_t max_vertex_count, double area_ratio) const;
|
||||
|
|
@ -1417,7 +1409,6 @@ public:
|
|||
|
||||
virtual OnEmptyIntruderHint on_empty_intruder_hint () const;
|
||||
virtual db::Coord computed_dist () const;
|
||||
virtual bool wants_merged () const;
|
||||
|
||||
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::Polygon, db::Polygon> &interactions, std::vector<std::unordered_set<db::EdgePair> > &results, size_t max_vertex_count, double area_ratio) const;
|
||||
virtual void do_compute_local (db::Layout *layout, const shape_interactions<db::PolygonRef, db::PolygonRef> &interactions, std::vector<std::unordered_set<db::EdgePair> > &results, size_t max_vertex_count, double area_ratio) const;
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@
|
|||
#include "dbHierProcessor.h"
|
||||
#include "dbEmptyEdges.h"
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
|
|
|
|||
|
|
@ -1362,8 +1362,7 @@ Output *region_cop_impl (DeepRegion *region, db::CompoundRegionOperationNode &no
|
|||
proc.set_base_verbosity (region->base_verbosity ());
|
||||
proc.set_threads (region->deep_layer ().store ()->threads ());
|
||||
|
||||
bool needs_merged = node.wants_merged ();
|
||||
const db::DeepLayer &polygons (needs_merged ? region->merged_deep_layer () : region->deep_layer ());
|
||||
const db::DeepLayer &polygons (region->merged_deep_layer ());
|
||||
|
||||
std::vector<unsigned int> other_layers;
|
||||
for (std::vector<db::Region *>::const_iterator i = inputs.begin (); i != inputs.end (); ++i) {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include "dbGenericShapeIterator.h"
|
||||
|
||||
#include <list>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace db {
|
||||
|
||||
|
|
@ -115,10 +116,16 @@ public:
|
|||
|
||||
/**
|
||||
* @brief Filters the edge
|
||||
* If this method returns true, the polygon is kept. Otherwise it's discarded.
|
||||
* If this method returns true, the edge is kept. Otherwise it's discarded.
|
||||
*/
|
||||
virtual bool selected (const db::Edge &edge) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Filters the edge set
|
||||
* If this method returns true, the edges are kept. Otherwise they are discarded.
|
||||
*/
|
||||
virtual bool selected (const std::unordered_set<db::Edge> &edge) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Returns the transformation reducer for building cell variants
|
||||
* This method may return 0. In this case, not cell variants are built.
|
||||
|
|
|
|||
|
|
@ -24,11 +24,14 @@
|
|||
#define HDR_dbEdgesUtils
|
||||
|
||||
#include "dbCommon.h"
|
||||
#include "dbHash.h"
|
||||
#include "dbEdges.h"
|
||||
#include "dbBoxScanner.h"
|
||||
#include "dbPolygonTools.h"
|
||||
#include "tlSelect.h"
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
namespace db {
|
||||
|
||||
class PolygonSink;
|
||||
|
|
@ -65,12 +68,19 @@ struct DB_PUBLIC EdgeLengthFilter
|
|||
*/
|
||||
virtual bool selected (const db::Edge &edge) const
|
||||
{
|
||||
length_type l = edge.length ();
|
||||
if (! m_inverse) {
|
||||
return l >= m_lmin && l < m_lmax;
|
||||
} else {
|
||||
return ! (l >= m_lmin && l < m_lmax);
|
||||
return check (edge.length ());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true if the total edge length matches the criterion
|
||||
*/
|
||||
bool selected (const std::unordered_set<db::Edge> &edges) const
|
||||
{
|
||||
length_type l = 0;
|
||||
for (std::unordered_set<db::Edge>::const_iterator e = edges.begin (); e != edges.end (); ++e) {
|
||||
l += e->length ();
|
||||
}
|
||||
return check (l);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -101,6 +111,15 @@ private:
|
|||
length_type m_lmin, m_lmax;
|
||||
bool m_inverse;
|
||||
db::MagnificationReducer m_vars;
|
||||
|
||||
virtual bool check (length_type l) const
|
||||
{
|
||||
if (! m_inverse) {
|
||||
return l >= m_lmin && l < m_lmax;
|
||||
} else {
|
||||
return ! (l >= m_lmin && l < m_lmax);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -179,6 +198,19 @@ struct DB_PUBLIC EdgeOrientationFilter
|
|||
*/
|
||||
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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -3192,7 +3192,15 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief The area ratio of the polygon
|
||||
*/
|
||||
double area_ratio () const
|
||||
{
|
||||
return this->obj ().area_ratio ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The area of the polygon
|
||||
*/
|
||||
area_type area () const
|
||||
|
|
|
|||
|
|
@ -64,6 +64,24 @@ public:
|
|||
*/
|
||||
virtual bool selected (const db::Polygon &polygon) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Filters the polygon reference
|
||||
* If this method returns true, the polygon is kept. Otherwise it's discarded.
|
||||
*/
|
||||
virtual bool selected (const db::PolygonRef &polygon) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Filters the set of polygons (taking the overall properties)
|
||||
* If this method returns true, the polygon is kept. Otherwise it's discarded.
|
||||
*/
|
||||
virtual bool selected_set (const std::unordered_set<db::Polygon> &polygons) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Filters the set of polygon references (taking the overall properties)
|
||||
* If this method returns true, the polygon is kept. Otherwise it's discarded.
|
||||
*/
|
||||
virtual bool selected_set (const std::unordered_set<db::PolygonRef> &polygons) const = 0;
|
||||
|
||||
/**
|
||||
* @brief Returns the transformation reducer for building cell variants
|
||||
* This method may return 0. In this case, not cell variants are built.
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@
|
|||
#include "dbLocalOperation.h"
|
||||
#include "dbEdgeProcessor.h"
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
|
|
|
|||
|
|
@ -446,13 +446,8 @@ RegionPerimeterFilter::RegionPerimeterFilter (perimeter_type pmin, perimeter_typ
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
bool RegionPerimeterFilter::selected (const db::Polygon &poly) const
|
||||
bool RegionPerimeterFilter::check (perimeter_type p) const
|
||||
{
|
||||
perimeter_type p = 0;
|
||||
for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end () && p < m_pmax; ++e) {
|
||||
p += (*e).length ();
|
||||
}
|
||||
|
||||
if (! m_inverse) {
|
||||
return p >= m_pmin && p < m_pmax;
|
||||
} else {
|
||||
|
|
@ -460,6 +455,34 @@ bool RegionPerimeterFilter::selected (const db::Polygon &poly) const
|
|||
}
|
||||
}
|
||||
|
||||
bool RegionPerimeterFilter::selected (const db::Polygon &poly) const
|
||||
{
|
||||
return check (poly.perimeter ());
|
||||
}
|
||||
|
||||
bool RegionPerimeterFilter::selected (const db::PolygonRef &poly) const
|
||||
{
|
||||
return check (poly.perimeter ());
|
||||
}
|
||||
|
||||
bool RegionPerimeterFilter::selected_set (const std::unordered_set<db::Polygon> &poly) const
|
||||
{
|
||||
perimeter_type ps = 0;
|
||||
for (std::unordered_set<db::Polygon>::const_iterator p = poly.begin (); p != poly.end (); ++p) {
|
||||
ps += p->perimeter ();
|
||||
}
|
||||
return check (ps);
|
||||
}
|
||||
|
||||
bool RegionPerimeterFilter::selected_set (const std::unordered_set<db::PolygonRef> &poly) const
|
||||
{
|
||||
perimeter_type ps = 0;
|
||||
for (std::unordered_set<db::PolygonRef>::const_iterator p = poly.begin (); p != poly.end (); ++p) {
|
||||
ps += p->perimeter ();
|
||||
}
|
||||
return check (ps);
|
||||
}
|
||||
|
||||
const TransformationReducer *RegionPerimeterFilter::vars () const
|
||||
{
|
||||
return &m_vars;
|
||||
|
|
@ -474,10 +497,8 @@ RegionAreaFilter::RegionAreaFilter (area_type amin, area_type amax, bool inverse
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
bool
|
||||
RegionAreaFilter::selected (const db::Polygon &poly) const
|
||||
bool RegionAreaFilter::check (area_type a) const
|
||||
{
|
||||
area_type a = poly.area ();
|
||||
if (! m_inverse) {
|
||||
return a >= m_amin && a < m_amax;
|
||||
} else {
|
||||
|
|
@ -485,6 +506,34 @@ RegionAreaFilter::selected (const db::Polygon &poly) const
|
|||
}
|
||||
}
|
||||
|
||||
bool RegionAreaFilter::selected (const db::Polygon &poly) const
|
||||
{
|
||||
return check (poly.area ());
|
||||
}
|
||||
|
||||
bool RegionAreaFilter::selected (const db::PolygonRef &poly) const
|
||||
{
|
||||
return check (poly.area ());
|
||||
}
|
||||
|
||||
bool RegionAreaFilter::selected_set (const std::unordered_set<db::Polygon> &poly) const
|
||||
{
|
||||
area_type as = 0;
|
||||
for (std::unordered_set<db::Polygon>::const_iterator p = poly.begin (); p != poly.end (); ++p) {
|
||||
as += p->area ();
|
||||
}
|
||||
return check (as);
|
||||
}
|
||||
|
||||
bool RegionAreaFilter::selected_set (const std::unordered_set<db::PolygonRef> &poly) const
|
||||
{
|
||||
area_type as = 0;
|
||||
for (std::unordered_set<db::PolygonRef>::const_iterator p = poly.begin (); p != poly.end (); ++p) {
|
||||
as += p->area ();
|
||||
}
|
||||
return check (as);
|
||||
}
|
||||
|
||||
const TransformationReducer *
|
||||
RegionAreaFilter::vars () const
|
||||
{
|
||||
|
|
@ -506,6 +555,12 @@ RectilinearFilter::selected (const db::Polygon &poly) const
|
|||
return poly.is_rectilinear () != m_inverse;
|
||||
}
|
||||
|
||||
bool
|
||||
RectilinearFilter::selected (const db::PolygonRef &poly) const
|
||||
{
|
||||
return poly.is_rectilinear () != m_inverse;
|
||||
}
|
||||
|
||||
const TransformationReducer *
|
||||
RectilinearFilter::vars () const
|
||||
{
|
||||
|
|
@ -532,6 +587,17 @@ RectangleFilter::selected (const db::Polygon &poly) const
|
|||
return ok != m_inverse;
|
||||
}
|
||||
|
||||
bool
|
||||
RectangleFilter::selected (const db::PolygonRef &poly) const
|
||||
{
|
||||
bool ok = poly.is_box ();
|
||||
if (ok && m_is_square) {
|
||||
db::Box box = poly.box ();
|
||||
ok = box.width () == box.height ();
|
||||
}
|
||||
return ok != m_inverse;
|
||||
}
|
||||
|
||||
const TransformationReducer *RectangleFilter::vars () const
|
||||
{
|
||||
return 0;
|
||||
|
|
@ -547,10 +613,9 @@ RegionBBoxFilter::RegionBBoxFilter (value_type vmin, value_type vmax, bool inver
|
|||
}
|
||||
|
||||
bool
|
||||
RegionBBoxFilter::selected (const db::Polygon &poly) const
|
||||
RegionBBoxFilter::check (const db::Box &box) const
|
||||
{
|
||||
value_type v = 0;
|
||||
db::Box box = poly.box ();
|
||||
if (m_parameter == BoxWidth) {
|
||||
v = box.width ();
|
||||
} else if (m_parameter == BoxHeight) {
|
||||
|
|
@ -569,6 +634,18 @@ RegionBBoxFilter::selected (const db::Polygon &poly) const
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
RegionBBoxFilter::selected (const db::Polygon &poly) const
|
||||
{
|
||||
return check (poly.box ());
|
||||
}
|
||||
|
||||
bool
|
||||
RegionBBoxFilter::selected (const db::PolygonRef &poly) const
|
||||
{
|
||||
return check (poly.box ());
|
||||
}
|
||||
|
||||
const TransformationReducer *
|
||||
RegionBBoxFilter::vars () const
|
||||
{
|
||||
|
|
@ -588,29 +665,54 @@ RegionRatioFilter::RegionRatioFilter (double vmin, bool min_included, double vma
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
bool RegionRatioFilter::selected (const db::Polygon &poly) const
|
||||
template <class P>
|
||||
static double compute_ratio_parameter (const P &poly, RegionRatioFilter::parameter_type parameter)
|
||||
{
|
||||
double v = 0.0;
|
||||
if (m_parameter == AreaRatio) {
|
||||
|
||||
if (parameter == RegionRatioFilter::AreaRatio) {
|
||||
|
||||
v = poly.area_ratio ();
|
||||
} else if (m_parameter == AspectRatio) {
|
||||
|
||||
} else if (parameter == RegionRatioFilter::AspectRatio) {
|
||||
|
||||
db::Box box = poly.box ();
|
||||
double f = std::max (box.height (), box.width ());
|
||||
double d = std::min (box.height (), box.width ());
|
||||
if (d < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
v = f / d;
|
||||
} else if (m_parameter == RelativeHeight) {
|
||||
|
||||
} else if (parameter == RegionRatioFilter::RelativeHeight) {
|
||||
|
||||
db::Box box = poly.box ();
|
||||
double f = box.height ();
|
||||
double d = box.width ();
|
||||
if (d < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
v = f / d;
|
||||
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
bool RegionRatioFilter::selected (const db::Polygon &poly) const
|
||||
{
|
||||
double v = compute_ratio_parameter (poly, m_parameter);
|
||||
|
||||
bool ok = (v - (m_vmin_included ? -db::epsilon : db::epsilon) > m_vmin && v - (m_vmax_included ? db::epsilon : -db::epsilon) < m_vmax);
|
||||
return ok != m_inverse;
|
||||
}
|
||||
|
||||
bool RegionRatioFilter::selected (const db::PolygonRef &poly) const
|
||||
{
|
||||
double v = compute_ratio_parameter (poly, m_parameter);
|
||||
|
||||
bool ok = (v - (m_vmin_included ? -db::epsilon : db::epsilon) > m_vmin && v - (m_vmax_included ? db::epsilon : -db::epsilon) < m_vmax);
|
||||
return ok != m_inverse;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,21 @@ struct DB_PUBLIC RegionPerimeterFilter
|
|||
*/
|
||||
virtual bool selected (const db::Polygon &poly) const;
|
||||
|
||||
/**
|
||||
* @brief Returns true if the polygon's perimeter matches the criterion
|
||||
*/
|
||||
virtual bool selected (const db::PolygonRef &poly) const;
|
||||
|
||||
/**
|
||||
* @brief Returns true if the polygon's perimeter sum matches the criterion
|
||||
*/
|
||||
virtual bool selected_set (const std::unordered_set<db::PolygonRef> &polygons) const;
|
||||
|
||||
/**
|
||||
* @brief Returns true if the polygon's perimeter sum matches the criterion
|
||||
*/
|
||||
virtual bool selected_set (const std::unordered_set<db::Polygon> &polygons) const;
|
||||
|
||||
/**
|
||||
* @brief This filter is isotropic
|
||||
*/
|
||||
|
|
@ -78,6 +93,8 @@ private:
|
|||
perimeter_type m_pmin, m_pmax;
|
||||
bool m_inverse;
|
||||
db::MagnificationReducer m_vars;
|
||||
|
||||
bool check (perimeter_type p) const;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -108,6 +125,21 @@ struct DB_PUBLIC RegionAreaFilter
|
|||
*/
|
||||
virtual bool selected (const db::Polygon &poly) const;
|
||||
|
||||
/**
|
||||
* @brief Returns true if the polygon's area matches the criterion
|
||||
*/
|
||||
virtual bool selected (const db::PolygonRef &poly) const;
|
||||
|
||||
/**
|
||||
* @brief Returns true if the polygon's area sum matches the criterion
|
||||
*/
|
||||
virtual bool selected_set (const std::unordered_set<db::PolygonRef> &polygons) const;
|
||||
|
||||
/**
|
||||
* @brief Returns true if the polygon's area sum matches the criterion
|
||||
*/
|
||||
virtual bool selected_set (const std::unordered_set<db::Polygon> &polygons) const;
|
||||
|
||||
/**
|
||||
* @brief This filter is isotropic
|
||||
*/
|
||||
|
|
@ -127,6 +159,42 @@ private:
|
|||
area_type m_amin, m_amax;
|
||||
bool m_inverse;
|
||||
db::MagnificationReducer m_vars;
|
||||
|
||||
bool check (area_type a) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A filter implementation which implements the set filters through "all must match"
|
||||
*/
|
||||
|
||||
struct DB_PUBLIC AllMustMatchFilter
|
||||
: public PolygonFilterBase
|
||||
{
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
AllMustMatchFilter () { }
|
||||
|
||||
virtual bool selected_set (const std::unordered_set<db::PolygonRef> &polygons) const
|
||||
{
|
||||
for (std::unordered_set<db::PolygonRef>::const_iterator p = polygons.begin (); p != polygons.end (); ++p) {
|
||||
if (! selected (*p)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool selected_set (const std::unordered_set<db::Polygon> &polygons) const
|
||||
{
|
||||
for (std::unordered_set<db::Polygon>::const_iterator p = polygons.begin (); p != polygons.end (); ++p) {
|
||||
if (! selected (*p)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -136,7 +204,7 @@ private:
|
|||
*/
|
||||
|
||||
struct DB_PUBLIC RectilinearFilter
|
||||
: public PolygonFilterBase
|
||||
: public AllMustMatchFilter
|
||||
{
|
||||
/**
|
||||
* @brief Constructor
|
||||
|
|
@ -145,10 +213,15 @@ struct DB_PUBLIC RectilinearFilter
|
|||
RectilinearFilter (bool inverse);
|
||||
|
||||
/**
|
||||
* @brief Returns true if the polygon's area matches the criterion
|
||||
* @brief Returns true if the polygon is rectilinear
|
||||
*/
|
||||
virtual bool selected (const db::Polygon &poly) const;
|
||||
|
||||
/**
|
||||
* @brief Returns true if the polygon is rectilinear
|
||||
*/
|
||||
virtual bool selected (const db::PolygonRef &poly) const;
|
||||
|
||||
/**
|
||||
* @brief This filter does not need variants
|
||||
*/
|
||||
|
|
@ -175,7 +248,7 @@ private:
|
|||
*/
|
||||
|
||||
struct DB_PUBLIC RectangleFilter
|
||||
: public PolygonFilterBase
|
||||
: public AllMustMatchFilter
|
||||
{
|
||||
/**
|
||||
* @brief Constructor
|
||||
|
|
@ -184,10 +257,15 @@ struct DB_PUBLIC RectangleFilter
|
|||
RectangleFilter (bool is_square, bool inverse);
|
||||
|
||||
/**
|
||||
* @brief Returns true if the polygon's area matches the criterion
|
||||
* @brief Returns true if the polygon is a rectangle
|
||||
*/
|
||||
virtual bool selected (const db::Polygon &poly) const;
|
||||
|
||||
/**
|
||||
* @brief Returns true if the polygon is a rectangle
|
||||
*/
|
||||
virtual bool selected (const db::PolygonRef &poly) const;
|
||||
|
||||
/**
|
||||
* @brief This filter does not need variants
|
||||
*/
|
||||
|
|
@ -225,7 +303,7 @@ private:
|
|||
*/
|
||||
|
||||
struct DB_PUBLIC RegionBBoxFilter
|
||||
: public PolygonFilterBase
|
||||
: public AllMustMatchFilter
|
||||
{
|
||||
typedef db::Box::distance_type value_type;
|
||||
|
||||
|
|
@ -250,10 +328,15 @@ struct DB_PUBLIC RegionBBoxFilter
|
|||
RegionBBoxFilter (value_type vmin, value_type vmax, bool inverse, parameter_type parameter);
|
||||
|
||||
/**
|
||||
* @brief Returns true if the polygon's area matches the criterion
|
||||
* @brief Returns true if the polygon's bounding box matches the criterion
|
||||
*/
|
||||
virtual bool selected (const db::Polygon &poly) const;
|
||||
|
||||
/**
|
||||
* @brief Returns true if the polygon's bounding box matches the criterion
|
||||
*/
|
||||
virtual bool selected (const db::PolygonRef &poly) const;
|
||||
|
||||
/**
|
||||
* @brief This filter is isotropic unless the parameter is width or height
|
||||
*/
|
||||
|
|
@ -275,6 +358,8 @@ private:
|
|||
parameter_type m_parameter;
|
||||
db::MagnificationReducer m_isotropic_vars;
|
||||
db::MagnificationAndOrientationReducer m_anisotropic_vars;
|
||||
|
||||
bool check (const db::Box &box) const;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -291,7 +376,7 @@ private:
|
|||
*/
|
||||
|
||||
struct DB_PUBLIC RegionRatioFilter
|
||||
: public PolygonFilterBase
|
||||
: public AllMustMatchFilter
|
||||
{
|
||||
/**
|
||||
* @brief The parameters available
|
||||
|
|
@ -316,6 +401,11 @@ struct DB_PUBLIC RegionRatioFilter
|
|||
*/
|
||||
virtual bool selected (const db::Polygon &poly) const;
|
||||
|
||||
/**
|
||||
* @brief Returns true if the polygon's area matches the criterion
|
||||
*/
|
||||
virtual bool selected (const db::PolygonRef &poly) const;
|
||||
|
||||
/**
|
||||
* @brief This filter is isotropic unless the parameter is width or height
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -326,6 +326,12 @@ static db::CompoundRegionOperationNode *new_edge_length_filter (db::CompoundRegi
|
|||
return new db::CompoundRegionEdgeFilterOperationNode (new db::EdgeLengthFilter (lmin, lmax, inverse), input, true /*processor is owned*/);
|
||||
}
|
||||
|
||||
static db::CompoundRegionOperationNode *new_edge_length_sum_filter (db::CompoundRegionOperationNode *input, bool inverse, db::Edge::distance_type lmin, db::Edge::distance_type lmax)
|
||||
{
|
||||
check_non_null (input, "input");
|
||||
return new db::CompoundRegionEdgeFilterOperationNode (new db::EdgeLengthFilter (lmin, lmax, inverse), input, true /*processor is owned*/, true /*sum*/);
|
||||
}
|
||||
|
||||
static db::CompoundRegionOperationNode *new_edge_orientation_filter (db::CompoundRegionOperationNode *input, bool inverse, double amin, bool include_amin, double amax, bool include_amax)
|
||||
{
|
||||
check_non_null (input, "input");
|
||||
|
|
@ -472,12 +478,24 @@ static db::CompoundRegionOperationNode *new_perimeter_filter (db::CompoundRegion
|
|||
return new db::CompoundRegionFilterOperationNode (new db::RegionPerimeterFilter (pmin, pmax, inverse), input, true);
|
||||
}
|
||||
|
||||
static db::CompoundRegionOperationNode *new_perimeter_sum_filter (db::CompoundRegionOperationNode *input, bool inverse, db::coord_traits<db::Coord>::perimeter_type pmin, db::coord_traits<db::Coord>::perimeter_type pmax)
|
||||
{
|
||||
check_non_null (input, "input");
|
||||
return new db::CompoundRegionFilterOperationNode (new db::RegionPerimeterFilter (pmin, pmax, inverse), input, true, true /*sum of set*/);
|
||||
}
|
||||
|
||||
static db::CompoundRegionOperationNode *new_area_filter (db::CompoundRegionOperationNode *input, bool inverse, db::coord_traits<db::Coord>::area_type amin, db::coord_traits<db::Coord>::area_type amax)
|
||||
{
|
||||
check_non_null (input, "input");
|
||||
return new db::CompoundRegionFilterOperationNode (new db::RegionAreaFilter (amin, amax, inverse), input, true);
|
||||
}
|
||||
|
||||
static db::CompoundRegionOperationNode *new_area_sum_filter (db::CompoundRegionOperationNode *input, bool inverse, db::coord_traits<db::Coord>::area_type amin, db::coord_traits<db::Coord>::area_type amax)
|
||||
{
|
||||
check_non_null (input, "input");
|
||||
return new db::CompoundRegionFilterOperationNode (new db::RegionAreaFilter (amin, amax, inverse), input, true, true /*sum of set*/);
|
||||
}
|
||||
|
||||
static db::CompoundRegionOperationNode *new_rectilinear_filter (db::CompoundRegionOperationNode *input, bool inverse)
|
||||
{
|
||||
check_non_null (input, "input");
|
||||
|
|
@ -659,11 +677,19 @@ Class<db::CompoundRegionOperationNode> decl_CompoundRegionOperationNode ("db", "
|
|||
"This node renders the input if the perimeter is between pmin and pmax (exclusively). If 'inverse' is set to true, the "
|
||||
"input shape is returned if the perimeter is less than pmin (exclusively) or larger than pmax (inclusively)."
|
||||
) +
|
||||
gsi::constructor ("new_perimeter_sum_filter", &new_perimeter_sum_filter, gsi::arg ("input"), gsi::arg ("inverse", false), gsi::arg ("amin", 0), gsi::arg ("amax", std::numeric_limits<db::coord_traits<db::Coord>::area_type>::max (), "max"),
|
||||
"@brief Creates a node filtering the input by area sum.\n"
|
||||
"Like \\new_perimeter_filter, but applies to the sum of all shapes in the current set.\n"
|
||||
) +
|
||||
gsi::constructor ("new_area_filter", &new_area_filter, gsi::arg ("input"), gsi::arg ("inverse", false), gsi::arg ("amin", 0), gsi::arg ("amax", std::numeric_limits<db::coord_traits<db::Coord>::area_type>::max (), "max"),
|
||||
"@brief Creates a node filtering the input by area.\n"
|
||||
"This node renders the input if the area is between amin and amax (exclusively). If 'inverse' is set to true, the "
|
||||
"input shape is returned if the area is less than amin (exclusively) or larger than amax (inclusively)."
|
||||
) +
|
||||
gsi::constructor ("new_area_sum_filter", &new_area_sum_filter, gsi::arg ("input"), gsi::arg ("inverse", false), gsi::arg ("amin", 0), gsi::arg ("amax", std::numeric_limits<db::coord_traits<db::Coord>::area_type>::max (), "max"),
|
||||
"@brief Creates a node filtering the input by area sum.\n"
|
||||
"Like \\new_area_filter, but applies to the sum of all shapes in the current set.\n"
|
||||
) +
|
||||
gsi::constructor ("new_bbox_filter", &new_bbox_filter, gsi::arg ("input"), gsi::arg ("parameter"), gsi::arg ("inverse", false), gsi::arg ("pmin", 0), gsi::arg ("pmax", std::numeric_limits<db::coord_traits<db::Coord>::area_type>::max (), "max"),
|
||||
"@brief Creates a node filtering the input by bounding box parameters.\n"
|
||||
"This node renders the input if the specified bounding box parameter of the input shape is between pmin and pmax (exclusively). If 'inverse' is set to true, the "
|
||||
|
|
@ -687,6 +713,9 @@ Class<db::CompoundRegionOperationNode> decl_CompoundRegionOperationNode ("db", "
|
|||
gsi::constructor ("new_edge_length_filter", &new_edge_length_filter, gsi::arg ("input"), gsi::arg ("inverse", false), gsi::arg ("lmin", 0), gsi::arg ("lmax", std::numeric_limits<db::Edge::distance_type>::max (), "max"),
|
||||
"@brief Creates a node filtering edges by their length.\n"
|
||||
) +
|
||||
gsi::constructor ("new_edge_length_sum_filter", &new_edge_length_sum_filter, gsi::arg ("input"), gsi::arg ("inverse", false), gsi::arg ("lmin", 0), gsi::arg ("lmax", std::numeric_limits<db::Edge::distance_type>::max (), "max"),
|
||||
"@brief Creates a node filtering edges by their length sum (over the local set).\n"
|
||||
) +
|
||||
gsi::constructor ("new_edge_orientation_filter", &new_edge_orientation_filter, gsi::arg ("input"), gsi::arg ("inverse", false), gsi::arg ("amin"), gsi::arg ("include_amin"), gsi::arg ("amax"), gsi::arg ("include_amax"),
|
||||
"@brief Creates a node filtering edges by their orientation.\n"
|
||||
) +
|
||||
|
|
|
|||
|
|
@ -27,55 +27,206 @@ module DRC
|
|||
# The following global functions are relevant for the DRC expressions:
|
||||
#
|
||||
# @ul
|
||||
# @li \global#angle @/li
|
||||
# @li \global#area @/li
|
||||
# @li \global#area_ratio @/li
|
||||
# @li \global#bbox_area_ratio @/li
|
||||
# @li \global#bbox_height @/li
|
||||
# @li \global#bbox_max @/li
|
||||
# @li \global#bbox_min @/li
|
||||
# @li \global#bbox_width @/li
|
||||
# @li \global#case @/li
|
||||
# @li \global#corners @/li
|
||||
# @li \global#covering @/li
|
||||
# @li \global#enc @/li
|
||||
# @li \global#enclosing @/li
|
||||
# @li \global#extent_refs @/li
|
||||
# @li \global#extents @/li
|
||||
# @li \global#foreign @/li
|
||||
# @li \global#holes @/li
|
||||
# @li \global#hulls @/li
|
||||
# @li \global#if_all @/li
|
||||
# @li \global#if_any @/li
|
||||
# @li \global#if_none @/li
|
||||
# @li \global#inside @/li
|
||||
# @li \global#interacting @/li
|
||||
# @li \global#iso @/li
|
||||
# @li \global#length @/li
|
||||
# @li \global#middle @/li
|
||||
# @li \global#notch @/li
|
||||
# @li \global#odd_polygons @/li
|
||||
# @li \global#outside @/li
|
||||
# @li \global#overlap @/li
|
||||
# @li \global#overlapping @/li
|
||||
# @li \global#perimeter @/li
|
||||
# @li \global#primary @/li
|
||||
# @li \global#rectangles @/li
|
||||
# @li \global#rectilinear @/li
|
||||
# @li \global#relative_height @/li
|
||||
# @li \global#rounded_corners @/li
|
||||
# @li \global#secondary @/li
|
||||
# @li \global#separation @/li
|
||||
# @li \global#sep @/li
|
||||
# @li \global#sized @/li
|
||||
# @li \global#smoothed @/li
|
||||
# @li \global#space @/li
|
||||
# @li \global#squares @/li
|
||||
# @li \global#width @/li
|
||||
# @li \\global#angle @/li
|
||||
# @li \\global#area @/li
|
||||
# @li \\global#area_ratio @/li
|
||||
# @li \\global#bbox_area_ratio @/li
|
||||
# @li \\global#bbox_height @/li
|
||||
# @li \\global#bbox_max @/li
|
||||
# @li \\global#bbox_min @/li
|
||||
# @li \\global#bbox_width @/li
|
||||
# @li \\global#case @/li
|
||||
# @li \\global#corners @/li
|
||||
# @li \\global#covering @/li
|
||||
# @li \\global#enc @/li
|
||||
# @li \\global#enclosing @/li
|
||||
# @li \\global#extent_refs @/li
|
||||
# @li \\global#extents @/li
|
||||
# @li \\global#foreign @/li
|
||||
# @li \\global#holes @/li
|
||||
# @li \\global#hulls @/li
|
||||
# @li \\global#if_all @/li
|
||||
# @li \\global#if_any @/li
|
||||
# @li \\global#if_none @/li
|
||||
# @li \\global#inside @/li
|
||||
# @li \\global#interacting @/li
|
||||
# @li \\global#iso @/li
|
||||
# @li \\global#length @/li
|
||||
# @li \\global#middle @/li
|
||||
# @li \\global#notch @/li
|
||||
# @li \\global#odd_polygons @/li
|
||||
# @li \\global#outside @/li
|
||||
# @li \\global#overlap @/li
|
||||
# @li \\global#overlapping @/li
|
||||
# @li \\global#perimeter @/li
|
||||
# @li \\global#primary @/li
|
||||
# @li \\global#rectangles @/li
|
||||
# @li \\global#rectilinear @/li
|
||||
# @li \\global#relative_height @/li
|
||||
# @li \\global#rounded_corners @/li
|
||||
# @li \\global#secondary @/li
|
||||
# @li \\global#separation @/li
|
||||
# @li \\global#sep @/li
|
||||
# @li \\global#sized @/li
|
||||
# @li \\global#smoothed @/li
|
||||
# @li \\global#space @/li
|
||||
# @li \\global#squares @/li
|
||||
# @li \\global#width @/li
|
||||
# @/ul
|
||||
#
|
||||
# The following documentation will list the methods available for DRC expression objects.
|
||||
|
||||
# A base class for implementing ranges that can be put into a condition
|
||||
module DRCComparable
|
||||
|
||||
attr_accessor :reverse
|
||||
attr_accessor :original
|
||||
attr_accessor :lt, :le, :gt, :ge
|
||||
attr_accessor :description
|
||||
attr_accessor :mode_or_supported
|
||||
attr_accessor :mode_or
|
||||
|
||||
def _init_comparable
|
||||
self.reverse = false
|
||||
self.original = nil
|
||||
self.le = nil
|
||||
self.ge = nil
|
||||
self.lt = nil
|
||||
self.gt = nil
|
||||
self.gt = nil
|
||||
self.description = ""
|
||||
self.mode_or_supported = false
|
||||
self.mode_or = false
|
||||
end
|
||||
|
||||
def _check_bounds
|
||||
if ! self.mode_or && (self.lt || self.le) && (self.gt || self.ge)
|
||||
epsilon = 1e-10
|
||||
lower = self.ge ? self.ge - epsilon : self.gt + epsilon
|
||||
upper = self.le ? self.le + epsilon : self.lt - epsilon
|
||||
if lower > upper - epsilon
|
||||
raise("'" + self.description + "': lower bound is larger than upper bound")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def set_lt(value)
|
||||
(self.lt || self.le) && raise("'" + self.description + "' already has an upper bound of " + ("%.12g" % (self.lt || self.le)))
|
||||
self.lt = value
|
||||
self._check_bounds
|
||||
end
|
||||
|
||||
def set_le(value)
|
||||
(self.lt || self.le) && raise("'" + self.description + "' already has an upper bound of " + ("%.12g" % (self.lt || self.le)))
|
||||
self.le = value
|
||||
self._check_bounds
|
||||
end
|
||||
|
||||
def set_gt(value)
|
||||
(self.gt || self.ge) && raise("'" + self.description + "' already has an lower bound of " + ("%.12g" % (self.gt || self.ge)))
|
||||
self.gt = value
|
||||
self._check_bounds
|
||||
end
|
||||
|
||||
def set_ge(value)
|
||||
(self.gt || self.ge) && raise("'" + self.description + "' already has an lower bound of " + ("%.12g" % (self.gt || self.ge)))
|
||||
self.ge = value
|
||||
self._check_bounds
|
||||
end
|
||||
|
||||
def coerce(something)
|
||||
reversed = self.dup
|
||||
reversed.reverse = true
|
||||
reversed.original = self
|
||||
[ reversed, something ]
|
||||
end
|
||||
|
||||
def _self_or_original
|
||||
return (self.original || self).dup
|
||||
end
|
||||
|
||||
def !=(other)
|
||||
if self.respond_to?(:inverted)
|
||||
res = self.==(other).inverted
|
||||
else
|
||||
if !self.mode_or_supported
|
||||
raise("!= operator is not allowed for '" + self.description + "'")
|
||||
end
|
||||
if !(other.is_a?(Float) || other.is_a?(Integer))
|
||||
raise("!= operator needs a numerical argument for '" + self.description + "' argument")
|
||||
end
|
||||
res = self._self_or_original
|
||||
res.mode_or = true
|
||||
res.set_lt(other)
|
||||
res.set_gt(other)
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
if !(other.is_a?(Float) || other.is_a?(Integer))
|
||||
raise("== operator needs a numerical argument for '" + self.description + "' argument")
|
||||
end
|
||||
res = self._self_or_original
|
||||
res.set_le(other)
|
||||
res.set_ge(other)
|
||||
return res
|
||||
end
|
||||
|
||||
def <(other)
|
||||
if !(other.is_a?(Float) || other.is_a?(Integer))
|
||||
raise("< operator needs a numerical argument for '" + self.description + "' argument")
|
||||
end
|
||||
res = self._self_or_original
|
||||
if reverse
|
||||
res.set_gt(other)
|
||||
else
|
||||
res.set_lt(other)
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
def <=(other)
|
||||
if !(other.is_a?(Float) || other.is_a?(Integer))
|
||||
raise("<= operator needs a numerical argument for '" + self.description + "' argument")
|
||||
end
|
||||
res = self._self_or_original
|
||||
if reverse
|
||||
res.set_ge(other)
|
||||
else
|
||||
res.set_le(other)
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
def >(other)
|
||||
if !(other.is_a?(Float) || other.is_a?(Integer))
|
||||
raise("> operator needs a numerical argument for '" + self.description + "' argument")
|
||||
end
|
||||
res = self._self_or_original
|
||||
if reverse
|
||||
res.set_lt(other)
|
||||
else
|
||||
res.set_gt(other)
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
def >=(other)
|
||||
if !(other.is_a?(Float) || other.is_a?(Integer))
|
||||
raise(">= operator needs a numerical argument for '" + self.description + "' argument")
|
||||
end
|
||||
res = self._self_or_original
|
||||
if reverse
|
||||
res.set_le(other)
|
||||
else
|
||||
res.set_ge(other)
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class DRCOpNode
|
||||
|
||||
attr_accessor :description
|
||||
|
|
@ -239,7 +390,23 @@ CODE
|
|||
# The plain function is equivalent to "primary.area".
|
||||
|
||||
def area
|
||||
DRCOpNodeAreaFilter::new(@engine, self)
|
||||
DRCOpNodeAreaFilter::new(@engine, self, false)
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name area_sum
|
||||
# @brief Selects the input polygons if the sum of all areas meets the condition
|
||||
# @synopsis expression.area_sum (in condition)
|
||||
#
|
||||
# Returns the input polygons if the sum of their areas meets the specified
|
||||
# condition. This condition is evaluated on the total of all shapes generated in one step of the
|
||||
# "drc" loop. As there is a single primary in each loop iteration, "primary.area_sum" is
|
||||
# equivalent to "primary.area".
|
||||
#
|
||||
# See \Layer#drc for more details about comparison specs.
|
||||
|
||||
def area_sum
|
||||
DRCOpNodeAreaFilter::new(@engine, self, true)
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
|
|
@ -293,7 +460,23 @@ CODE
|
|||
# The plain function is equivalent to "primary.perimeter".
|
||||
|
||||
def perimeter
|
||||
DRCOpNodePerimeterFilter::new(@engine, self)
|
||||
DRCOpNodePerimeterFilter::new(@engine, self, false)
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name perimeter_sum
|
||||
# @brief Selects the input polygons if the sum of all perimeters meets the condition
|
||||
# @synopsis expression.perimeter_sum (in condition)
|
||||
#
|
||||
# Returns the input polygons if the sum of their perimeters meets the specified
|
||||
# condition. This condition is evaluated on the total of all shapes generated in one step of the
|
||||
# "drc" loop. As there is a single primary in each loop iteration, "primary.perimeter_sum" is
|
||||
# equivalent to "primary.perimeter".
|
||||
#
|
||||
# See \Layer#drc for more details about comparison specs.
|
||||
|
||||
def perimeter_sum
|
||||
DRCOpNodePerimeterFilter::new(@engine, self, true)
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
|
|
@ -482,7 +665,22 @@ CODE
|
|||
# The plain function is equivalent to "primary.length".
|
||||
|
||||
def length
|
||||
DRCOpNodeEdgeLengthFilter::new(@engine, self)
|
||||
DRCOpNodeEdgeLengthFilter::new(@engine, self, false)
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name length_sum
|
||||
# @brief Selects the input edges if the sum of their lengths meets the condition
|
||||
# @synopsis expression.length_sum (in condition)
|
||||
#
|
||||
# Returns the input edges if the sum of their lengths meets the specified
|
||||
# condition. This condition is evaluated on the total of all edges generated in one step of the
|
||||
# "drc" loop.
|
||||
#
|
||||
# See \Layer#drc for more details about comparison specs.
|
||||
|
||||
def length_sum
|
||||
DRCOpNodeEdgeLengthFilter::new(@engine, self, true)
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
|
|
@ -1236,18 +1434,14 @@ class DRCOpNodeCase < DRCOpNode
|
|||
end
|
||||
|
||||
class DRCOpNodeWithCompare < DRCOpNode
|
||||
|
||||
include DRCComparable
|
||||
|
||||
attr_accessor :reverse
|
||||
attr_accessor :original
|
||||
attr_accessor :lt, :le, :gt, :ge, :arg
|
||||
attr_accessor :mode_or_supported
|
||||
attr_accessor :mode_or
|
||||
|
||||
def initialize(engine, original = nil, reverse = false)
|
||||
def initialize(engine)
|
||||
super(engine)
|
||||
self.reverse = reverse
|
||||
self.original = original
|
||||
self.description = original ? original.description : "BasicWithCompare"
|
||||
self.description = "BasicWithCompare"
|
||||
self.mode_or = false
|
||||
self.mode_or_supported = false
|
||||
end
|
||||
|
|
@ -1269,129 +1463,6 @@ class DRCOpNodeWithCompare < DRCOpNode
|
|||
end
|
||||
end
|
||||
|
||||
def _check_bounds
|
||||
if ! self.mode_or && (self.lt || self.le) && (self.gt || self.ge)
|
||||
epsilon = 1e-10
|
||||
lower = self.ge ? self.ge - epsilon : self.gt + epsilon
|
||||
upper = self.le ? self.le + epsilon : self.lt - epsilon
|
||||
if lower > upper - epsilon
|
||||
raise("Lower bound is larger than upper bound")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def set_lt(value)
|
||||
(self.lt || self.le) && raise("'" + self.description + "' already has an upper bound of " + ("%.12g" % (self.lt || self.le)))
|
||||
self.lt = value
|
||||
self._check_bounds
|
||||
end
|
||||
|
||||
def set_le(value)
|
||||
(self.lt || self.le) && raise("'" + self.description + "' already has an upper bound of " + ("%.12g" % (self.lt || self.le)))
|
||||
self.le = value
|
||||
self._check_bounds
|
||||
end
|
||||
|
||||
def set_gt(value)
|
||||
(self.gt || self.ge) && raise("'" + self.description + "' already has an lower bound of " + ("%.12g" % (self.gt || self.ge)))
|
||||
self.gt = value
|
||||
self._check_bounds
|
||||
end
|
||||
|
||||
def set_ge(value)
|
||||
(self.gt || self.ge) && raise("'" + self.description + "' already has an lower bound of " + ("%.12g" % (self.gt || self.ge)))
|
||||
self.ge = value
|
||||
self._check_bounds
|
||||
end
|
||||
|
||||
def coerce(something)
|
||||
[ DRCOpNodeWithCompare::new(@engine, self, true), something ]
|
||||
end
|
||||
|
||||
def _self_or_original
|
||||
return (self.original || self).dup
|
||||
end
|
||||
|
||||
def !=(other)
|
||||
if self.respond_to?(:inverted)
|
||||
res = self.==(other).inverted
|
||||
else
|
||||
if !self.mode_or_supported
|
||||
raise("!= operator is not allowed for '" + self.description + "'")
|
||||
end
|
||||
if !(other.is_a?(Float) || other.is_a?(Integer))
|
||||
raise("!= operator needs a numerical argument for '" + self.description + "' argument")
|
||||
end
|
||||
res = self._self_or_original
|
||||
res.mode_or = true
|
||||
res.set_lt(other)
|
||||
res.set_gt(other)
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
if !(other.is_a?(Float) || other.is_a?(Integer))
|
||||
raise("== operator needs a numerical argument for '" + self.description + "' argument")
|
||||
end
|
||||
res = self._self_or_original
|
||||
res.set_le(other)
|
||||
res.set_ge(other)
|
||||
return res
|
||||
end
|
||||
|
||||
def <(other)
|
||||
if !(other.is_a?(Float) || other.is_a?(Integer))
|
||||
raise("< operator needs a numerical argument for '" + self.description + "' argument")
|
||||
end
|
||||
res = self._self_or_original
|
||||
if reverse
|
||||
res.set_gt(other)
|
||||
else
|
||||
res.set_lt(other)
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
def <=(other)
|
||||
if !(other.is_a?(Float) || other.is_a?(Integer))
|
||||
raise("<= operator needs a numerical argument for '" + self.description + "' argument")
|
||||
end
|
||||
res = self._self_or_original
|
||||
if reverse
|
||||
res.set_ge(other)
|
||||
else
|
||||
res.set_le(other)
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
def >(other)
|
||||
if !(other.is_a?(Float) || other.is_a?(Integer))
|
||||
raise("> operator needs a numerical argument for '" + self.description + "' argument")
|
||||
end
|
||||
res = self._self_or_original
|
||||
if reverse
|
||||
res.set_lt(other)
|
||||
else
|
||||
res.set_gt(other)
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
def >=(other)
|
||||
if !(other.is_a?(Float) || other.is_a?(Integer))
|
||||
raise(">= operator needs a numerical argument for '" + self.description + "' argument")
|
||||
end
|
||||
res = self._self_or_original
|
||||
if reverse
|
||||
res.set_le(other)
|
||||
else
|
||||
res.set_ge(other)
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class DRCOpNodeCountFilter < DRCOpNodeWithCompare
|
||||
|
|
@ -1431,16 +1502,18 @@ class DRCOpNodeAreaFilter < DRCOpNodeWithCompare
|
|||
|
||||
attr_accessor :input
|
||||
attr_accessor :inverse
|
||||
attr_accessor :sum
|
||||
|
||||
def initialize(engine, input)
|
||||
def initialize(engine, input, sum)
|
||||
super(engine)
|
||||
self.input = input
|
||||
self.inverse = false
|
||||
self.description = "area"
|
||||
self.sum = sum
|
||||
end
|
||||
|
||||
def _description_for_dump
|
||||
self.inverse ? "area" : "not_area"
|
||||
(self.inverse ? "area" : "not_area") + (self.sum ? "_sum" : "")
|
||||
end
|
||||
|
||||
def do_create_node(cache)
|
||||
|
|
@ -1449,7 +1522,7 @@ class DRCOpNodeAreaFilter < DRCOpNodeWithCompare
|
|||
if self.lt || self.le
|
||||
args << (self.lt ? @engine._make_area_value(self.lt) : @engine._make_area_value(self.le) + 1)
|
||||
end
|
||||
RBA::CompoundRegionOperationNode::new_area_filter(*args)
|
||||
RBA::CompoundRegionOperationNode::send(self.sum ? :new_area_sum_filter : :new_area_filter, *args)
|
||||
end
|
||||
|
||||
def inverted
|
||||
|
|
@ -1464,16 +1537,18 @@ class DRCOpNodeEdgeLengthFilter < DRCOpNodeWithCompare
|
|||
|
||||
attr_accessor :input
|
||||
attr_accessor :inverse
|
||||
attr_accessor :sum
|
||||
|
||||
def initialize(engine, input)
|
||||
def initialize(engine, input, sum)
|
||||
super(engine)
|
||||
self.input = input
|
||||
self.inverse = false
|
||||
self.description = "length"
|
||||
self.sum = sum
|
||||
end
|
||||
|
||||
def _description_for_dump
|
||||
self.inverse ? "length" : "not_length"
|
||||
(self.inverse ? "length" : "not_length") + (self.sum ? "_sum" : "")
|
||||
end
|
||||
|
||||
def do_create_node(cache)
|
||||
|
|
@ -1491,7 +1566,7 @@ class DRCOpNodeEdgeLengthFilter < DRCOpNodeWithCompare
|
|||
args << (self.lt ? @engine._make_value(self.lt) : @engine._make_value(self.le) + 1)
|
||||
end
|
||||
|
||||
RBA::CompoundRegionOperationNode::new_edge_length_filter(*args)
|
||||
RBA::CompoundRegionOperationNode::send(self.sum ? :new_edge_length_sum_filter : :new_edge_length_filter, *args)
|
||||
|
||||
end
|
||||
|
||||
|
|
@ -1551,16 +1626,18 @@ class DRCOpNodePerimeterFilter < DRCOpNodeWithCompare
|
|||
|
||||
attr_accessor :input
|
||||
attr_accessor :inverse
|
||||
attr_accessor :sum
|
||||
|
||||
def initialize(engine, input)
|
||||
def initialize(engine, input, sum)
|
||||
super(engine)
|
||||
self.input = input
|
||||
self.inverse = false
|
||||
self.description = "perimeter"
|
||||
self.sum = sum
|
||||
end
|
||||
|
||||
def _description_for_dump
|
||||
self.inverse ? "perimeter" : "not_perimeter"
|
||||
(self.inverse ? "perimeter" : "not_perimeter") + (self.sum ? "_sum" : "")
|
||||
end
|
||||
|
||||
def do_create_node(cache)
|
||||
|
|
@ -1569,7 +1646,7 @@ class DRCOpNodePerimeterFilter < DRCOpNodeWithCompare
|
|||
if self.lt || self.le
|
||||
args << (self.lt ? @engine._make_value(self.lt) : @engine._make_value(self.le) + 1)
|
||||
end
|
||||
RBA::CompoundRegionOperationNode::new_perimeter_filter(*args)
|
||||
RBA::CompoundRegionOperationNode::send(self.sum ? :new_perimeter_sum_filter : :new_perimeter_filter, *args)
|
||||
end
|
||||
|
||||
def inverted
|
||||
|
|
|
|||
|
|
@ -51,6 +51,8 @@ module DRC
|
|||
# merged, so the secondary polygons may be partial. This is important when
|
||||
# using measurement operations like "area" on secondary polygons.
|
||||
#
|
||||
# @h3 Checks @/h3
|
||||
#
|
||||
# Here is an example for a generic DRC operation which performs a width
|
||||
# check for less than 0.5.um on the primary shapes. It uses the \global#width operator:
|
||||
#
|
||||
|
|
@ -88,13 +90,90 @@ module DRC
|
|||
# out = in.drc(width(projection) < 0.5.um)
|
||||
# @/code
|
||||
#
|
||||
# The "drc" function supports filter operators. These select input or derived polygons
|
||||
# based on their properties. These filters are:
|
||||
#
|
||||
# @h3 Edges and edge pairs @/h3
|
||||
#
|
||||
# Although the "drc" function operates on polygon layers, internally it is
|
||||
# able to handle edge and edge pair types too. Some operations generate edge pairs,
|
||||
# some other generate edges. As results from one operation can be processed further
|
||||
# in the DRC expressions, methods are available to filter, process and convert
|
||||
# these types.
|
||||
#
|
||||
# For example, the check produces edge pairs which can be converted into polygons
|
||||
# using the "polygons" method:
|
||||
#
|
||||
# @code
|
||||
# out = in.drc((width(projection) < 0.5.um).polygons)
|
||||
# @/code
|
||||
#
|
||||
# Note the subtle difference: when putting the "polygons" method inside the "drc"
|
||||
# brackets, it is executed locally on every checked primary polygon. The result
|
||||
# may be identical to the global conversion:
|
||||
#
|
||||
# @code
|
||||
# # same, but with "global" conversion:
|
||||
# out = in.drc(width(projection) < 0.5.um).polygons
|
||||
# @/code
|
||||
#
|
||||
# but having the check polygons inside the loop opens new opportunities and
|
||||
# is more efficient in general.
|
||||
#
|
||||
# Conversion methods are:
|
||||
#
|
||||
# @ul
|
||||
# @li "\global#area": select polygons based on their area @/li
|
||||
# @li "\global#perimeter": select polygons based on their perimeter @/li
|
||||
# @li "\global#bbox_min", "\global#bbox_max", "\global#bbox_width", "\global#bbox_height": select polygons based on their bounding box properties @/li
|
||||
# @li \DRC#polygons: converts edge pairs to polygons @/li
|
||||
# @li \DRC#extended, \DRC#extended_in, \DRC#extended_out: converts edges to polygons @/li
|
||||
# @li \DRC#first_edges, \DRC#second_edges: extracts edges from edge pairs @/li
|
||||
# @li \DRC#edges: decomposes edge pairs and polygons into edges @/li
|
||||
# @li \DRC#corners: can extract corners from polygons @/li
|
||||
# @/ul
|
||||
#
|
||||
# This example decomposes the primary polygons into edges:
|
||||
#
|
||||
# @code
|
||||
# out = in.drc(primary.edges)
|
||||
# @/code
|
||||
#
|
||||
# (for backward compatibility you cannot abbreviate "primary.edges" simply as "edges" like
|
||||
# other functions).
|
||||
#
|
||||
# The previous isn't quite exciting as it is equivalent to
|
||||
#
|
||||
# @code
|
||||
# # Same as above
|
||||
# out = in.edges
|
||||
# @/code
|
||||
#
|
||||
# But it gets more interesting as within the loop, "edges" delivers the edge set for
|
||||
# each individual polygon. So this will give you the edges of polygons with more than four corners:
|
||||
#
|
||||
# @code
|
||||
# out = in.drc(primary.edges.count > 4)
|
||||
# @/code
|
||||
#
|
||||
# The same result can be achieved with classic DRC with "interact" and a figure count, but
|
||||
# at a much higher computation cost.
|
||||
#
|
||||
# @h3 Edge and edge/polygon operations @/h3
|
||||
#
|
||||
# The "drc" framework supports the following edge and edge/polygon operations:
|
||||
#
|
||||
# @ul
|
||||
# @li Edge vs. edge and edge vs. polygon booleans @/li
|
||||
# @li Edge vs. polygon interactions (\DRC#interacting, \DRC#overlapping) @/li
|
||||
# @li Edge sampling (\DRC#start_segments, \DRC#centers, \DRC#end_segments) @/li
|
||||
# @/ul
|
||||
#
|
||||
# @h3 Filters @/h3
|
||||
#
|
||||
# Filter operators select input polygons or edges based on their properties. These filters are:
|
||||
#
|
||||
# @ul
|
||||
# @li "\DRC#area": selects polygons based on their area @/li
|
||||
# @li "\DRC#perimeter": selects polygons based on their perimeter @/li
|
||||
# @li "\DRC#bbox_min", "\global#bbox_max", "\global#bbox_width", "\global#bbox_height": selects polygons based on their bounding box properties @/li
|
||||
# @li "\DRC#length": selects edges based on their length @/li
|
||||
# @li "\DRC#angle": selects edges based on their orientation @/li
|
||||
# @/ul
|
||||
#
|
||||
# For example, to select polygons with an area larger than one square micrometer, use:
|
||||
|
|
@ -125,6 +204,8 @@ module DRC
|
|||
# It's recommended therefore to use the measurement functions on primary polygons
|
||||
# only.
|
||||
#
|
||||
# @h3 Filter predicates @/h3
|
||||
#
|
||||
# The "drc" feature also supports some predicates. "predicates" are boolean values
|
||||
# indicating a certain condition. A predicate filter works in a way that it only
|
||||
# passes the polygons
|
||||
|
|
@ -132,6 +213,7 @@ module DRC
|
|||
#
|
||||
# @ul
|
||||
# @li "\global#rectangles": Filters rectangles @/li
|
||||
# @li "\global#squares": Filters squares @/li
|
||||
# @li "\global#rectilinear": Filters rectilinear ("Manhattan") polygons @/li
|
||||
# @/ul
|
||||
#
|
||||
|
|
@ -139,6 +221,8 @@ module DRC
|
|||
# standalone, so they act on primary shapes. It's possible to use the predicates
|
||||
# on computed shapes or secondary input, but that may not render the desired results.
|
||||
#
|
||||
# @h3 Logical NOT operator @/h3
|
||||
#
|
||||
# The "!" operator will evaluate the expression behind it and return the
|
||||
# current primary shape if the input is empty and return an empty polygon set
|
||||
# if not. Hence the following filter will deliver all polygons which are
|
||||
|
|
@ -148,6 +232,8 @@ module DRC
|
|||
# out = in.drc(! rectangles)
|
||||
# @/code
|
||||
#
|
||||
# @h3 Logical combination operators @/h3
|
||||
#
|
||||
# The logical "if_any" or "if_all" statements allow connecting multiple
|
||||
# conditions and evaluate to "true" (means: a non-empty shape set) if either
|
||||
# on input is a non-empty shape set ("if_any") or if all inputs are non-empty
|
||||
|
|
@ -175,6 +261,7 @@ module DRC
|
|||
# out = in.drc(if_any(rectangles.sized(100.nm), primary))
|
||||
# @/code
|
||||
#
|
||||
# @h3 Polygon manipulations @/h3
|
||||
#
|
||||
# The "drc" operations feature polygon manipulations where the input is
|
||||
# either the primary polygon or derived shapes.
|
||||
|
|
@ -209,6 +296,32 @@ module DRC
|
|||
# out = l1.drc((secondary(l2) & primary).area > 1.0)
|
||||
# @/code
|
||||
#
|
||||
# @h3 Quantifiers @/h3
|
||||
#
|
||||
# Some filters operate on properties of the full, local shape set.
|
||||
# While the loop is executed, the DRC expressions will collect shapes, either
|
||||
# from the primary, it's neighborhood (secondary) or by deriving shape sets.
|
||||
#
|
||||
# Obviously the primary is a simple one: it consists of a single shape, because
|
||||
# this is how the loop operates. Derived shape sets however can be more complex.
|
||||
# "Quantifiers" allow to assess properties of the complete, per-primary shape
|
||||
# set. A simple one is "count" which checks if the number of shapes within
|
||||
# a shape set is within a given range.
|
||||
#
|
||||
# Obviously, "primary.count == 1" is always true. The following condition will
|
||||
# select all primary shapes which have more than 13 corners:
|
||||
#
|
||||
# @code
|
||||
# out = in.drc(if_any(primary.corners.count > 13))
|
||||
# @/code
|
||||
#
|
||||
# Note an important detail here: the "if_any" function will render primary
|
||||
# @b polygons @/b, if the expression inside gives a non-empty result. Without
|
||||
# "if_any", the result would be the output of "count" which is the set of all
|
||||
# corners where the corner count is larger than 13.
|
||||
#
|
||||
# @h3 Expressions as objects @/h3
|
||||
#
|
||||
# The expression inside the "drc" function is a Ruby object and can be
|
||||
# stored in variables. If you need the same expression multiple times, it can be
|
||||
# more efficient to use the same Ruby object. In this example, the same expression
|
||||
|
|
@ -229,28 +342,7 @@ module DRC
|
|||
# or the boolean operation. But when the "drc" function executes the operation it will
|
||||
# only compute the area once as it is represented by the same Ruby object.
|
||||
#
|
||||
#
|
||||
# The "drc" functionality also offers support for edge pairs and edges. Edge pairs
|
||||
# are the results of check operations and can be turned into polygons using the
|
||||
# "polygons" method:
|
||||
#
|
||||
# @code
|
||||
# drc = in.drc((width < 0.5.um).polygons)
|
||||
# @/code
|
||||
#
|
||||
# Similarly, polygons can be converted into edges:
|
||||
#
|
||||
# @code
|
||||
# drc = in.drc(primary.edges)
|
||||
# @/code
|
||||
#
|
||||
# The "drc" framework supports edge vs. edge and edge vs. polygon booleans, edge
|
||||
# filters (\global#length, \global#angle), edge vs. polygon interactions (\global#interacting, \global#overlapping),
|
||||
# edge sampling (\global#start_segments, \global#centers, \global#end_segments) and edge to polygon
|
||||
# conversions (\global#extended, \global#extended_in, \global#extended_out). Edge pairs
|
||||
# can be converted into polygons and edges and separated into first and second edges (\global#first_edges,
|
||||
# \global#second_edges).
|
||||
#
|
||||
# @h3 Summary @/h3
|
||||
#
|
||||
# The bottom line is: DRC expressions are quite rich and there is a lot more to be said and written.
|
||||
# More formal details about the bits and pieces can be found in the \DRC# class documentation.
|
||||
|
|
@ -1014,8 +1106,7 @@ CODE
|
|||
elsif a.is_a?(DRCLayer)
|
||||
other = self._make_node(a)
|
||||
elsif a.is_a?(DRCProjectionLimits)
|
||||
minp = self._make_value(a.min)
|
||||
maxp = self._make_value(a.max)
|
||||
(minp, maxp) = a.get_limits(self)
|
||||
elsif a.is_a?(DRCShielded)
|
||||
shielded = a.value
|
||||
else
|
||||
|
|
|
|||
|
|
@ -2,157 +2,6 @@
|
|||
|
||||
module DRC
|
||||
|
||||
# A base class for implementing ranges that can be put into a condition
|
||||
module DRCComparable
|
||||
|
||||
attr_accessor :reverse
|
||||
attr_accessor :original
|
||||
attr_accessor :lt, :le, :gt, :ge
|
||||
attr_accessor :description
|
||||
attr_accessor :mode_or_supported
|
||||
attr_accessor :mode_or
|
||||
|
||||
def _init_comparable
|
||||
self.reverse = false
|
||||
self.original = nil
|
||||
self.le = nil
|
||||
self.ge = nil
|
||||
self.lt = nil
|
||||
self.gt = nil
|
||||
self.gt = nil
|
||||
self.description = ""
|
||||
self.mode_or_supported = false
|
||||
self.mode_or = false
|
||||
end
|
||||
|
||||
def _check_bounds
|
||||
if ! self.mode_or && (self.lt || self.le) && (self.gt || self.ge)
|
||||
epsilon = 1e-10
|
||||
lower = self.ge ? self.ge - epsilon : self.gt + epsilon
|
||||
upper = self.le ? self.le + epsilon : self.lt - epsilon
|
||||
if lower > upper - epsilon
|
||||
raise("'" + self.description + "': lower bound is larger than upper bound")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def set_lt(value)
|
||||
(self.lt || self.le) && raise("'" + self.description + "' already has an upper bound of " + ("%.12g" % (self.lt || self.le)))
|
||||
self.lt = value
|
||||
self._check_bounds
|
||||
end
|
||||
|
||||
def set_le(value)
|
||||
(self.lt || self.le) && raise("'" + self.description + "' already has an upper bound of " + ("%.12g" % (self.lt || self.le)))
|
||||
self.le = value
|
||||
self._check_bounds
|
||||
end
|
||||
|
||||
def set_gt(value)
|
||||
(self.gt || self.ge) && raise("'" + self.description + "' already has an lower bound of " + ("%.12g" % (self.gt || self.ge)))
|
||||
self.gt = value
|
||||
self._check_bounds
|
||||
end
|
||||
|
||||
def set_ge(value)
|
||||
(self.gt || self.ge) && raise("'" + self.description + "' already has an lower bound of " + ("%.12g" % (self.gt || self.ge)))
|
||||
self.ge = value
|
||||
self._check_bounds
|
||||
end
|
||||
|
||||
def coerce(something)
|
||||
reversed = self.dup
|
||||
reversed.reverse = true
|
||||
reversed.original = self
|
||||
[ reversed, something ]
|
||||
end
|
||||
|
||||
def _self_or_original
|
||||
return (self.original || self).dup
|
||||
end
|
||||
|
||||
def !=(other)
|
||||
if self.respond_to?(:inverted)
|
||||
res = self.==(other).inverted
|
||||
else
|
||||
if !self.mode_or_supported
|
||||
raise("!= operator is not allowed for '" + self.description + "'")
|
||||
end
|
||||
if !(other.is_a?(Float) || other.is_a?(Integer))
|
||||
raise("!= operator needs a numerical argument for '" + self.description + "' argument")
|
||||
end
|
||||
res = self._self_or_original
|
||||
res.mode_or = true
|
||||
res.set_lt(other)
|
||||
res.set_gt(other)
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
if !(other.is_a?(Float) || other.is_a?(Integer))
|
||||
raise("== operator needs a numerical argument for '" + self.description + "' argument")
|
||||
end
|
||||
res = self._self_or_original
|
||||
res.set_le(other)
|
||||
res.set_ge(other)
|
||||
return res
|
||||
end
|
||||
|
||||
def <(other)
|
||||
if !(other.is_a?(Float) || other.is_a?(Integer))
|
||||
raise("< operator needs a numerical argument for '" + self.description + "' argument")
|
||||
end
|
||||
res = self._self_or_original
|
||||
if reverse
|
||||
res.set_gt(other)
|
||||
else
|
||||
res.set_lt(other)
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
def <=(other)
|
||||
if !(other.is_a?(Float) || other.is_a?(Integer))
|
||||
raise("<= operator needs a numerical argument for '" + self.description + "' argument")
|
||||
end
|
||||
res = self._self_or_original
|
||||
if reverse
|
||||
res.set_ge(other)
|
||||
else
|
||||
res.set_le(other)
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
def >(other)
|
||||
if !(other.is_a?(Float) || other.is_a?(Integer))
|
||||
raise("> operator needs a numerical argument for '" + self.description + "' argument")
|
||||
end
|
||||
res = self._self_or_original
|
||||
if reverse
|
||||
res.set_lt(other)
|
||||
else
|
||||
res.set_gt(other)
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
def >=(other)
|
||||
if !(other.is_a?(Float) || other.is_a?(Integer))
|
||||
raise(">= operator needs a numerical argument for '" + self.description + "' argument")
|
||||
end
|
||||
res = self._self_or_original
|
||||
if reverse
|
||||
res.set_le(other)
|
||||
else
|
||||
res.set_ge(other)
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# A wrapper for a named value which is stored in
|
||||
# a variable for delayed execution
|
||||
class DRCVar
|
||||
|
|
|
|||
|
|
@ -208,3 +208,13 @@ TEST(14d)
|
|||
{
|
||||
run_test (_this, "14", true);
|
||||
}
|
||||
|
||||
TEST(15)
|
||||
{
|
||||
run_test (_this, "15", false);
|
||||
}
|
||||
|
||||
TEST(15d)
|
||||
{
|
||||
run_test (_this, "15", true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,47 +28,51 @@ out = in.drc((width < 2.0).polygons)
|
|||
The following global functions are relevant for the DRC expressions:
|
||||
</p><p>
|
||||
<ul>
|
||||
<li><a href="/about/drc_ref_global.xml#angle">global#angle</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#area">global#area</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#area_ratio">global#area_ratio</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#bbox_area_ratio">global#bbox_area_ratio</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#bbox_height">global#bbox_height</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#bbox_max">global#bbox_max</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#bbox_min">global#bbox_min</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#bbox_width">global#bbox_width</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#case">global#case</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#secondary">global#secondary</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#primary">global#primary</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#corners">global#corners</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#covering">global#covering</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#enc">global#enc</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#enclosing">global#enclosing</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#extent_refs">global#extent_refs</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#extents">global#extents</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#foreign">global#foreign</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#holes">global#holes</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#hulls">global#hulls</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#if_all">global#if_all</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#if_any">global#if_any</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#if_none">global#if_none</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#bbox_height">global#bbox_height</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#bbox_width">global#bbox_width</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#bbox_max">global#bbox_max</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#bbox_min">global#bbox_min</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#area">global#area</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#hulls">global#hulls</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#holes">global#holes</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#inside">global#inside</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#interacting">global#interacting</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#iso">global#iso</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#length">global#length</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#middle">global#middle</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#notch">global#notch</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#odd_polygons">global#odd_polygons</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#outside">global#outside</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#overlap">global#overlap</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#overlapping">global#overlapping</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#perimeter">global#perimeter</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#primary">global#primary</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#rectangles">global#rectangles</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#rectilinear">global#rectilinear</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#length">global#length</a> (in condition) </li>
|
||||
<li><a href="/about/drc_ref_global.xml#angle">global#angle</a> (in condition) </li>
|
||||
<li><a href="/about/drc_ref_global.xml#corners">global#corners</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#extent_refs">global#extent_refs</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#extents">global#extents</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#middle">global#middle</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#relative_height">global#relative_height</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#rounded_corners">global#rounded_corners</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#secondary">global#secondary</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#separation">global#separation</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#sep">global#sep</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#sized">global#sized</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#smoothed">global#smoothed</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#covering">global#covering</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#interacting">global#interacting</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#overlapping">global#overlapping</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#inside">global#inside</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#outside">global#outside</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#enclosing">global#enclosing</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#separation">global#separation</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#overlap">global#overlap</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#width">global#width</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#space">global#space</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#notch">global#notch</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#iso">global#iso</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#sep">global#sep</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#enc">global#enc</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#squares">global#squares</a> </li>
|
||||
<li><a href="/about/drc_ref_global.xml#width">global#width</a> </li>
|
||||
</ul>
|
||||
</p><p>
|
||||
The following documentation will list the methods available for DRC expression objects.
|
||||
|
|
@ -206,7 +210,61 @@ out = in.drc(primary.area < 2.0) # equivalent
|
|||
The area method is available as a plain function or as a method on <a href="/about/drc_ref_drc.xml">DRC</a> expressions.
|
||||
The plain function is equivalent to "primary.area".
|
||||
</p>
|
||||
<a name="bbox_height"/><h2>"bbox_height" - Selects the primary shape if its bounding box height is meeting the condition</h2>
|
||||
<a name="area_ratio"/><h2>"area_ratio" - Selects the input polygon according to its area ratio (bounding box area by polygon area)</h2>
|
||||
<keyword name="area_ratio"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>expression.area_ratio (in condition)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This operation is used in conditions to select shapes based on their area ratio.
|
||||
The area ratio is the ratio of bounding box vs. polygon area. It's a measure how
|
||||
"sparse" the polygons are and how good an approximation the bounding box is.
|
||||
The value is always larger or equal than 1. Boxes have a value of 1.
|
||||
</p><p>
|
||||
This filter is applicable on polygon expressions. The result will be the input
|
||||
polygon if the condition is met.
|
||||
</p><p>
|
||||
See <a href="/about/drc_ref_layer.xml#drc">Layer#drc</a> for more details about comparison specs.
|
||||
</p><p>
|
||||
The following example will select all polygons whose area ratio is larger than 3:
|
||||
</p><p>
|
||||
<pre>
|
||||
out = in.drc(area_ratio > 3)
|
||||
out = in.drc(primary.area_ratio > 3) # equivalent
|
||||
</pre>
|
||||
</p><p>
|
||||
The "area_ratio" method is available as a plain function or as a method on <a href="/about/drc_ref_drc#.xml">DRC#</a> expressions.
|
||||
The plain function is equivalent to "primary.area_ratio".
|
||||
</p>
|
||||
<a name="bbox_aspect_ratio"/><h2>"bbox_aspect_ratio" - Selects the input polygon according to the aspect ratio of the bounding box</h2>
|
||||
<keyword name="bbox_aspect_ratio"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>expression.bbox_aspect_ratio (in condition)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This operation is used in conditions to select shapes based on aspect ratios of their bounding boxes.
|
||||
The aspect ratio is computed by dividing the larger of width and height by the smaller of both.
|
||||
The aspect ratio is always larger or equal to 1. Square or square-boxed shapes have a
|
||||
bounding box aspect ratio of 1.
|
||||
</p><p>
|
||||
This filter is applicable on polygon expressions. The result will be the input
|
||||
polygon if the bounding box condition is met.
|
||||
</p><p>
|
||||
See <a href="/about/drc_ref_layer.xml#drc">Layer#drc</a> for more details about comparison specs.
|
||||
</p><p>
|
||||
The following example will select all polygons whose bounding box aspect ratio is larger than 3:
|
||||
</p><p>
|
||||
<pre>
|
||||
out = in.drc(bbox_aspect_ratio > 3)
|
||||
out = in.drc(primary.bbox_aspect_ratio > 3) # equivalent
|
||||
</pre>
|
||||
</p><p>
|
||||
The "bbox_aspect_ratio" method is available as a plain function or as a method on <a href="/about/drc_ref_drc#.xml">DRC#</a> expressions.
|
||||
The plain function is equivalent to "primary.bbox_aspect_ratio".
|
||||
</p>
|
||||
<a name="bbox_height"/><h2>"bbox_height" - Selects the input polygon if its bounding box height is meeting the condition</h2>
|
||||
<keyword name="bbox_height"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
|
|
@ -222,7 +280,7 @@ ones not rotated. This usually results in a larger computation effort and larger
|
|||
The "bbox_height" method is available as a plain function or as a method on <a href="/about/drc_ref_drc.xml">DRC</a> expressions.
|
||||
The plain function is equivalent to "primary.bbox_height".
|
||||
</p>
|
||||
<a name="bbox_max"/><h2>"bbox_max" - Selects the primary shape if its bounding box larger dimension is meeting the condition</h2>
|
||||
<a name="bbox_max"/><h2>"bbox_max" - Selects the input polygon if its bounding box larger dimension is meeting the condition</h2>
|
||||
<keyword name="bbox_max"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
|
|
@ -235,7 +293,7 @@ bounding box.
|
|||
The "bbox_max" method is available as a plain function or as a method on <a href="/about/drc_ref_drc.xml">DRC</a> expressions.
|
||||
The plain function is equivalent to "primary.bbox_max".
|
||||
</p>
|
||||
<a name="bbox_min"/><h2>"bbox_min" - Selects the primary shape if its bounding box smaller dimension is meeting the condition</h2>
|
||||
<a name="bbox_min"/><h2>"bbox_min" - Selects the input polygon if its bounding box smaller dimension is meeting the condition</h2>
|
||||
<keyword name="bbox_min"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
|
|
@ -259,7 +317,7 @@ out = in.drc(primary.bbox_min > 200.nm) # equivalent
|
|||
The "bbox_min" method is available as a plain function or as a method on <a href="/about/drc_ref_drc#.xml">DRC#</a> expressions.
|
||||
The plain function is equivalent to "primary.bbox_min".
|
||||
</p>
|
||||
<a name="bbox_width"/><h2>"bbox_width" - Selects the primary shape if its bounding box width is meeting the condition</h2>
|
||||
<a name="bbox_width"/><h2>"bbox_width" - Selects the input polygon if its bounding box width is meeting the condition</h2>
|
||||
<keyword name="bbox_width"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
|
|
@ -554,7 +612,7 @@ wrap count rule in place.
|
|||
This operation can be used as a plain function in which case it acts on primary
|
||||
shapes or can be used as method on another DRC expression.
|
||||
</p>
|
||||
<a name="perimeter"/><h2>"perimeter" - Selects the primary shape if the perimeter is meeting the condition</h2>
|
||||
<a name="perimeter"/><h2>"perimeter" - Selects the input polygon if the perimeter is meeting the condition</h2>
|
||||
<keyword name="perimeter"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
|
|
@ -635,6 +693,35 @@ out = in.drc(rectilinear)
|
|||
out = in.drc(primary.rectilinear) # equivalent
|
||||
</pre>
|
||||
</p>
|
||||
<a name="relative_height"/><h2>"relative_height" - Selects the input polygon according to the height vs. width of the bounding box</h2>
|
||||
<keyword name="relative_height"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>expression.relative_height (in condition)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This operation is used in conditions to select shapes based on the ratio of bounding box
|
||||
height vs. width. The taller the shape, the larger the value. Wide polygons have a value
|
||||
below 1. A square has a relative height of 1.
|
||||
</p><p>
|
||||
This filter is applicable on polygon expressions. The result will be the input
|
||||
polygon if the condition is met.
|
||||
</p><p>
|
||||
Don't use this method if you can use <a href="#bbox_aspect_ratio">bbox_aspect_ratio</a>, because the latter is
|
||||
isotropic and can be used hierarchically without generating rotation variants.
|
||||
</p><p>
|
||||
See <a href="/about/drc_ref_layer.xml#drc">Layer#drc</a> for more details about comparison specs.
|
||||
</p><p>
|
||||
The following example will select all polygons whose relative height is larger than 3:
|
||||
</p><p>
|
||||
<pre>
|
||||
out = in.drc(relative_height > 3)
|
||||
out = in.drc(primary.relative_height > 3) # equivalent
|
||||
</pre>
|
||||
</p><p>
|
||||
The "relative_height" method is available as a plain function or as a method on <a href="/about/drc_ref_drc#.xml">DRC#</a> expressions.
|
||||
The plain function is equivalent to "primary.bbox_aspect_ratio".
|
||||
</p>
|
||||
<a name="rounded_corners"/><h2>"rounded_corners" - Applies corner rounding</h2>
|
||||
<keyword name="rounded_corners"/>
|
||||
<p>Usage:</p>
|
||||
|
|
@ -684,6 +771,22 @@ This operation acts on polygons and applies polygon smoothing with the tolerance
|
|||
The "smoothed" method is available as a plain function or as a method on <a href="/about/drc_ref_drc.xml">DRC</a> expressions.
|
||||
The plain function is equivalent to "primary.smoothed".
|
||||
</p>
|
||||
<a name="squares"/><h2>"squares" - Selects all polygons which are squares</h2>
|
||||
<keyword name="squares"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>expression.squares</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This operation can be used as a plain function in which case it acts on primary
|
||||
shapes or can be used as method on another DRC expression.
|
||||
The following example selects all squares:
|
||||
</p><p>
|
||||
<pre>
|
||||
out = in.drc(squares)
|
||||
out = in.drc(primary.squares) # equivalent
|
||||
</pre>
|
||||
</p>
|
||||
<a name="start_segments"/><h2>"start_segments" - Returns the part at the beginning of each edge of the input</h2>
|
||||
<keyword name="start_segments"/>
|
||||
<p>Usage:</p>
|
||||
|
|
|
|||
|
|
@ -43,6 +43,24 @@ polygons in the layer.
|
|||
Without a layer argument, "area" represents an area filter for primary shapes in
|
||||
<a href="/about/drc_ref_drc.xml">DRC</a> expressions (see <a href="/about/drc_ref_layer.xml#drc">Layer#drc</a> and <a href="/about/drc_ref_drc.xml#area">DRC#area</a> for more details).
|
||||
</p>
|
||||
<a name="area_ratio"/><h2>"area_ratio" - Selects primary shapes based on the ratio of bounding box and polygon area</h2>
|
||||
<keyword name="area_ratio"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>area_ratio (in condition)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
See <a href="/about/drc_ref_layer.xml#drc">Layer#drc</a>, <a href="#area_ratio">area_ratio</a> and <a href="/about/drc_ref_drc.xml#area_ratio">DRC#area_ratio</a> for more details.
|
||||
</p>
|
||||
<a name="bbox_aspect_ratio"/><h2>"bbox_aspect_ratio" - Selects primary shapes based on the aspect ratio of their bounding boxes</h2>
|
||||
<keyword name="bbox_aspect_ratio"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>bbox_aspect_ratio (in condition)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
See <a href="/about/drc_ref_layer.xml#drc">Layer#drc</a>, <a href="#bbox_aspect_ratio">bbox_aspect_ratio</a> and <a href="/about/drc_ref_drc.xml#bbox_aspect_ratio">DRC#bbox_aspect_ratio</a> for more details.
|
||||
</p>
|
||||
<a name="bbox_height"/><h2>"bbox_height" - Selects primary shapes based on their bounding box height</h2>
|
||||
<keyword name="bbox_height"/>
|
||||
<p>Usage:</p>
|
||||
|
|
@ -364,13 +382,9 @@ applied to coners meeting a particular angle constraint.
|
|||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>covering(other) (in conditions)</tt></li>
|
||||
<li><tt>covering(layer, other [, options ])</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This function can be used with a layer argument in which case it
|
||||
is equivalent to "layer.covering" (see <a href="/about/drc_ref_layer.xml#covering">Layer#covering</a>).
|
||||
</p><p>
|
||||
Without a layer argument, this method represents the selector of primary shapes
|
||||
This method represents the selector of primary shapes
|
||||
which entirely cover shapes from the other layer. This version can be put into
|
||||
a condition indicating how many shapes of the other layer need to be covered.
|
||||
Use this variant within <a href="/about/drc_ref_drc.xml">DRC</a> expressions (also see <a href="/about/drc_ref_layer.xml#drc">Layer#drc</a>).
|
||||
|
|
@ -567,6 +581,7 @@ out = in.drc(enclosing(other) <= 0.2.um)
|
|||
out = in.drc(enclosing(other) > 0.2.um)
|
||||
out = in.drc(enclosing(other) >= 0.2.um)
|
||||
out = in.drc(enclosing(other) == 0.2.um)
|
||||
out = in.drc(enclosing(other) != 0.2.um)
|
||||
out = in.drc(0.1.um <= enclosing(other) < 0.2.um)
|
||||
</pre>
|
||||
</p><p>
|
||||
|
|
@ -759,13 +774,9 @@ this method.
|
|||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>inside(other)</tt></li>
|
||||
<li><tt>inside(layer, other)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This function can be used with a layer argument in which case it
|
||||
is equivalent to "layer.inside" (see <a href="/about/drc_ref_layer.xml#inside">Layer#inside</a>).
|
||||
</p><p>
|
||||
Without a layer argument, this method represents the selector of primary shapes
|
||||
This method represents the selector of primary shapes
|
||||
which are entirely inside shapes from the other layer.
|
||||
Use this variant within <a href="/about/drc_ref_drc.xml">DRC</a> expressions (also see <a href="/about/drc_ref_layer.xml#drc">Layer#drc</a>).
|
||||
</p>
|
||||
|
|
@ -774,12 +785,18 @@ Use this variant within <a href="/about/drc_ref_drc.xml">DRC</a> expressions (al
|
|||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>interacting(other) (in conditions)</tt></li>
|
||||
<li><tt>interacting(layer, other [, options ])</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
See <a href="#covering">covering</a> for a description of the use cases for this function.
|
||||
When using "interacting", shapes are selected when the interact (overlap, touch)
|
||||
shapes from the other layer.
|
||||
</p><p>
|
||||
When using this method with a count, the operation may not render
|
||||
the correct results if the other input is not merged. By nature of the
|
||||
generic DRC feature, only those shapes that interact with the primary shape
|
||||
will be selected. If the other input is split into multiple polygons,
|
||||
not all components may be captured and the computed interaction count
|
||||
may be incorrect.
|
||||
</p>
|
||||
<a name="is_deep?"/><h2>"is_deep?" - Returns true, if in deep mode</h2>
|
||||
<keyword name="is_deep?"/>
|
||||
|
|
@ -1066,13 +1083,9 @@ layout if is report database.
|
|||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>outside(other)</tt></li>
|
||||
<li><tt>outside(layer, other)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This function can be used with a layer argument in which case it
|
||||
is equivalent to "layer.outside" (see <a href="/about/drc_ref_layer.xml#outside">Layer#outside</a>).
|
||||
</p><p>
|
||||
Without a layer argument, this method represents the selector of primary shapes
|
||||
This method represents the selector of primary shapes
|
||||
which are entirely outside shapes from the other layer.
|
||||
Use this variant within <a href="/about/drc_ref_drc.xml">DRC</a> expressions (also see <a href="/about/drc_ref_layer.xml#drc">Layer#drc</a>).
|
||||
</p>
|
||||
|
|
@ -1092,12 +1105,18 @@ function provides a two-layer check. See there for details how to use this funct
|
|||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>overlapping(other) (in conditions)</tt></li>
|
||||
<li><tt>overlapping(layer, other [, options ])</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
See <a href="#covering">covering</a> for a description of the use cases for this function.
|
||||
When using "overlapping", shapes are selected when the overlap
|
||||
shapes from the other layer.
|
||||
</p><p>
|
||||
When using this method with a count, the operation may not render
|
||||
the correct results if the other input is not merged. By nature of the
|
||||
generic DRC feature, only those shapes that interact with the primary shape
|
||||
will be selected. If the other input is split into multiple polygons,
|
||||
not all components may be captured and the computed interaction count
|
||||
may be incorrect.
|
||||
</p>
|
||||
<a name="p"/><h2>"p" - Creates a point object</h2>
|
||||
<keyword name="p"/>
|
||||
|
|
@ -1206,6 +1225,15 @@ is equivalent to "layer.rectilinear" (see <a href="/about/drc_ref_layer.xml#rect
|
|||
argument, "rectilinear" represents the rectilinear polygons filter for primary shapes in
|
||||
<a href="/about/drc_ref_drc.xml">DRC</a> expressions (see <a href="/about/drc_ref_layer.xml#drc">Layer#drc</a> and <a href="/about/drc_ref_drc.xml#rectilinear">DRC#rectilinear</a> for more details).
|
||||
</p>
|
||||
<a name="relative_height"/><h2>"relative_height" - Selects primary shapes based on the ratio of height and width of their bounding boxes</h2>
|
||||
<keyword name="relative_height"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>relative_height (in condition)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
See <a href="/about/drc_ref_layer.xml#drc">Layer#drc</a>, <a href="#relative_height">relative_height</a> and <a href="/about/drc_ref_drc.xml#relative_height">DRC#relative_height</a> for more details.
|
||||
</p>
|
||||
<a name="report"/><h2>"report" - Specifies a report database for output</h2>
|
||||
<keyword name="report"/>
|
||||
<p>Usage:</p>
|
||||
|
|
@ -1419,6 +1447,19 @@ For further methods on the source object see <a href="#Source">Source</a>.
|
|||
Provides a space check on the primary layer. Like <a href="#width">width</a> this
|
||||
function provides a single-layer check. See there for details how to use this function.
|
||||
</p>
|
||||
<a name="squares"/><h2>"squares" - Selects all polygons which are squares</h2>
|
||||
<keyword name="squares"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>squares</tt></li>
|
||||
<li><tt>squares(layer)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This function can be used with a layer argument in which case it
|
||||
is equivalent to "layer.squares" (see <a href="/about/drc_ref_layer.xml#squares">Layer#squares</a>). Without a layer
|
||||
argument, "squares" represents the rectangles filter for primary shapes in
|
||||
<a href="/about/drc_ref_drc.xml">DRC</a> expressions (see <a href="/about/drc_ref_layer.xml#drc">Layer#drc</a> and <a href="/about/drc_ref_drc.xml#squares">DRC#squares</a> for more details).
|
||||
</p>
|
||||
<a name="target"/><h2>"target" - Specify the target layout</h2>
|
||||
<keyword name="target"/>
|
||||
<p>Usage:</p>
|
||||
|
|
@ -1568,6 +1609,7 @@ out = in.drc(width <= 0.2.um)
|
|||
out = in.drc(width > 0.2.um)
|
||||
out = in.drc(width >= 0.2.um)
|
||||
out = in.drc(width == 0.2.um)
|
||||
out = in.drc(width != 0.2.um)
|
||||
out = in.drc(0.1.um <= width < 0.2.um)
|
||||
</pre>
|
||||
</p><p>
|
||||
|
|
|
|||
|
|
@ -366,18 +366,142 @@ merged, so the secondary polygons may be partial. This is important when
|
|||
using measurement operations like "area" on secondary polygons.
|
||||
</p><p>
|
||||
Here is an example for a generic DRC operation which performs a width
|
||||
check for less than 0.5.um on the primary shapes.
|
||||
check for less than 0.5.um on the primary shapes. It uses the <a href="/about/drc_ref_global.xml#width">global#width</a> operator:
|
||||
</p><p>
|
||||
<pre>
|
||||
out = in.drc(width < 0.5.um)
|
||||
</pre>
|
||||
</p><p>
|
||||
Another example computes a boolean AND between two layers before selecting
|
||||
the result polygons with an area larger than 1 square micrometer:
|
||||
Other single or double-bounded conditions are available too, for example:
|
||||
</p><p>
|
||||
<pre>
|
||||
other = ... another layer ..
|
||||
out = in.drc((primary & other).area > 1.0)
|
||||
out = in.drc(width <= 0.5.um)
|
||||
out = in.drc(width > 0.5.um)
|
||||
out = in.drc(width == 0.5.um)
|
||||
out = in.drc(width != 0.5.um)
|
||||
out = in.drc(0.2.um < width < 0.5.um)
|
||||
</pre>
|
||||
</p><p>
|
||||
To specify the second input for a two-layer check, specify the second input
|
||||
with the check function. Here a two-layer separation check is used (<a href="/about/drc_ref_global.xml#separation">global#separation</a>):
|
||||
</p><p>
|
||||
<pre>
|
||||
l1 = input(1, 0)
|
||||
l2 = input(2, 0)
|
||||
out = l1.drc(separation(l2) < 0.5.um)
|
||||
</pre>
|
||||
</p><p>
|
||||
The second input of this check function can be a computed expression. In this
|
||||
case the local loop will first evaluate the expression for the second input and
|
||||
then use it inside the check.
|
||||
</p><p>
|
||||
Options for the checks are also specified inside the brackets. For example,
|
||||
to specify a projection metrics for width use:
|
||||
</p><p>
|
||||
<pre>
|
||||
out = in.drc(width(projection) < 0.5.um)
|
||||
</pre>
|
||||
</p><p>
|
||||
The "drc" function supports filter operators. These select input or derived polygons
|
||||
based on their properties. These filters are:
|
||||
</p><p>
|
||||
<ul>
|
||||
<li>"<a href="/about/drc_ref_global.xml#area">global#area</a>": select polygons based on their area </li>
|
||||
<li>"<a href="/about/drc_ref_global.xml#perimeter">global#perimeter</a>": select polygons based on their perimeter </li>
|
||||
<li>"<a href="/about/drc_ref_global.xml#bbox_min">global#bbox_min</a>", "<a href="/about/drc_ref_global.xml#bbox_max">global#bbox_max</a>", "<a href="/about/drc_ref_global.xml#bbox_width">global#bbox_width</a>", "<a href="/about/drc_ref_global.xml#bbox_height">global#bbox_height</a>": select polygons based on their bounding box properties </li>
|
||||
</ul>
|
||||
</p><p>
|
||||
For example, to select polygons with an area larger than one square micrometer, use:
|
||||
</p><p>
|
||||
<pre>
|
||||
out = in.drc(area > 1.0)
|
||||
</pre>
|
||||
</p><p>
|
||||
For the condition, use the usual numerical bounds like:
|
||||
</p><p>
|
||||
<pre>
|
||||
out = in.drc(area == 1.0)
|
||||
out = in.drc(area <= 1.0)
|
||||
out = in.drc(0.2 < area < 1.0)
|
||||
</pre>
|
||||
</p><p>
|
||||
The result of the area operation is the input polygon if the area condition is met.
|
||||
</p><p>
|
||||
In the same fashion, "perimeter" applies to the perimeter of the polygon.
|
||||
"bbox_min" etc. will evaluate a particular dimensions of the polygon's bounding box and
|
||||
use the respective dimension for filtering the polygon.
|
||||
</p><p>
|
||||
Note that it's basically possible to use the polygon filters on any kind of input.
|
||||
In fact, plain "area" for example is a shortcut for "<a href="/about/drc_ref_global.xml#primary">global#primary</a>.area" indicating that
|
||||
the area of primary shapes are supposed to be computed.
|
||||
However, any input other than the primary is not necessarily complete or it may
|
||||
consist of multiple polygons. Hence the computed values may be too big or too small.
|
||||
It's recommended therefore to use the measurement functions on primary polygons
|
||||
only.
|
||||
</p><p>
|
||||
The "drc" feature also supports some predicates. "predicates" are boolean values
|
||||
indicating a certain condition. A predicate filter works in a way that it only
|
||||
passes the polygons
|
||||
The predicates available currently are:
|
||||
</p><p>
|
||||
<ul>
|
||||
<li>"<a href="/about/drc_ref_global.xml#rectangles">global#rectangles</a>": Filters rectangles </li>
|
||||
<li>"<a href="/about/drc_ref_global.xml#rectilinear">global#rectilinear</a>": Filters rectilinear ("Manhattan") polygons </li>
|
||||
</ul>
|
||||
</p><p>
|
||||
For the same reason as explained above, it's recommended to use these predicates
|
||||
standalone, so they act on primary shapes. It's possible to use the predicates
|
||||
on computed shapes or secondary input, but that may not render the desired results.
|
||||
</p><p>
|
||||
The "!" operator will evaluate the expression behind it and return the
|
||||
current primary shape if the input is empty and return an empty polygon set
|
||||
if not. Hence the following filter will deliver all polygons which are
|
||||
not rectangles:
|
||||
</p><p>
|
||||
<pre>
|
||||
out = in.drc(! rectangles)
|
||||
</pre>
|
||||
</p><p>
|
||||
The logical "if_any" or "if_all" statements allow connecting multiple
|
||||
conditions and evaluate to "true" (means: a non-empty shape set) if either
|
||||
on input is a non-empty shape set ("if_any") or if all inputs are non-empty
|
||||
("if_all"). For example, this will select all polygons which are rectangles
|
||||
and whose area is larger than 20 quare micrometers:
|
||||
</p><p>
|
||||
<pre>
|
||||
out = in.drc(if_all(rectangles, area > 20.0))
|
||||
</pre>
|
||||
</p><p>
|
||||
In fact, "if_all" renders the result of the last expression, provided all
|
||||
previous ones are non-empty. So this operation will render rectangles
|
||||
sized by 100 nm and skip all other types of polygons:
|
||||
</p><p>
|
||||
<pre>
|
||||
out = in.drc(if_all(rectangles, sized(100.nm)))
|
||||
</pre>
|
||||
</p><p>
|
||||
Contrary to this, the "if_any" operation will render the first non-empty
|
||||
expression result and skip the following ones. So this example will
|
||||
size all rectangles by 100 nm and leave all other types of polygons
|
||||
untouched:
|
||||
</p><p>
|
||||
<pre>
|
||||
out = in.drc(if_any(rectangles.sized(100.nm), primary))
|
||||
</pre>
|
||||
</p><p>
|
||||
The "drc" operations feature polygon manipulations where the input is
|
||||
either the primary polygon or derived shapes.
|
||||
Manipulations include sizing ("<a href="/about/drc_ref_global.xml#sized">global#sized</a>"), corner rounding ("<a href="/about/drc_ref_global.xml#rounded_corners">global#rounded_corners</a>"), smoothing ("<a href="/about/drc_ref_global.xml#smoothed">global#smoothed</a>")
|
||||
and boolean operations.
|
||||
</p><p>
|
||||
This example computes a boolean AND between two layers before selecting
|
||||
the result polygons with an area larger than 1 square micrometer. Note that
|
||||
"primary" is a placeholder for the primary shape:
|
||||
</p><p>
|
||||
<pre>
|
||||
l1 = input(1, 0)
|
||||
l2 = input(2, 0)
|
||||
out = l1.drc((primary & l2).area > 1.0)
|
||||
</pre>
|
||||
</p><p>
|
||||
This example demonstrates how the "drc" operation can improve performance: as the
|
||||
|
|
@ -385,7 +509,62 @@ boolean operation is computed locally and the result is discarded when no longer
|
|||
less shapes need to be stored hence reducing the memory overhead and CPU time required
|
||||
to manage these shapes.
|
||||
</p><p>
|
||||
For more details about the expression see the <a href="/about/drc_ref_drc.xml">DRC</a> class documentation.
|
||||
Note that the precise form of the example above is
|
||||
</p><p>
|
||||
<pre>
|
||||
out = l1.drc((primary & secondary(l2)).area > 1.0)
|
||||
</pre>
|
||||
</p><p>
|
||||
The "<a href="/about/drc_ref_global.xml#secondar">global#secondar</a>" operator indicates that "l2" is to be used as secondary input to the "drc" function. Only
|
||||
in this form, the operators of the boolean AND can be reversed:
|
||||
</p><p>
|
||||
<pre>
|
||||
out = l1.drc((secondary(l2) & primary).area > 1.0)
|
||||
</pre>
|
||||
</p><p>
|
||||
The expression inside the "drc" function is a Ruby object and can be
|
||||
stored in variables. If you need the same expression multiple times, it can be
|
||||
more efficient to use the same Ruby object. In this example, the same expression
|
||||
is used two times. Hence it's computed two times:
|
||||
</p><p>
|
||||
<pre>
|
||||
out = l1.drc(((primary & l2).area == 1.0) + ((primary & l2).area == 2.0))
|
||||
</pre>
|
||||
</p><p>
|
||||
A more efficient version is:
|
||||
</p><p>
|
||||
<pre>
|
||||
overlap_area = (primary & l2).area
|
||||
out = l1.drc((overlap_area == 1.0) + (overlap_area == 2.0))
|
||||
</pre>
|
||||
</p><p>
|
||||
Note that the first line prepares the operation, but does not execute the area computation
|
||||
or the boolean operation. But when the "drc" function executes the operation it will
|
||||
only compute the area once as it is represented by the same Ruby object.
|
||||
</p><p>
|
||||
The "drc" functionality also offers support for edge pairs and edges. Edge pairs
|
||||
are the results of check operations and can be turned into polygons using the
|
||||
"polygons" method:
|
||||
</p><p>
|
||||
<pre>
|
||||
drc = in.drc((width < 0.5.um).polygons)
|
||||
</pre>
|
||||
</p><p>
|
||||
Similarly, polygons can be converted into edges:
|
||||
</p><p>
|
||||
<pre>
|
||||
drc = in.drc(primary.edges)
|
||||
</pre>
|
||||
</p><p>
|
||||
The "drc" framework supports edge vs. edge and edge vs. polygon booleans, edge
|
||||
filters (<a href="/about/drc_ref_global.xml#length">global#length</a>, <a href="/about/drc_ref_global.xml#angle">global#angle</a>), edge vs. polygon interactions (<a href="/about/drc_ref_global.xml#interacting">global#interacting</a>, <a href="/about/drc_ref_global.xml#overlapping">global#overlapping</a>),
|
||||
edge sampling (<a href="/about/drc_ref_global.xml#start_segments">global#start_segments</a>, <a href="/about/drc_ref_global.xml#centers">global#centers</a>, <a href="/about/drc_ref_global.xml#end_segments">global#end_segments</a>) and edge to polygon
|
||||
conversions (<a href="/about/drc_ref_global.xml#extended">global#extended</a>, <a href="/about/drc_ref_global.xml#extended_in">global#extended_in</a>, <a href="/about/drc_ref_global.xml#extended_out">global#extended_out</a>). Edge pairs
|
||||
can be converted into polygons and edges and separated into first and second edges (<a href="/about/drc_ref_global.xml#first_edges">global#first_edges</a>,
|
||||
<a href="/about/drc_ref_global.xml#second_edges">global#second_edges</a>).
|
||||
</p><p>
|
||||
The bottom line is: DRC expressions are quite rich and there is a lot more to be said and written.
|
||||
More formal details about the bits and pieces can be found in the <a href="/about/drc_ref_drc.xml">DRC</a> class documentation.
|
||||
</p>
|
||||
<a name="dup"/><h2>"dup" - Duplicates a layer</h2>
|
||||
<keyword name="dup"/>
|
||||
|
|
@ -1191,6 +1370,16 @@ i.e. all polygons are merged before non-rectangles are selected (see <a href="#c
|
|||
This method is available for polygon layers. By default "merged" semantics applies,
|
||||
i.e. all polygons are merged before non-rectilinear polygons are selected (see <a href="#clean">clean</a> and <a href="#raw">raw</a>).
|
||||
</p>
|
||||
<a name="non_squares"/><h2>"non_squares" - Selects all polygons from the input which are not squares</h2>
|
||||
<keyword name="non_squares"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.non_rectangles</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method is available for polygon layers. By default "merged" semantics applies,
|
||||
i.e. all polygons are merged before non-squares are selected (see <a href="#clean">clean</a> and <a href="#raw">raw</a>).
|
||||
</p>
|
||||
<a name="non_strict"/><h2>"non_strict" - Marks a layer for non-strict handling</h2>
|
||||
<keyword name="non_strict"/>
|
||||
<p>Usage:</p>
|
||||
|
|
@ -1725,7 +1914,7 @@ l.raw
|
|||
</p><p>
|
||||
To avoid that, use the <a href="#dup">dup</a> method to create a real (deep) copy.
|
||||
</p>
|
||||
<a name="rectangles"/><h2>"rectangles" - Selects all rectangle polygons from the input</h2>
|
||||
<a name="rectangles"/><h2>"rectangles" - Selects all rectangles from the input</h2>
|
||||
<keyword name="rectangles"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
|
|
@ -2306,6 +2495,17 @@ The following image shows the effect of the space check:
|
|||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
<a name="squares"/><h2>"squares" - Selects all squares from the input</h2>
|
||||
<keyword name="squares"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.squares</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method is available for polygon layers. By default "merged" semantics applies,
|
||||
i.e. all polygons are merged before squares are selected (see <a href="#clean">clean</a> and <a href="#raw">raw</a>).
|
||||
<a href="#non_squares">non_squares</a> will select all non-rectangles.
|
||||
</p>
|
||||
<a name="start_segments"/><h2>"start_segments" - Returns the part at the beginning of each edge</h2>
|
||||
<keyword name="start_segments"/>
|
||||
<p>Usage:</p>
|
||||
|
|
@ -2486,6 +2686,10 @@ make the check only consider edges enclosing angles of less than 45 degree. </li
|
|||
<li><b>projection_limits(min, max) or projection_limits(min .. max) </b>:
|
||||
this option makes the check only consider edge pairs whose projected length on
|
||||
each other is more or equal than min and less than max </li>
|
||||
<li><b>projecting (in condition) </b>: This specification is equivalent to "projection_limits"
|
||||
but is more intuitive, as "projecting" is written with a condition, like
|
||||
"projecting < 2.um". Available operators are: "==", "<", "<=", ">" and ">=".
|
||||
Double-bounded ranges are also available, like: "0.5 <= projecting < 2.0".
|
||||
<li><b>transparent </b>: performs the check without shielding (polygon layers only) </li>
|
||||
<li><b>shielded </b>: performs the check with shielding (polygon layers only) </li>
|
||||
</ul>
|
||||
|
|
@ -2594,6 +2798,38 @@ The third form basically is equivalent to the first form, but
|
|||
allows specification of nil for min or max indicating no lower or
|
||||
upper limit.
|
||||
</p>
|
||||
<a name="with_area_ratio"/><h2>"with_area_ratio" - Selects polygons by the ratio of the bounding box area vs. polygon area</h2>
|
||||
<keyword name="with_area_ratio"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.with_area_ratio(min .. max)</tt></li>
|
||||
<li><tt>layer.with_area_ratio(value)</tt></li>
|
||||
<li><tt>layer.with_area_ratio(min, max)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
The area ratio is a measure how far a polygon is approximated by it's
|
||||
bounding box. The value is always larger or equal to 1. Boxes have a
|
||||
area ratio of 1. Larger values mean more empty area inside the bounding box.
|
||||
</p><p>
|
||||
This method is available for polygon layers only.
|
||||
</p>
|
||||
<a name="with_bbox_aspect_ratio"/><h2>"with_bbox_aspect_ratio" - Selects polygons by the aspect ratio of their bounding box</h2>
|
||||
<keyword name="with_bbox_aspect_ratio"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.with_bbox_aspect_ratio(min .. max)</tt></li>
|
||||
<li><tt>layer.with_bbox_aspect_ratio(value)</tt></li>
|
||||
<li><tt>layer.with_bbox_aspect_ratio(min, max)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
The method selects polygons similar to <a href="#with_area">with_area</a> or <a href="#with_perimeter">with_perimeter</a>.
|
||||
However, the measured value is the aspect ratio of the bounding
|
||||
box. It is the larger dimensions divided by the smaller one.
|
||||
The "thinner" the polygon, the larger the aspect ratio. A square
|
||||
bounding box gives an aspect ratio of 1.
|
||||
</p><p>
|
||||
This method is available for polygon layers only.
|
||||
</p>
|
||||
<a name="with_bbox_height"/><h2>"with_bbox_height" - Selects polygons by the height of the bounding box</h2>
|
||||
<keyword name="with_bbox_height"/>
|
||||
<p>Usage:</p>
|
||||
|
|
@ -2691,6 +2927,24 @@ upper limit.
|
|||
</p><p>
|
||||
This method is available for polygon layers only.
|
||||
</p>
|
||||
<a name="with_relative_height"/><h2>"with_relative_height" - Selects polygons by the ratio of the height vs. width of it's bounding box</h2>
|
||||
<keyword name="with_relative_height"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.with_relative_height(min .. max)</tt></li>
|
||||
<li><tt>layer.with_relative_height(value)</tt></li>
|
||||
<li><tt>layer.with_relative_height(min, max)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
The relative height is a measure how tall a polygon is. Tall polygons
|
||||
have values larger than 1, wide polygons have a value smaller than 1.
|
||||
Squares have a value of 1.
|
||||
</p><p>
|
||||
Don't use this method when you can use <a href="#with_area_ratio">with_area_ratio</a>, which provides a
|
||||
similar measure but is isotropic.
|
||||
</p><p>
|
||||
This method is available for polygon layers only.
|
||||
</p>
|
||||
<a name="without_angle"/><h2>"without_angle" - Selects edges by the their angle</h2>
|
||||
<keyword name="without_angle"/>
|
||||
<p>Usage:</p>
|
||||
|
|
@ -2719,18 +2973,29 @@ the given interval.
|
|||
</p><p>
|
||||
This method is available for polygon layers only.
|
||||
</p>
|
||||
<a name="without_bbox_height"/><h2>"without_bbox_height" - Selects polygons by the height of the bounding box</h2>
|
||||
<a name="without_area_ratio"/><h2>"without_area_ratio" - Selects polygons by the aspect ratio of their bounding box</h2>
|
||||
<keyword name="without_area_ratio"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.without_area_ratio(min .. max)</tt></li>
|
||||
<li><tt>layer.without_area_ratio(value)</tt></li>
|
||||
<li><tt>layer.without_area_ratio(min, max)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
The method provides the opposite filter for <a href="#with_area_ratio">with_area_ratio</a>.
|
||||
</p><p>
|
||||
This method is available for polygon layers only.
|
||||
</p>
|
||||
<a name="without_bbox_height"/><h2>"without_bbox_height" - Selects polygons by the aspect ratio of their bounding box</h2>
|
||||
<keyword name="without_bbox_height"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.without_bbox_height(min .. max)</tt></li>
|
||||
<li><tt>layer.without_bbox_height(value)</tt></li>
|
||||
<li><tt>layer.without_bbox_height(min, max)</tt></li>
|
||||
<li><tt>layer.without_bbox_aspect_ratio(min .. max)</tt></li>
|
||||
<li><tt>layer.without_bbox_aspect_ratio(value)</tt></li>
|
||||
<li><tt>layer.without_bbox_aspect_ratio(min, max)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
The method selects polygons similar to <a href="#without_area">without_area</a> or <a href="#without_perimeter">without_perimeter</a>.
|
||||
However, the measured dimension is the width of the
|
||||
bounding box.
|
||||
The method provides the opposite filter for <a href="#with_bbox_aspect_ratio">with_bbox_aspect_ratio</a>.
|
||||
</p><p>
|
||||
This method is available for polygon layers only.
|
||||
</p>
|
||||
|
|
@ -2811,6 +3076,19 @@ the given interval.
|
|||
</p><p>
|
||||
This method is available for polygon layers only.
|
||||
</p>
|
||||
<a name="without_relative_height"/><h2>"without_relative_height" - Selects polygons by the ratio of the height vs. width</h2>
|
||||
<keyword name="without_relative_height"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>layer.without_relative_height(min .. max)</tt></li>
|
||||
<li><tt>layer.without_relative_height(value)</tt></li>
|
||||
<li><tt>layer.without_relative_height(min, max)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
The method provides the opposite filter for <a href="#with_relative_height">with_relative_height</a>.
|
||||
</p><p>
|
||||
This method is available for polygon layers only.
|
||||
</p>
|
||||
<a name="xor"/><h2>"xor" - Boolean XOR operation</h2>
|
||||
<keyword name="xor"/>
|
||||
<p>Usage:</p>
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include "tlExpression.h"
|
||||
#include "tlFileUtils.h"
|
||||
#include "tlStream.h"
|
||||
#include "tlEnv.h"
|
||||
|
||||
#include "rba.h"
|
||||
#include "rbaInspector.h"
|
||||
|
|
@ -77,74 +78,91 @@ namespace rba
|
|||
// -------------------------------------------------------------------
|
||||
// RubyStackTraceProvider definition and implementation
|
||||
|
||||
class RBA_PUBLIC RubyStackTraceProvider
|
||||
: public gsi::StackTraceProvider
|
||||
RubyStackTraceProvider::RubyStackTraceProvider (const std::string &scope)
|
||||
: m_scope (scope)
|
||||
{ }
|
||||
|
||||
std::vector<tl::BacktraceElement>
|
||||
RubyStackTraceProvider::stack_trace () const
|
||||
{
|
||||
public:
|
||||
RubyStackTraceProvider (const std::string &scope)
|
||||
: m_scope (scope)
|
||||
{ }
|
||||
std::vector<tl::BacktraceElement> bt;
|
||||
bt.push_back (tl::BacktraceElement (rb_sourcefile (), rb_sourceline ()));
|
||||
static ID id_caller = rb_intern ("caller");
|
||||
rba_get_backtrace_from_array (rb_funcall (rb_mKernel, id_caller, 0), bt, 0);
|
||||
return bt;
|
||||
}
|
||||
|
||||
virtual std::vector<tl::BacktraceElement> stack_trace () const
|
||||
{
|
||||
std::vector<tl::BacktraceElement> bt;
|
||||
bt.push_back (tl::BacktraceElement (rb_sourcefile (), rb_sourceline ()));
|
||||
static ID id_caller = rb_intern ("caller");
|
||||
rba_get_backtrace_from_array (rb_funcall (rb_mKernel, id_caller, 0), bt, 0);
|
||||
return bt;
|
||||
size_t
|
||||
RubyStackTraceProvider::scope_index () const
|
||||
{
|
||||
if (! m_scope.empty ()) {
|
||||
return RubyStackTraceProvider::scope_index (stack_trace (), m_scope);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
virtual size_t scope_index () const
|
||||
{
|
||||
if (! m_scope.empty ()) {
|
||||
std::vector<tl::BacktraceElement> bt = stack_trace ();
|
||||
for (size_t i = 0; i < bt.size (); ++i) {
|
||||
if (bt[i].file == m_scope) {
|
||||
return i;
|
||||
}
|
||||
size_t
|
||||
RubyStackTraceProvider::scope_index (const std::vector<tl::BacktraceElement> &bt, const std::string &scope)
|
||||
{
|
||||
if (! scope.empty ()) {
|
||||
|
||||
static int consider_scope = -1;
|
||||
|
||||
// disable scoped debugging (e.g. DRC script lines) if $KLAYOUT_RBA_DEBUG_SCOPE is set.
|
||||
if (consider_scope < 0) {
|
||||
consider_scope = tl::has_env ("KLAYOUT_RBA_DEBUG_SCOPE") ? 0 : 1;
|
||||
}
|
||||
if (! consider_scope) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < bt.size (); ++i) {
|
||||
if (bt[i].file == scope) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual int stack_depth () const
|
||||
{
|
||||
// NOTE: this implementation will provide an "internal stack depth".
|
||||
// It's not exactly the same than the length of the stack_trace vector length.
|
||||
// But the purpose is a relative compare, so efficiency is not sacrificed here
|
||||
// for unnecessary consistency.
|
||||
int d = 1;
|
||||
static ID id_caller = rb_intern ("caller");
|
||||
VALUE backtrace = rb_funcall (rb_mKernel, id_caller, 0);
|
||||
if (TYPE (backtrace) == T_ARRAY) {
|
||||
d += RARRAY_LEN(backtrace);
|
||||
}
|
||||
return d;
|
||||
int
|
||||
RubyStackTraceProvider::stack_depth () const
|
||||
{
|
||||
// NOTE: this implementation will provide an "internal stack depth".
|
||||
// It's not exactly the same than the length of the stack_trace vector length.
|
||||
// But the purpose is a relative compare, so efficiency is not sacrificed here
|
||||
// for unnecessary consistency.
|
||||
int d = 1;
|
||||
static ID id_caller = rb_intern ("caller");
|
||||
VALUE backtrace = rb_funcall (rb_mKernel, id_caller, 0);
|
||||
if (TYPE (backtrace) == T_ARRAY) {
|
||||
d += RARRAY_LEN(backtrace);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
// we could use this for ruby >= 1.9.3
|
||||
// we could use this for ruby >= 1.9.3
|
||||
#if 0
|
||||
static int
|
||||
count_stack_levels(void *arg, VALUE file, int line, VALUE method)
|
||||
{
|
||||
*(int *)arg += 1;
|
||||
return 0;
|
||||
}
|
||||
static int
|
||||
RubyStackTraceProvider::count_stack_levels(void *arg, VALUE file, int line, VALUE method)
|
||||
{
|
||||
*(int *)arg += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int rb_backtrace_each (int (*iter)(void *arg, VALUE file, int line, VALUE method), void *arg);
|
||||
extern "C" int
|
||||
RubyStackTraceProvider::rb_backtrace_each (int (*iter)(void *arg, VALUE file, int line, VALUE method), void *arg);
|
||||
|
||||
virutal int stack_depth ()
|
||||
{
|
||||
int l = 0;
|
||||
rb_backtrace_each(count_stack_levels, &l);
|
||||
return l;
|
||||
}
|
||||
virtual int
|
||||
RubyStackTraceProvider::stack_depth ()
|
||||
{
|
||||
int l = 0;
|
||||
rb_backtrace_each(count_stack_levels, &l);
|
||||
return l;
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
const std::string &m_scope;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// The lookup table for the method overload resolution
|
||||
|
||||
|
|
|
|||
|
|
@ -216,6 +216,29 @@ public:
|
|||
RubyInterpreterPrivateData *d;
|
||||
};
|
||||
|
||||
class RBA_PUBLIC RubyStackTraceProvider
|
||||
: public gsi::StackTraceProvider
|
||||
{
|
||||
public:
|
||||
RubyStackTraceProvider (const std::string &scope);
|
||||
|
||||
virtual std::vector<tl::BacktraceElement> stack_trace () const;
|
||||
virtual size_t scope_index () const;
|
||||
virtual int stack_depth () const;
|
||||
|
||||
static size_t scope_index (const std::vector<tl::BacktraceElement> &bt, const std::string &scope);
|
||||
|
||||
// we could use this for ruby >= 1.9.3
|
||||
#if 0
|
||||
static int count_stack_levels(void *arg, VALUE file, int line, VALUE method);
|
||||
extern "C" int rb_backtrace_each (int (*iter)(void *arg, VALUE file, int line, VALUE method), void *arg);
|
||||
virtual int stack_depth ();
|
||||
#endif
|
||||
|
||||
private:
|
||||
const std::string &m_scope;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -150,14 +150,7 @@ rba_check_error ()
|
|||
rba_get_backtrace_from_array (rb_funcall (lasterr, rb_intern ("backtrace"), 0), bt, 0);
|
||||
|
||||
const std::string &ds = RubyInterpreter::instance ()->debugger_scope ();
|
||||
if (! ds.empty ()) {
|
||||
for (size_t i = 0; i < bt.size (); ++i) {
|
||||
if (bt [i].file == ds) {
|
||||
bt.erase (bt.begin (), bt.begin () + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
bt.erase (bt.begin (), bt.begin () + RubyStackTraceProvider::scope_index (bt, ds));
|
||||
|
||||
// parse the backtrace to get the line number
|
||||
tl::BacktraceElement info;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ TARGET = rba_tests
|
|||
include($$PWD/../../lib_ut.pri)
|
||||
|
||||
SOURCES = \
|
||||
rba.cc
|
||||
rbaTests.cc
|
||||
|
||||
INCLUDEPATH += $$RBA_INC $$TL_INC $$DB_INC $$GSI_INC
|
||||
DEPENDPATH += $$RBA_INC $$TL_INC $$DB_INC $$GSI_INC
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
|
||||
source $drc_test_source
|
||||
target $drc_test_target
|
||||
|
||||
if $drc_test_deep
|
||||
deep
|
||||
end
|
||||
|
||||
l1 = input(1, 0)
|
||||
l2 = input(2, 0)
|
||||
l3 = input(3, 0)
|
||||
|
||||
l1.output(1, 0)
|
||||
l2.output(2, 0)
|
||||
l3.output(3, 0)
|
||||
|
||||
l1.drc((primary & secondary(l2)).edges.length_sum == 6.0).output(100, 0)
|
||||
l1.drc((primary & secondary(l2)).edges.length_sum <= 6.0).output(101, 0)
|
||||
|
||||
l1.drc((primary & secondary(l2)).area_sum == 1.0).output(110, 0)
|
||||
l1.drc((primary & secondary(l2)).area_sum != 1.0).output(111, 0)
|
||||
l1.drc((primary & secondary(l2)).area_sum <= 2.0).output(112, 0)
|
||||
l1.drc((primary & secondary(l2)).area_sum >= 2.0).output(113, 0)
|
||||
|
||||
l1.drc((primary & secondary(l2)).count >= 2.0).output(120, 0)
|
||||
l1.drc((primary & secondary(l2)).count != 2.0).output(121, 0)
|
||||
|
||||
l1.drc((primary & secondary(l2)).perimeter_sum == 6.0).output(130, 0)
|
||||
l1.drc((primary & secondary(l2)).perimeter_sum <= 6.0).output(131, 0)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue