mirror of https://github.com/KLayout/klayout.git
Some refactoring (angle check), angle check and length check for universal DRC, tests, bug fixes.
This commit is contained in:
parent
158ea196ec
commit
0a7ca69da2
|
|
@ -207,4 +207,71 @@ EdgeSegmentSelector::process (const db::Edge &edge, std::vector<db::Edge> &res)
|
|||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
// EdgeAngleChecker implementation
|
||||
|
||||
EdgeAngleChecker::EdgeAngleChecker (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end)
|
||||
{
|
||||
m_t_start = db::CplxTrans(1.0, angle_start, false, db::DVector ());
|
||||
m_t_end = db::CplxTrans(1.0, angle_end, false, db::DVector ());
|
||||
|
||||
m_include_start = include_angle_start;
|
||||
m_include_end = include_angle_end;
|
||||
|
||||
m_big_angle = (angle_end - angle_start + db::epsilon) > 180.0;
|
||||
m_all = (angle_end - angle_start - db::epsilon) > 360.0;
|
||||
}
|
||||
|
||||
bool
|
||||
EdgeAngleChecker::check (const db::Vector &a, const db::Vector &b) const
|
||||
{
|
||||
db::DVector vout (b);
|
||||
|
||||
db::DVector v1 = m_t_start * a;
|
||||
db::DVector v2 = m_t_end * a;
|
||||
|
||||
int vps1 = db::vprod_sign (v1, vout);
|
||||
int vps2 = db::vprod_sign (v2, vout);
|
||||
bool opp1 = vps1 == 0 && (db::sprod_sign (v1, vout) < 0);
|
||||
bool opp2 = vps2 == 0 && (db::sprod_sign (v2, vout) < 0);
|
||||
|
||||
bool vp1 = !opp1 && (m_include_start ? (db::vprod_sign (v1, vout) >= 0) : (db::vprod_sign (v1, vout) > 0));
|
||||
bool vp2 = !opp2 && (m_include_end ? (db::vprod_sign (v2, vout) <= 0) : (db::vprod_sign (v2, vout) < 0));
|
||||
|
||||
if (m_big_angle && (vp1 || vp2)) {
|
||||
return true;
|
||||
} else if (! m_big_angle && vp1 && vp2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
// EdgeOrientationFilter implementation
|
||||
|
||||
EdgeOrientationFilter::EdgeOrientationFilter (double amin, bool include_amin, double amax, bool include_amax, bool inverse)
|
||||
: m_inverse (inverse), m_checker (amin, include_amin, amax, include_amax)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
EdgeOrientationFilter::EdgeOrientationFilter (double a, bool inverse)
|
||||
: m_inverse (inverse), m_checker (a, true, a, true)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
bool
|
||||
EdgeOrientationFilter::selected (const db::Edge &edge) const
|
||||
{
|
||||
// NOTE: this edge normalization confines the angle to a range between (-90 .. 90] (-90 excluded).
|
||||
// A horizontal edge has 0 degree, a vertical one has 90 degree.
|
||||
if (edge.dx () < 0 || (edge.dx () == 0 && edge.dy () < 0)) {
|
||||
return m_checker (db::Vector (edge.ortho_length (), 0), -edge.d ()) != m_inverse;
|
||||
} else {
|
||||
return m_checker (db::Vector (edge.ortho_length (), 0), edge.d ()) != m_inverse;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,6 +103,41 @@ private:
|
|||
db::MagnificationReducer m_vars;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An angle detector
|
||||
*
|
||||
* This detector can check whether the angle between two edges is within a certain angle interval.
|
||||
* It takes two edges: a and b. If b "turns left" (b following a), the angle will be positive, if it "turns" right,
|
||||
* the angle will be negative. The angle can be between -180 and 180 degree. The case of reflection
|
||||
* (exactly 180 degree) is not considered.
|
||||
*
|
||||
* The constraint can be given in terms of a minimum and maximum angle. "include" specifies whether the
|
||||
* angle value itself is included. The operator() will return true, if the angle between the given
|
||||
* edges a and b in matching the constraint.
|
||||
*/
|
||||
class DB_PUBLIC EdgeAngleChecker
|
||||
{
|
||||
public:
|
||||
EdgeAngleChecker (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end);
|
||||
|
||||
bool operator() (const db::Edge &a, const db::Edge &b) const
|
||||
{
|
||||
return m_all || check (a.d (), b.d ());
|
||||
}
|
||||
|
||||
bool operator() (const db::Vector &a, const db::Vector &b) const
|
||||
{
|
||||
return m_all || check (a, b);
|
||||
}
|
||||
|
||||
private:
|
||||
db::CplxTrans m_t_start, m_t_end;
|
||||
bool m_include_start, m_include_end;
|
||||
bool m_big_angle, m_all;
|
||||
|
||||
bool check (const db::Vector &a, const db::Vector &b) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An edge orientation filter for use with Edges::filter or Edges::filtered
|
||||
*
|
||||
|
|
@ -126,12 +161,7 @@ struct DB_PUBLIC EdgeOrientationFilter
|
|||
* This filter will filter out all edges whose angle against x axis
|
||||
* is larger or equal to amin and less than amax.
|
||||
*/
|
||||
EdgeOrientationFilter (double amin, double amax, bool inverse)
|
||||
: m_inverse (inverse), m_exact (false)
|
||||
{
|
||||
m_emin = db::DVector (cos (amin * M_PI / 180.0), sin (amin * M_PI / 180.0));
|
||||
m_emax = db::DVector (cos (amax * M_PI / 180.0), sin (amax * M_PI / 180.0));
|
||||
}
|
||||
EdgeOrientationFilter (double amin, bool include_amin, double amax, bool include_amax, bool inverse);
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
|
|
@ -142,33 +172,12 @@ struct DB_PUBLIC EdgeOrientationFilter
|
|||
* This filter will filter out all edges whose angle against x axis
|
||||
* is equal to a.
|
||||
*/
|
||||
EdgeOrientationFilter (double a, bool inverse)
|
||||
: m_inverse (inverse), m_exact (true)
|
||||
{
|
||||
m_emin = db::DVector (cos (a * M_PI / 180.0), sin (a * M_PI / 180.0));
|
||||
}
|
||||
EdgeOrientationFilter (double a, bool inverse);
|
||||
|
||||
/**
|
||||
* @brief Returns true if the edge orientation matches the criterion
|
||||
*/
|
||||
virtual bool selected (const db::Edge &edge) const
|
||||
{
|
||||
int smin = db::vprod_sign (m_emin, db::DVector (edge.d ()));
|
||||
if (m_exact) {
|
||||
if (! m_inverse) {
|
||||
return smin == 0;
|
||||
} else {
|
||||
return smin != 0;
|
||||
}
|
||||
} else {
|
||||
int smax = db::vprod_sign (m_emax, db::DVector (edge.d ()));
|
||||
if (! m_inverse) {
|
||||
return (smin >= 0 && smax < 0) || (smax > 0 && smin <= 0);
|
||||
} else {
|
||||
return ! ((smin >= 0 && smax < 0) || (smax > 0 && smin <= 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual bool selected (const db::Edge &edge) const;
|
||||
|
||||
/**
|
||||
* @brief This filter is not isotropic
|
||||
|
|
@ -197,8 +206,8 @@ struct DB_PUBLIC EdgeOrientationFilter
|
|||
private:
|
||||
db::DVector m_emin, m_emax;
|
||||
bool m_inverse;
|
||||
bool m_exact;
|
||||
db::MagnificationAndOrientationReducer m_vars;
|
||||
EdgeAngleChecker m_checker;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -31,15 +31,9 @@ namespace db
|
|||
// CornerDetectorCore implementation
|
||||
|
||||
CornerDetectorCore::CornerDetectorCore (double angle_start, bool include_angle_start, double angle_end, bool include_angle_end)
|
||||
: m_checker (angle_start, include_angle_start, angle_end, include_angle_end)
|
||||
{
|
||||
m_t_start = db::CplxTrans(1.0, angle_start, false, db::DVector ());
|
||||
m_t_end = db::CplxTrans(1.0, angle_end, false, db::DVector ());
|
||||
|
||||
m_include_start = include_angle_start;
|
||||
m_include_end = include_angle_end;
|
||||
|
||||
m_big_angle = (angle_end - angle_start + db::epsilon) > 180.0;
|
||||
m_all = (angle_end - angle_start - db::epsilon) > 360.0;
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void CornerDetectorCore::detect_corners (const db::Polygon &poly, const CornerPointDelivery &delivery) const
|
||||
|
|
@ -57,30 +51,8 @@ void CornerDetectorCore::detect_corners (const db::Polygon &poly, const CornerPo
|
|||
|
||||
db::Point pn = ctr [j];
|
||||
|
||||
if (m_all) {
|
||||
if (m_checker (pt - pp, pn - pt)) {
|
||||
delivery.make_point (pt);
|
||||
} else {
|
||||
|
||||
db::Vector vin (pt - pp);
|
||||
db::DVector vout (pn - pt);
|
||||
|
||||
db::DVector v1 = m_t_start * vin;
|
||||
db::DVector v2 = m_t_end * vin;
|
||||
|
||||
int vps1 = db::vprod_sign (v1, vout);
|
||||
int vps2 = db::vprod_sign (v2, vout);
|
||||
bool opp1 = vps1 == 0 && (db::sprod_sign (v1, vout) < 0);
|
||||
bool opp2 = vps2 == 0 && (db::sprod_sign (v2, vout) < 0);
|
||||
|
||||
bool vp1 = !opp1 && (m_include_start ? (db::vprod_sign (v1, vout) >= 0) : (db::vprod_sign (v1, vout) > 0));
|
||||
bool vp2 = !opp2 && (m_include_end ? (db::vprod_sign (v2, vout) <= 0) : (db::vprod_sign (v2, vout) < 0));
|
||||
|
||||
if (m_big_angle && (vp1 || vp2)) {
|
||||
delivery.make_point (pt);
|
||||
} else if (! m_big_angle && vp1 && vp2) {
|
||||
delivery.make_point (pt);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pp = pt;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "dbCommon.h"
|
||||
#include "dbRegionDelegate.h"
|
||||
#include "dbPolygonTools.h"
|
||||
#include "dbEdgesUtils.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
|
@ -97,9 +98,7 @@ public:
|
|||
void detect_corners (const db::Polygon &poly, const CornerPointDelivery &delivery) const;
|
||||
|
||||
private:
|
||||
db::CplxTrans m_t_start, m_t_end;
|
||||
bool m_include_start, m_include_end;
|
||||
bool m_big_angle, m_all;
|
||||
db::EdgeAngleChecker m_checker;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -326,10 +326,10 @@ 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_orientation_filter (db::CompoundRegionOperationNode *input, bool inverse, double amin, double amax)
|
||||
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");
|
||||
return new db::CompoundRegionEdgeFilterOperationNode (new db::EdgeOrientationFilter (amin, amax, inverse), input, true /*processor is owned*/);
|
||||
return new db::CompoundRegionEdgeFilterOperationNode (new db::EdgeOrientationFilter (amin, include_amin, amax, include_amax, inverse), input, true /*processor is owned*/);
|
||||
}
|
||||
|
||||
static db::CompoundRegionOperationNode *new_polygons (db::CompoundRegionOperationNode *input, db::Coord e)
|
||||
|
|
@ -675,7 +675,7 @@ 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_orientation_filter", &new_edge_orientation_filter, gsi::arg ("input"), gsi::arg ("inverse", false), gsi::arg ("amin"), gsi::arg ("amax"),
|
||||
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"
|
||||
) +
|
||||
gsi::constructor ("new_polygons", &new_polygons, gsi::arg ("input"), gsi::arg ("e", 0),
|
||||
|
|
|
|||
|
|
@ -206,9 +206,9 @@ static db::Edges with_angle1 (const db::Edges *r, double a, bool inverse)
|
|||
return r->filtered (f);
|
||||
}
|
||||
|
||||
static db::Edges with_angle2 (const db::Edges *r, double amin, double amax, bool inverse)
|
||||
static db::Edges with_angle2 (const db::Edges *r, double amin, double amax, bool inverse, bool include_amin, bool include_amax)
|
||||
{
|
||||
db::EdgeOrientationFilter f (amin, amax, inverse);
|
||||
db::EdgeOrientationFilter f (amin, include_amin, amax, include_amax, inverse);
|
||||
return r->filtered (f);
|
||||
}
|
||||
|
||||
|
|
@ -581,12 +581,17 @@ Class<db::Edges> decl_Edges (decl_dbShapeCollection, "db", "Edges",
|
|||
"horizontal = edges.with_orientation(0, true)\n"
|
||||
"@/code\n"
|
||||
) +
|
||||
method_ext ("with_angle", with_angle2, gsi::arg ("min_angle"), gsi::arg ("max_angle"), gsi::arg ("inverse"),
|
||||
method_ext ("with_angle", with_angle2, gsi::arg ("min_angle"), gsi::arg ("max_angle"), gsi::arg ("inverse"), gsi::arg ("include_amin", true), gsi::arg ("include_amax", true),
|
||||
"@brief Filter the edges by orientation\n"
|
||||
"Filters the edges in the edge collection by orientation. If \"inverse\" is false, only "
|
||||
"edges which have an angle to the x-axis larger or equal to \"min_angle\" and less than \"max_angle\" are "
|
||||
"returned. If \"inverse\" is true, "
|
||||
"edges which do not conform to this criterion are returned."
|
||||
"edges which do not conform to this criterion are returned.\n"
|
||||
"\n"
|
||||
"With \"include_min\" set to true (the default), the minimum angle is included in the criterion while with false, the "
|
||||
"minimum angle itself is not included. Same for \"include_max\".\n"
|
||||
"\n"
|
||||
"The two \"include..\" arguments have been added in version 0.27."
|
||||
) +
|
||||
method ("insert", (void (db::Edges::*)(const db::Edge &)) &db::Edges::insert, gsi::arg ("edge"),
|
||||
"@brief Inserts an edge\n"
|
||||
|
|
|
|||
|
|
@ -259,8 +259,8 @@ TEST(5_Filters)
|
|||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (2, 0)), r2);
|
||||
|
||||
db::EdgeOrientationFilter eof1 (0, 1, false);
|
||||
db::EdgeOrientationFilter eof2 (0, 1, true);
|
||||
db::EdgeOrientationFilter eof1 (0, true, 1, true, false);
|
||||
db::EdgeOrientationFilter eof2 (0, true, 1, true, true);
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), e2.filtered (eof1));
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), e2.filtered (eof2));
|
||||
|
|
|
|||
|
|
@ -200,23 +200,23 @@ TEST(4)
|
|||
EXPECT_EQ (r.filtered (f1).to_string (), "(0,200;100,200);(100,0;0,0);(300,0;200,0)");
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (50.0, 80.0, false);
|
||||
db::EdgeOrientationFilter f1 (50.0, true, 80.0, true, false);
|
||||
EXPECT_EQ (r.filtered (f1).to_string (), "(200,0;250,200);(250,-200;300,0)");
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (50.0, 80.0, true);
|
||||
db::EdgeOrientationFilter f1 (50.0, true, 80.0, true, true);
|
||||
EXPECT_EQ (r.filtered (f1).to_string (), "(0,0;0,200);(0,200;100,200);(100,200;100,0);(100,0;0,0);(250,200;300,0);(300,0;200,0);(200,0;250,-200)");
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (0.0, 1.0, false);
|
||||
db::EdgeOrientationFilter f1 (0.0, true, 1.0, true, false);
|
||||
EXPECT_EQ (r.filtered (f1).to_string (), "(0,200;100,200);(100,0;0,0);(300,0;200,0)");
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (-1.0, 1.0, false);
|
||||
db::EdgeOrientationFilter f1 (-1.0, true, 1.0, true, false);
|
||||
EXPECT_EQ (r.filtered (f1).to_string (), "(0,200;100,200);(100,0;0,0);(300,0;200,0)");
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (-1.0, 0.0, false);
|
||||
db::EdgeOrientationFilter f1 (-1.0, true, 0.0, true, false);
|
||||
EXPECT_EQ (r.filtered (f1).to_string (), "");
|
||||
}
|
||||
{
|
||||
|
|
@ -224,15 +224,15 @@ TEST(4)
|
|||
EXPECT_EQ (r.filtered (f1).to_string (), "(0,0;0,200);(100,200;100,0)");
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (90.0, 91.0, false);
|
||||
db::EdgeOrientationFilter f1 (90.0, true, 91.0, true, false);
|
||||
EXPECT_EQ (r.filtered (f1).to_string (), "(0,0;0,200);(100,200;100,0)");
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (89.0, 91.0, false);
|
||||
db::EdgeOrientationFilter f1 (89.0, true, 91.0, true, false);
|
||||
EXPECT_EQ (r.filtered (f1).to_string (), "(0,0;0,200);(100,200;100,0)");
|
||||
}
|
||||
{
|
||||
db::EdgeOrientationFilter f1 (89.0, 90.0, false);
|
||||
db::EdgeOrientationFilter f1 (89.0, true, 90.0, true, false);
|
||||
EXPECT_EQ (r.filtered (f1).to_string (), "");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1324,7 +1324,9 @@ class DRCOpNodeEdgeOrientationFilter < DRCOpNodeWithCompare
|
|||
args = [ n, self.inverse ]
|
||||
angle_delta = 1e-6
|
||||
args << (self.gt ? self.gt + angle_delta : (self.ge ? self.ge : -180.0))
|
||||
args << (self.gt ? false : true)
|
||||
args << (self.lt ? self.lt : (self.le ? self.le + angle_delta : 180.0))
|
||||
args << (self.lt ? false : true)
|
||||
|
||||
RBA::CompoundRegionOperationNode::new_edge_orientation_filter(*args)
|
||||
|
||||
|
|
|
|||
|
|
@ -334,13 +334,15 @@ CODE
|
|||
|
||||
# %DRC%
|
||||
# @name area
|
||||
# @brief Selects the primary shape if the area is meeting the condition
|
||||
# @brief Computes the total area or in universal DRC context: selects the primary shape if the area is meeting the condition
|
||||
# @synopsis area (in condition)
|
||||
# @synopsis area(layer)
|
||||
#
|
||||
# This function can be used with a layer argument in which case it
|
||||
# is equivalent to "layer.area" (see \Layer#area). Without a layer
|
||||
# argument, "area" represents an area filter for primary shapes in
|
||||
# is equivalent to "layer.area" (see \Layer#area) and returns the total area of the
|
||||
# polygons in the layer.
|
||||
#
|
||||
# Without a layer argument, "area" represents an area filter for primary shapes in
|
||||
# \DRC# expressions (see \Layer#drc and \DRC#area for more details).
|
||||
|
||||
# %DRC%
|
||||
|
|
@ -378,13 +380,15 @@ CODE
|
|||
|
||||
# %DRC%
|
||||
# @name perimeter
|
||||
# @brief Selects the primary shape if the perimeter is meeting the condition
|
||||
# @brief Computes the total perimeter or in universal DRC context: selects the primary shape if the perimeter is meeting the condition
|
||||
# @synopsis perimeter (in condition)
|
||||
# @synopsis perimeter(layer)
|
||||
#
|
||||
# This function can be used with a layer argument in which case it
|
||||
# is equivalent to "layer.perimeter" (see \Layer#perimeter). Without a layer
|
||||
# argument, "perimeter" represents a perimeter filter for primary shapes in
|
||||
# is equivalent to "layer.perimeter" (see \Layer#perimeter) and returns the
|
||||
# total perimeter of all polygons in the layer.
|
||||
#
|
||||
# Without a layer argument, "perimeter" represents a perimeter filter for primary shapes in
|
||||
# \DRC# expressions (see \Layer#drc and \DRC#perimeter for more details).
|
||||
|
||||
# %DRC%
|
||||
|
|
@ -409,6 +413,27 @@ CODE
|
|||
# argument, "rectilinear" represents the rectilinear polygons filter for primary shapes in
|
||||
# \DRC# expressions (see \Layer#drc and \DRC#rectilinear for more details).
|
||||
|
||||
# %DRC%
|
||||
# @name length (in condition)
|
||||
# @brief Computes the total edge length of an edge layer or in universal DRC context: selects edges based on a length condition
|
||||
# @synopsis length (in condition)
|
||||
# @synopsis length(layer)
|
||||
#
|
||||
# This function can be used with a layer argument in which case it
|
||||
# is equivalent to "layer.length" (see \Layer#length). Without a layer
|
||||
# argument, "length" represents the edge length filter on the primary shape edges in
|
||||
# \DRC# expressions (see \Layer#drc and \DRC#length for more details). In this context,
|
||||
# the operation acts similar to \Layer#with_length.
|
||||
|
||||
# %DRC%
|
||||
# @name angle (in condition)
|
||||
# @brief In universal DRC context: selects edges based on their orientation
|
||||
# @synopsis angle (in condition)
|
||||
#
|
||||
# "angle" represents the edge orientation filter on the primary shape edges in
|
||||
# \DRC# expressions (see \Layer#drc and \DRC#angle for more details). In this context,
|
||||
# the operation acts similar to \Layer#with_angle.
|
||||
|
||||
%w(
|
||||
area
|
||||
holes
|
||||
|
|
@ -417,6 +442,8 @@ CODE
|
|||
perimeter
|
||||
rectangles
|
||||
rectilinear
|
||||
length
|
||||
angle
|
||||
).each do |f|
|
||||
# NOTE: these methods are fallback for the respective global ones which route to DRCLayer or here.
|
||||
eval <<"CODE"
|
||||
|
|
|
|||
|
|
@ -1574,6 +1574,7 @@ CODE
|
|||
%w(
|
||||
and
|
||||
andnot
|
||||
angle
|
||||
area
|
||||
bbox
|
||||
centers
|
||||
|
|
|
|||
|
|
@ -2780,7 +2780,7 @@ CODE
|
|||
@engine._cmd(self.data, :length) * @engine.dbu.to_f
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# %DRC%
|
||||
# @name flatten
|
||||
# @brief Flattens the layer
|
||||
|
|
|
|||
|
|
@ -178,3 +178,13 @@ TEST(11d)
|
|||
{
|
||||
run_test (_this, "11", true);
|
||||
}
|
||||
|
||||
TEST(12)
|
||||
{
|
||||
run_test (_this, "12", false);
|
||||
}
|
||||
|
||||
TEST(12d)
|
||||
{
|
||||
run_test (_this, "12", true);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue