New *_sum quantifiers, doc enhancements, bug fixing

This commit is contained in:
Matthias Koefferlein 2021-01-14 00:21:21 +01:00
parent 80d0229b7c
commit 80996a77fb
30 changed files with 1375 additions and 599 deletions

View File

@ -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("<", "&lt;").
gsub(">", "&gt;").
gsub(/\\([\w:#]+)/) { create_ref(mod, $1) }.
gsub(/\\\\([\w:#]+)/) { create_link(mod, $1) }.
gsub(/RBA::([\w#]+)/) { create_class_doc_ref($1) }
end

View File

@ -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 ());

View File

@ -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
{

View File

@ -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;

View File

@ -37,6 +37,8 @@
#include "dbHierProcessor.h"
#include "dbEmptyEdges.h"
#include <unordered_set>
namespace db
{

View File

@ -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) {

View File

@ -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.

View File

@ -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
*/

View File

@ -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

View File

@ -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.

View File

@ -29,6 +29,9 @@
#include "dbLocalOperation.h"
#include "dbEdgeProcessor.h"
#include <vector>
#include <unordered_set>
namespace db
{

View File

@ -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;
}

View File

@ -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
*/

View File

@ -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"
) +

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -28,47 +28,51 @@ out = in.drc((width &lt; 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 &lt; 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 &gt; 3)
out = in.drc(primary.area_ratio &gt; 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 &gt; 3)
out = in.drc(primary.bbox_aspect_ratio &gt; 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 &gt; 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 &gt; 3)
out = in.drc(primary.relative_height &gt; 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>

View File

@ -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) &lt;= 0.2.um)
out = in.drc(enclosing(other) &gt; 0.2.um)
out = in.drc(enclosing(other) &gt;= 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 &lt;= enclosing(other) &lt; 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 &lt;= 0.2.um)
out = in.drc(width &gt; 0.2.um)
out = in.drc(width &gt;= 0.2.um)
out = in.drc(width == 0.2.um)
out = in.drc(width != 0.2.um)
out = in.drc(0.1.um &lt;= width &lt; 0.2.um)
</pre>
</p><p>

View File

@ -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 &lt; 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 &amp; other).area &gt; 1.0)
out = in.drc(width &lt;= 0.5.um)
out = in.drc(width &gt; 0.5.um)
out = in.drc(width == 0.5.um)
out = in.drc(width != 0.5.um)
out = in.drc(0.2.um &lt; width &lt; 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) &lt; 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) &lt; 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 &gt; 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 &lt;= 1.0)
out = in.drc(0.2 &lt; area &lt; 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 &gt; 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 &amp; l2).area &gt; 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 &amp; secondary(l2)).area &gt; 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) &amp; primary).area &gt; 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 &amp; l2).area == 1.0) + ((primary &amp; l2).area == 2.0))
</pre>
</p><p>
A more efficient version is:
</p><p>
<pre>
overlap_area = (primary &amp; 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 &lt; 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 &lt; 2.um". Available operators are: "==", "&lt;", "&lt;=", "&gt;" and "&gt;=".
Double-bounded ranges are also available, like: "0.5 &lt;= projecting &lt; 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>

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

30
testdata/drc/drcGenericTests_15.drc vendored Normal file
View File

@ -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)

BIN
testdata/drc/drcGenericTests_15.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcGenericTests_au15.gds vendored Normal file

Binary file not shown.

BIN
testdata/drc/drcGenericTests_au15d.gds vendored Normal file

Binary file not shown.