mirror of https://github.com/KLayout/klayout.git
Merge pull request #847 from KLayout/more-edge-pair-filters
More edge pair filters
This commit is contained in:
commit
fb9c0077eb
|
|
@ -78,4 +78,51 @@ bool EdgePairFilterByDistance::selected (const db::EdgePair &edge_pair) const
|
|||
return m_inverted ? !sel : sel;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------
|
||||
// EdgePairFilterByArea implementation
|
||||
|
||||
EdgePairFilterByArea::EdgePairFilterByArea (area_type min_area, area_type max_area, bool inverted)
|
||||
: m_min_area (min_area), m_max_area (max_area), m_inverted (inverted)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
bool EdgePairFilterByArea::selected (const db::EdgePair &edge_pair) const
|
||||
{
|
||||
area_type dist = edge_pair.to_simple_polygon (0).area ();
|
||||
bool sel = (dist >= m_min_area && dist < m_max_area);
|
||||
return m_inverted ? !sel : sel;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------
|
||||
// EdgePairFilterByArea implementation
|
||||
|
||||
InternalAngleEdgePairFilter::InternalAngleEdgePairFilter (double a, bool inverted)
|
||||
: m_inverted (inverted), m_checker (a, true, a, true)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
InternalAngleEdgePairFilter::InternalAngleEdgePairFilter (double amin, bool include_amin, double amax, bool include_amax, bool inverted)
|
||||
: m_inverted (inverted), m_checker (amin, include_amin, amax, include_amax)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
bool
|
||||
InternalAngleEdgePairFilter::selected (const db::EdgePair &edge_pair) const
|
||||
{
|
||||
db::Vector d1 = edge_pair.first ().d ();
|
||||
db::Vector d2 = edge_pair.second ().d ();
|
||||
|
||||
if (db::sprod_sign (d1, d2) < 0) {
|
||||
d1 = -d1;
|
||||
}
|
||||
if (db::vprod_sign (d1, d2) < 0) {
|
||||
std::swap (d1, d2);
|
||||
}
|
||||
|
||||
return m_checker (d1, d2) != m_inverted;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#define HDR_dbEdgePairFilters
|
||||
|
||||
#include "dbEdgePairs.h"
|
||||
#include "dbEdgesUtils.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
|
@ -69,12 +70,57 @@ public:
|
|||
EdgePairFilterByDistance (distance_type min_distance, distance_type max_distance, bool inverted);
|
||||
|
||||
virtual bool selected (const db::EdgePair &edge_pair) const;
|
||||
virtual const TransformationReducer *vars () const { return 0; }
|
||||
virtual bool wants_variants () const { return false; }
|
||||
virtual const TransformationReducer *vars () const { return &m_vars; }
|
||||
virtual bool wants_variants () const { return true; }
|
||||
|
||||
private:
|
||||
distance_type m_min_distance, m_max_distance;
|
||||
bool m_inverted;
|
||||
db::MagnificationReducer m_vars;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Filters edge pairs based on the distance of the edges.
|
||||
*
|
||||
* The distance is measured as the smallest distance between each of the points of the two edges.
|
||||
*/
|
||||
class DB_PUBLIC EdgePairFilterByArea
|
||||
: public EdgePairFilterBase
|
||||
{
|
||||
public:
|
||||
typedef db::coord_traits<db::Coord>::area_type area_type;
|
||||
|
||||
EdgePairFilterByArea (area_type min_area, area_type max_area, bool inverted);
|
||||
|
||||
virtual bool selected (const db::EdgePair &edge_pair) const;
|
||||
virtual const TransformationReducer *vars () const { return &m_vars; }
|
||||
virtual bool wants_variants () const { return true; }
|
||||
|
||||
private:
|
||||
area_type m_min_area, m_max_area;
|
||||
bool m_inverted;
|
||||
db::MagnificationReducer m_vars;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Filters edge pairs based on the distance of the edges.
|
||||
*
|
||||
* The distance is measured as the smallest distance between each of the points of the two edges.
|
||||
*/
|
||||
class DB_PUBLIC InternalAngleEdgePairFilter
|
||||
: public EdgePairFilterBase
|
||||
{
|
||||
public:
|
||||
InternalAngleEdgePairFilter (double a, bool inverted);
|
||||
InternalAngleEdgePairFilter (double amin, bool include_amin, double amax, bool include_amax, bool inverted);
|
||||
|
||||
virtual bool selected (const db::EdgePair &edge_pair) const;
|
||||
virtual const TransformationReducer *vars () const { return 0; }
|
||||
virtual bool wants_variants () const { return false; }
|
||||
|
||||
private:
|
||||
bool m_inverted;
|
||||
db::EdgeAngleChecker m_checker;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -236,7 +236,6 @@ struct DB_PUBLIC EdgeOrientationFilter
|
|||
}
|
||||
|
||||
private:
|
||||
db::DVector m_emin, m_emax;
|
||||
bool m_inverse;
|
||||
db::MagnificationAndOrientationReducer m_vars;
|
||||
EdgeAngleChecker m_checker;
|
||||
|
|
|
|||
|
|
@ -246,6 +246,30 @@ static db::EdgePairs with_angle_both2 (const db::EdgePairs *r, double amin, doub
|
|||
return r->filtered (ef);
|
||||
}
|
||||
|
||||
static db::EdgePairs with_internal_angle1 (const db::EdgePairs *r, double a, bool inverse)
|
||||
{
|
||||
db::InternalAngleEdgePairFilter f (a, inverse);
|
||||
return r->filtered (f);
|
||||
}
|
||||
|
||||
static db::EdgePairs with_internal_angle2 (const db::EdgePairs *r, double amin, double amax, bool inverse, bool include_amin, bool include_amax)
|
||||
{
|
||||
db::InternalAngleEdgePairFilter f (amin, include_amin, amax, include_amax, inverse);
|
||||
return r->filtered (f);
|
||||
}
|
||||
|
||||
static db::EdgePairs with_area1 (const db::EdgePairs *r, db::EdgePair::area_type a, bool inverse)
|
||||
{
|
||||
db::EdgePairFilterByArea f (a, a + 1, inverse);
|
||||
return r->filtered (f);
|
||||
}
|
||||
|
||||
static db::EdgePairs with_area2 (const db::EdgePairs *r, db::EdgePair::area_type amin, db::EdgePair::area_type amax, bool inverse)
|
||||
{
|
||||
db::EdgePairFilterByArea f (amin, amax, inverse);
|
||||
return r->filtered (f);
|
||||
}
|
||||
|
||||
extern Class<db::ShapeCollection> decl_dbShapeCollection;
|
||||
|
||||
Class<db::EdgePairs> decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs",
|
||||
|
|
@ -621,7 +645,7 @@ Class<db::EdgePairs> decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs",
|
|||
method_ext ("with_distance", with_distance2, gsi::arg ("min_distance"), gsi::arg ("max_distance"), gsi::arg ("inverse"),
|
||||
"@brief Filters the edge pairs by the distance of the edges\n"
|
||||
"Filters the edge pairs in the edge pair collection by distance of the edges. If \"inverse\" is false, only "
|
||||
"edge pairs where both edges have a distance between min_distance and max_distance (max_distance itself is excluded). If \"inverse\" is true, "
|
||||
"edge pairs where both edges have a distance between min_distance and max_distance (max_distance itself is excluded) are returned. If \"inverse\" is true, "
|
||||
"edge pairs not fulfilling this criterion are returned.\n"
|
||||
"\n"
|
||||
"Distance is measured as the shortest distance between any of the points on the edges.\n"
|
||||
|
|
@ -678,6 +702,45 @@ Class<db::EdgePairs> decl_EdgePairs (decl_dbShapeCollection, "db", "EdgePairs",
|
|||
"\n"
|
||||
"This method has been added in version 0.27.1.\n"
|
||||
) +
|
||||
method_ext ("with_area", with_area1, gsi::arg ("area"), gsi::arg ("inverse"),
|
||||
"@brief Filters the edge pairs by the enclosed area\n"
|
||||
"Filters the edge pairs in the edge pair collection by enclosed area. If \"inverse\" is false, only "
|
||||
"edge pairs with the given area are returned. If \"inverse\" is true, "
|
||||
"edge pairs not with the given area are returned.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.27.2.\n"
|
||||
) +
|
||||
method_ext ("with_area", with_area2, gsi::arg ("min_area"), gsi::arg ("max_area"), gsi::arg ("inverse"),
|
||||
"@brief Filters the edge pairs by the enclosed area\n"
|
||||
"Filters the edge pairs in the edge pair collection by enclosed area. If \"inverse\" is false, only "
|
||||
"edge pairs with an area between min_area and max_area (max_area itself is excluded) are returned. If \"inverse\" is true, "
|
||||
"edge pairs not fulfilling this criterion are returned.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.27.2.\n"
|
||||
) +
|
||||
method_ext ("with_internal_angle", with_internal_angle1, gsi::arg ("angle"), gsi::arg ("inverse"),
|
||||
"@brief Filters the edge pairs by the angle between their edges\n"
|
||||
"Filters the edge pairs in the edge pair collection by the angle between their edges. If \"inverse\" is false, only "
|
||||
"edge pairs with the given angle are returned. If \"inverse\" is true, "
|
||||
"edge pairs not with the given angle are returned.\n"
|
||||
"\n"
|
||||
"The angle is measured between the two edges. It is between 0 (parallel or anti-parallel edges) and 90 degree (perpendicular edges).\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.27.2.\n"
|
||||
) +
|
||||
method_ext ("with_internal_angle", with_internal_angle2, gsi::arg ("min_angle"), gsi::arg ("max_angle"), gsi::arg ("inverse"), gsi::arg ("include_min_angle", true), gsi::arg ("include_max_angle", false),
|
||||
"@brief Filters the edge pairs by the angle between their edges\n"
|
||||
"Filters the edge pairs in the edge pair collection by the angle between their edges. If \"inverse\" is false, only "
|
||||
"edge pairs with an angle between min_angle and max_angle (max_angle itself is excluded) are returned. If \"inverse\" is true, "
|
||||
"edge pairs not fulfilling this criterion are returned.\n"
|
||||
"\n"
|
||||
"The angle is measured between the two edges. It is between 0 (parallel or anti-parallel edges) and 90 degree (perpendicular edges).\n"
|
||||
"\n"
|
||||
"With \"include_min_angle\" set to true (the default), the minimum angle is included in the criterion while with false, the "
|
||||
"minimum angle itself is not included. Same for \"include_max_angle\" where the default is false, meaning the maximum angle is not included in the range.\n"
|
||||
"\n"
|
||||
"This method has been added in version 0.27.2.\n"
|
||||
) +
|
||||
method_ext ("polygons", &polygons1,
|
||||
"@brief Converts the edge pairs to polygons\n"
|
||||
"This method creates polygons from the edge pairs. Each polygon will be a triangle or quadrangle "
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "tlUnitTest.h"
|
||||
|
||||
#include "dbEdgePairs.h"
|
||||
#include "dbEdgePairFilters.h"
|
||||
#include "dbEdges.h"
|
||||
#include "dbRegion.h"
|
||||
#include "dbTestSupport.h"
|
||||
|
|
@ -160,3 +161,42 @@ TEST(4)
|
|||
db::Region r (db::RecursiveShapeIterator (ly, ly.cell (top_cell), l1));
|
||||
EXPECT_EQ (db::compare (r, "(-10,-21;9,20;50,51;91,80);(-10,-21;9,20;110,121;91,80)"), true);
|
||||
}
|
||||
|
||||
TEST(5_InternalAngleFilter)
|
||||
{
|
||||
db::EdgePair ep0 (db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (100, 0), db::Point (0, 0)));
|
||||
db::EdgePair ep45 (db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 0), db::Point (100, 100)));
|
||||
db::EdgePair ep180 (db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 0), db::Point (100, 0)));
|
||||
db::EdgePair ep90 (db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 0), db::Point (0, 100)));
|
||||
db::EdgePair epm90 (db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 100), db::Point (0, 0)));
|
||||
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, false).selected (ep0), true);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, false).selected (ep180), true);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, false).selected (ep90), false);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, false).selected (epm90), false);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, false).selected (ep45), false);
|
||||
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (90.0, false).selected (ep0), false);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (90.0, false).selected (ep180), false);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (90.0, false).selected (ep90), true);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (90.0, false).selected (epm90), true);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (90.0, false).selected (ep45), false);
|
||||
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (45.0, false).selected (ep0), false);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (45.0, false).selected (ep180), false);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (45.0, false).selected (ep90), false);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (45.0, false).selected (epm90), false);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (45.0, false).selected (ep45), true);
|
||||
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true).selected (ep0), false);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true).selected (ep180), false);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true).selected (ep90), true);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true).selected (epm90), true);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true).selected (ep45), true);
|
||||
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, false).selected (ep0), true);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, false).selected (ep180), true);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, false).selected (ep90), false);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, false).selected (epm90), false);
|
||||
EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, false).selected (ep45), true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -330,28 +330,30 @@ module DRC
|
|||
|
||||
# %DRC%
|
||||
# @name with_area
|
||||
# @brief Selects polygons by area
|
||||
# @brief Selects polygons or edge pairs by area
|
||||
# @synopsis layer.with_area(min .. max)
|
||||
# @synopsis layer.with_area(value)
|
||||
# @synopsis layer.with_area(min, max)
|
||||
# The first form will select all polygons with an area larger or
|
||||
# The first form will select all polygons or edge pairs with an area larger or
|
||||
# equal to min and less (but not equal to) max. The second form
|
||||
# will select the polygons with exactly the given area.
|
||||
# will select the polygons or edge pairs with exactly the given area.
|
||||
# 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.
|
||||
#
|
||||
# This method is available for polygon or edge pair layers.
|
||||
|
||||
# %DRC%
|
||||
# @name without_area
|
||||
# @brief Selects polygons by area
|
||||
# @brief Selects polygons or edge pairs by area
|
||||
# @synopsis layer.without_area(min .. max)
|
||||
# @synopsis layer.without_area(value)
|
||||
# @synopsis layer.without_area(min, max)
|
||||
# This method is the inverse of "with_area". It will select
|
||||
# polygons without an area equal to the given one or outside
|
||||
# polygons or edge pairs without an area equal to the given one or outside
|
||||
# the given interval.
|
||||
#
|
||||
# This method is available for polygon layers only.
|
||||
# This method is available for polygon or edge pair layers.
|
||||
|
||||
%w(area).each do |f|
|
||||
[true, false].each do |inv|
|
||||
|
|
@ -361,7 +363,8 @@ module DRC
|
|||
|
||||
@engine._context("#{mn}") do
|
||||
|
||||
requires_region
|
||||
self.data.is_a?(RBA::Region) || self.data.is_a?(RBA::EdgePairs) || raise("Requires an edge pair or polygon layer")
|
||||
|
||||
if args.size == 1
|
||||
a = args[0]
|
||||
if a.is_a?(Range)
|
||||
|
|
@ -857,7 +860,7 @@ CODE
|
|||
# @synopsis layer.with_angle(min .. max)
|
||||
# @synopsis layer.with_angle(value)
|
||||
# @synopsis layer.with_angle(min, max)
|
||||
# @synopsis edge_pairlayer.with_angle(min, max [, both])
|
||||
# @synopsis edge_pair_layer.with_angle(min, max [, both])
|
||||
#
|
||||
# When called on an edge layer, the method selects edges by their angle,
|
||||
# measured against the horizontal axis in the mathematical sense.
|
||||
|
|
@ -871,10 +874,6 @@ CODE
|
|||
# The second version selects edges with exactly the given angle. The third
|
||||
# version is identical to the first one.
|
||||
#
|
||||
# When called on a polygon layer, this method selects corners which match the
|
||||
# given angle or is within the given angle interval. The angle is measured between the edges forming the corner.
|
||||
# For each corner, an edge pair containing the edges forming in the angle is returned.
|
||||
#
|
||||
# When called on an edge pair layer, this method selects edge pairs with one or both edges
|
||||
# meeting the angle criterion. In this case an additional argument is accepted which can be
|
||||
# either "both" (plain word) to indicate that both edges have to be within the given interval.
|
||||
|
|
@ -903,6 +902,9 @@ CODE
|
|||
# @td @img(/images/drc_with_angle4.png) @/td
|
||||
# @/tr
|
||||
# @/table
|
||||
#
|
||||
# Note that in former versions, with_angle could be used on polygon layers selecting corners with specific angles.
|
||||
# This feature has been deprecated. Use \corners instead.
|
||||
|
||||
# %DRC%
|
||||
# @name without_angle
|
||||
|
|
@ -910,11 +912,12 @@ CODE
|
|||
# @synopsis layer.without_angle(min .. max)
|
||||
# @synopsis layer.without_angle(value)
|
||||
# @synopsis layer.without_angle(min, max)
|
||||
# @synopsis edge_pairlayer.without_angle(min, max [, both])
|
||||
# @synopsis edge_pair_layer.without_angle(min, max [, both])
|
||||
#
|
||||
# The method basically is the inverse of \with_angle. It selects all edges
|
||||
# of the edge layer or corners of the polygons which do not have the given angle (second form) or whose angle
|
||||
# is not inside the given interval (first and third form).
|
||||
# is not inside the given interval (first and third form). When called on edge pairs, it selects
|
||||
# edge pairs by the angles of their edges.
|
||||
#
|
||||
# A note on the "both" modifier (without_angle called on edge pairs): "both" means that
|
||||
# both edges need to be "without_angle". For example
|
||||
|
|
@ -925,8 +928,41 @@ CODE
|
|||
# ep = edge_pairs.without_angle(0, both)
|
||||
# @/code
|
||||
#
|
||||
# See \with_internal_angle and \without_internal_angle to select edge pairs by the
|
||||
# angle between the edges.
|
||||
|
||||
%w(angle).each do |f|
|
||||
# %DRC%
|
||||
# @name with_internal_angle
|
||||
# @brief Selects edge pairs by their internal angle
|
||||
# @synopsis edge_pair_layer.with_internal_angle(min .. max)
|
||||
# @synopsis edge_pair_layer.with_internal_angle(value)
|
||||
# @synopsis edge_pair_layer.with_internal_angle(min, max)
|
||||
#
|
||||
# This method selects edge pairs by the angle enclosed by their edges.
|
||||
# The angle is between 0 (parallel or anti-parallel edges) and 90 degree (perpendicular edges).
|
||||
# If an interval or two values are given, the angle is checked to be within the given
|
||||
# range.
|
||||
#
|
||||
# Here are examples for "with_internal_angle" on edge pair layers:
|
||||
#
|
||||
# @code
|
||||
# # selects edge pairs with parallel edges
|
||||
# ep1 = edge_pairs.with_internal_angle(0)
|
||||
# # selects edge pairs with perpendicular edges
|
||||
# ep2 = edge_pairs.with_internal_angle(90)
|
||||
# @/code
|
||||
|
||||
# %DRC%
|
||||
# @name without_internal_angle
|
||||
# @brief Selects edge pairs by their internal angle
|
||||
# @synopsis edge_pair_layer.without_internal_angle(min .. max)
|
||||
# @synopsis edge_pair_layer.without_internal_angle(value)
|
||||
# @synopsis edge_pair_layer.without_internal_angle(min, max)
|
||||
#
|
||||
# The method basically is the inverse of \with_internal_angle. It selects all
|
||||
# edge pairs by the angle enclosed by their edges, applying the opposite criterion than \with_internal_angle.
|
||||
|
||||
%w(angle internal_angle).each do |f|
|
||||
[true, false].each do |inv|
|
||||
mn = (inv ? "without" : "with") + "_" + f
|
||||
eval <<"CODE"
|
||||
|
|
@ -935,16 +971,22 @@ CODE
|
|||
@engine._context("#{mn}") do
|
||||
|
||||
f = :with_#{f}
|
||||
args = args.select do |a|
|
||||
if a.is_a?(DRCBothEdges)
|
||||
if !self.data.is_a?(RBA::EdgePairs)
|
||||
raise("'both' keyword only available for edge pair layers")
|
||||
|
||||
if "#{f}" == "angle"
|
||||
self.data.is_a?(RBA::Region) || self.data.is_a?(RBA::Edges) || self.data.is_a?(RBA::EdgePairs) || raise("Requires an edge, edge pair or polygon layer")
|
||||
args = args.select do |a|
|
||||
if a.is_a?(DRCBothEdges)
|
||||
if !self.data.is_a?(RBA::EdgePairs)
|
||||
raise("'both' keyword only available for edge pair layers")
|
||||
end
|
||||
f = :with_#{f}_both
|
||||
false
|
||||
else
|
||||
true
|
||||
end
|
||||
f = :with_#{f}_both
|
||||
false
|
||||
else
|
||||
true
|
||||
end
|
||||
else
|
||||
requires_edge_pairs
|
||||
end
|
||||
|
||||
result_class = self.data.is_a?(RBA::Edges) ? RBA::Edges : RBA::EdgePairs
|
||||
|
|
|
|||
|
|
@ -1283,12 +1283,12 @@ TEST(48d_drcWithFragments)
|
|||
run_test (_this, "48", true);
|
||||
}
|
||||
|
||||
TEST(49_drcWithFragments)
|
||||
TEST(49_epAngle)
|
||||
{
|
||||
run_test (_this, "49", false);
|
||||
}
|
||||
|
||||
TEST(49d_drcWithFragments)
|
||||
TEST(49d_epAngle)
|
||||
{
|
||||
run_test (_this, "49", true);
|
||||
}
|
||||
|
|
@ -1298,3 +1298,8 @@ TEST(50_issue826)
|
|||
run_test (_this, "50", false);
|
||||
}
|
||||
|
||||
TEST(51_epInternalAngle)
|
||||
{
|
||||
run_test (_this, "51", false);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3157,7 +3157,7 @@ Shielding is enabled by default, but can be switched off with the "transparent"
|
|||
<li><tt>layer.with_angle(min .. max)</tt></li>
|
||||
<li><tt>layer.with_angle(value)</tt></li>
|
||||
<li><tt>layer.with_angle(min, max)</tt></li>
|
||||
<li><tt>edge_pairlayer.with_angle(min, max [, both])</tt></li>
|
||||
<li><tt>edge_pair_layer.with_angle(min, max [, both])</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
When called on an edge layer, the method selects edges by their angle,
|
||||
|
|
@ -3172,10 +3172,6 @@ edges with a angle larger or equal to min and less than max (but not equal).
|
|||
The second version selects edges with exactly the given angle. The third
|
||||
version is identical to the first one.
|
||||
</p><p>
|
||||
When called on a polygon layer, this method selects corners which match the
|
||||
given angle or is within the given angle interval. The angle is measured between the edges forming the corner.
|
||||
For each corner, an edge pair containing the edges forming in the angle is returned.
|
||||
</p><p>
|
||||
When called on an edge pair layer, this method selects edge pairs with one or both edges
|
||||
meeting the angle criterion. In this case an additional argument is accepted which can be
|
||||
either "both" (plain word) to indicate that both edges have to be within the given interval.
|
||||
|
|
@ -3204,8 +3200,11 @@ The following images demonstrate some use cases of <a href="#with_angle">with_an
|
|||
<td><img src="/images/drc_with_angle4.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</p><p>
|
||||
Note that in former versions, with_angle could be used on polygon layers selecting corners with specific angles.
|
||||
This feature has been deprecated. Use <a href="#corners">corners</a> instead.
|
||||
</p>
|
||||
<a name="with_area"/><h2>"with_area" - Selects polygons by area</h2>
|
||||
<a name="with_area"/><h2>"with_area" - Selects polygons or edge pairs by area</h2>
|
||||
<keyword name="with_area"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
|
|
@ -3214,12 +3213,14 @@ The following images demonstrate some use cases of <a href="#with_angle">with_an
|
|||
<li><tt>layer.with_area(min, max)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
The first form will select all polygons with an area larger or
|
||||
The first form will select all polygons or edge pairs with an area larger or
|
||||
equal to min and less (but not equal to) max. The second form
|
||||
will select the polygons with exactly the given area.
|
||||
will select the polygons or edge pairs with exactly the given area.
|
||||
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><p>
|
||||
This method is available for polygon or edge pair layers.
|
||||
</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"/>
|
||||
|
|
@ -3334,7 +3335,7 @@ The tile size must be specified with the "tile_size" option:
|
|||
</p><p>
|
||||
<pre>
|
||||
# reports areas where layer 1/0 density is below 10% on 20x20 um tiles
|
||||
low_density = input(1, 0).density(0.0 .. 0.1, tile_size(20.um))
|
||||
low_density = input(1, 0).with_density(0.0 .. 0.1, tile_size(20.um))
|
||||
</pre>
|
||||
</p><p>
|
||||
Anisotropic tiles can be specified by giving two values, like "tile_size(10.um, 20.um)".
|
||||
|
|
@ -3348,7 +3349,7 @@ in increments of the tile step:
|
|||
<pre>
|
||||
# reports areas where layer 1/0 density is below 10% on 30x30 um tiles
|
||||
# with a tile step of 20x20 um:
|
||||
low_density = input(1, 0).density(0.0 .. 0.1, tile_size(30.um), tile_step(20.um))
|
||||
low_density = input(1, 0).with_density(0.0 .. 0.1, tile_size(30.um), tile_step(20.um))
|
||||
</pre>
|
||||
</p><p>
|
||||
For "tile_step", anisotropic values can be given as well by using two values: the first for the
|
||||
|
|
@ -3366,7 +3367,7 @@ drawn boundary layer. To specify a separate, additional layer included in the bo
|
|||
# reports density of layer 1/0 below 10% on 20x20 um tiles. The layout's boundary is taken from
|
||||
# layer 0/0:
|
||||
cell_frame = input(0, 0)
|
||||
low_density = input(1, 0).density(0.0 .. 0.1, tile_size(20.um), tile_boundary(cell_frame))
|
||||
low_density = input(1, 0).with_density(0.0 .. 0.1, tile_size(20.um), tile_boundary(cell_frame))
|
||||
</pre>
|
||||
</p><p>
|
||||
Note that the layer given in "tile_boundary" adds to the input layer for computing the bounding box.
|
||||
|
|
@ -3378,7 +3379,7 @@ direction. With the "tile_origin" option this allows full control over the area
|
|||
<pre>
|
||||
# reports density of layer 1/0 below 10% on 20x20 um tiles in the region 0,0 .. 2000,3000
|
||||
# (100 and 150 tiles of 20 um each are used in horizontal and vertical direction):
|
||||
low_density = input(1, 0).density(0.0 .. 0.1, tile_size(20.um), tile_origin(0.0, 0.0), tile_count(100, 150))
|
||||
low_density = input(1, 0).with_density(0.0 .. 0.1, tile_size(20.um), tile_origin(0.0, 0.0), tile_count(100, 150))
|
||||
</pre>
|
||||
</p><p>
|
||||
The "padding mode" indicates how the area outside the layout's bounding box is considered.
|
||||
|
|
@ -3392,7 +3393,7 @@ There are two modes:
|
|||
Example:
|
||||
</p><p>
|
||||
<pre>
|
||||
low_density = input(1, 0).density(0.0 .. 0.1, tile_size(20.um), padding_ignore)
|
||||
low_density = input(1, 0).with_density(0.0 .. 0.1, tile_size(20.um), padding_ignore)
|
||||
</pre>
|
||||
</p><p>
|
||||
The complementary version of "with_density" is <a href="#without_density">without_density</a>.
|
||||
|
|
@ -3430,6 +3431,29 @@ This method is available for edge pair layers only.
|
|||
This method is available for polygon layers. It will select all polygons from the input layer
|
||||
which have the specified number of holes.
|
||||
</p>
|
||||
<a name="with_internal_angle"/><h2>"with_internal_angle" - Selects edge pairs by their internal angle</h2>
|
||||
<keyword name="with_internal_angle"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>edge_pair_layer.with_internal_angle(min .. max)</tt></li>
|
||||
<li><tt>edge_pair_layer.with_internal_angle(value)</tt></li>
|
||||
<li><tt>edge_pair_layer.with_internal_angle(min, max)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
This method selects edge pairs by the angle enclosed by their edges.
|
||||
The angle is between 0 (parallel or anti-parallel edges) and 90 degree (perpendicular edges).
|
||||
If an interval or two values are given, the angle is checked to be within the given
|
||||
range.
|
||||
</p><p>
|
||||
Here are examples for "with_internal_angle" on edge pair layers:
|
||||
</p><p>
|
||||
<pre>
|
||||
# selects edge pairs with parallel edges
|
||||
ep1 = edge_pairs.with_internal_angle(0)
|
||||
# selects edge pairs with perpendicular edges
|
||||
ep2 = edge_pairs.with_internal_angle(90)
|
||||
</pre>
|
||||
</p>
|
||||
<a name="with_length"/><h2>"with_length" - Selects edges by their length</h2>
|
||||
<keyword name="with_length"/>
|
||||
<p>Usage:</p>
|
||||
|
|
@ -3505,12 +3529,13 @@ This method is available for polygon layers only.
|
|||
<li><tt>layer.without_angle(min .. max)</tt></li>
|
||||
<li><tt>layer.without_angle(value)</tt></li>
|
||||
<li><tt>layer.without_angle(min, max)</tt></li>
|
||||
<li><tt>edge_pairlayer.without_angle(min, max [, both])</tt></li>
|
||||
<li><tt>edge_pair_layer.without_angle(min, max [, both])</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
The method basically is the inverse of <a href="#with_angle">with_angle</a>. It selects all edges
|
||||
of the edge layer or corners of the polygons which do not have the given angle (second form) or whose angle
|
||||
is not inside the given interval (first and third form).
|
||||
is not inside the given interval (first and third form). When called on edge pairs, it selects
|
||||
edge pairs by the angles of their edges.
|
||||
</p><p>
|
||||
A note on the "both" modifier (without_angle called on edge pairs): "both" means that
|
||||
both edges need to be "without_angle". For example
|
||||
|
|
@ -3520,8 +3545,11 @@ both edges need to be "without_angle". For example
|
|||
# the edge pair is skipped if one edge is horizontal
|
||||
ep = edge_pairs.without_angle(0, both)
|
||||
</pre>
|
||||
</p><p>
|
||||
See <a href="#with_internal_angle">with_internal_angle</a> and <a href="#without_internal_angle">without_internal_angle</a> to select edge pairs by the
|
||||
angle between the edges.
|
||||
</p>
|
||||
<a name="without_area"/><h2>"without_area" - Selects polygons by area</h2>
|
||||
<a name="without_area"/><h2>"without_area" - Selects polygons or edge pairs by area</h2>
|
||||
<keyword name="without_area"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
|
|
@ -3531,10 +3559,10 @@ ep = edge_pairs.without_angle(0, both)
|
|||
</ul>
|
||||
<p>
|
||||
This method is the inverse of "with_area". It will select
|
||||
polygons without an area equal to the given one or outside
|
||||
polygons or edge pairs without an area equal to the given one or outside
|
||||
the given interval.
|
||||
</p><p>
|
||||
This method is available for polygon layers only.
|
||||
This method is available for polygon or edge pair layers.
|
||||
</p>
|
||||
<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"/>
|
||||
|
|
@ -3647,6 +3675,18 @@ This method is available for edge pair layers only.
|
|||
This method is available for polygon layers. It will select all polygons from the input layer
|
||||
which do not have the specified number of holes.
|
||||
</p>
|
||||
<a name="without_internal_angle"/><h2>"without_internal_angle" - Selects edge pairs by their internal angle</h2>
|
||||
<keyword name="without_internal_angle"/>
|
||||
<p>Usage:</p>
|
||||
<ul>
|
||||
<li><tt>edge_pair_layer.without_internal_angle(min .. max)</tt></li>
|
||||
<li><tt>edge_pair_layer.without_internal_angle(value)</tt></li>
|
||||
<li><tt>edge_pair_layer.without_internal_angle(min, max)</tt></li>
|
||||
</ul>
|
||||
<p>
|
||||
The method basically is the inverse of <a href="#with_internal_angle">with_internal_angle</a>. It selects all
|
||||
edge pairs by the angle enclosed by their edges, applying the opposite criterion than <a href="#with_internal_angle">with_internal_angle</a>.
|
||||
</p>
|
||||
<a name="without_length"/><h2>"without_length" - Selects edges by the their length</h2>
|
||||
<keyword name="without_length"/>
|
||||
<p>Usage:</p>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
|
||||
source $drc_test_source
|
||||
target $drc_test_target
|
||||
|
||||
if $drc_test_deep
|
||||
deep
|
||||
end
|
||||
|
||||
ep = input(1, 0).drc(sep(input(2, 0), angle_limit(91)) < 0.5)
|
||||
|
||||
input(1, 0).output(1, 0)
|
||||
input(2, 0).output(2, 0)
|
||||
|
||||
ep.polygons(0).output(100, 0)
|
||||
|
||||
ep.with_internal_angle(45.0).polygons(0).output(200, 0)
|
||||
ep.with_internal_angle(0.0).polygons(0).output(201, 0)
|
||||
ep.with_internal_angle(45.0..91.0).polygons(0).output(202, 0)
|
||||
|
||||
ep.without_internal_angle(45.0).polygons(0).output(220, 0)
|
||||
ep.without_internal_angle(0.0).polygons(0).output(221, 0)
|
||||
ep.without_internal_angle(45.0..91.0).polygons(0).output(222, 0)
|
||||
|
||||
ep.with_area(0 .. 0.1).polygons(0).output(300, 0)
|
||||
ep.without_area(0 .. 0.1).polygons(0).output(301, 0)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -225,6 +225,86 @@ class DBEdgePairs_TestClass < TestBase
|
|||
|
||||
end
|
||||
|
||||
def test_5
|
||||
|
||||
# filters
|
||||
|
||||
ep1 = RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 10), RBA::Edge::new(10, 20, 10, 0))
|
||||
ep2 = RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 10), RBA::Edge::new(10, 0, 10, 20))
|
||||
ep3 = RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 20), RBA::Edge::new(10, 20, 10, 0))
|
||||
ep4 = RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 10), RBA::Edge::new(10, 0, 10, 10))
|
||||
|
||||
r1 = RBA::EdgePairs::new([ ep1, ep2, ep3, ep4 ])
|
||||
|
||||
assert_equal(r1.with_distance(10, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_distance(5, 20, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_distance(15, 20, false).to_s, "")
|
||||
assert_equal(r1.with_distance(15, 20, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
|
||||
assert_equal(r1.with_length(10, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_length(10, 20, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_length(10, 21, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_length(10, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0)")
|
||||
assert_equal(r1.with_length_both(10, false).to_s, "(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_length_both(10, 20, false).to_s, "(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_length_both(10, 21, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_length_both(10, true).to_s, "(0,0;0,20)/(10,20;10,0)")
|
||||
|
||||
assert_equal(r1.with_angle(0, false).to_s, "")
|
||||
assert_equal(r1.with_angle(0, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_angle(90, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_angle(0, 90, false).to_s, "")
|
||||
assert_equal(r1.with_angle(0, 90, false, true, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_angle_both(0, false).to_s, "")
|
||||
assert_equal(r1.with_angle_both(0, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_angle_both(90, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_angle_both(0, 90, false).to_s, "")
|
||||
assert_equal(r1.with_angle_both(0, 90, false, true, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
|
||||
assert_equal(r1.with_area(0, false).to_s, "(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_area(150, false).to_s, "(0,0;0,10)/(10,20;10,0)")
|
||||
assert_equal(r1.with_area(0, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0)")
|
||||
assert_equal(r1.with_area(150, 151, false).to_s, "(0,0;0,10)/(10,20;10,0)")
|
||||
assert_equal(r1.with_area(150, 150, false).to_s, "")
|
||||
assert_equal(r1.with_area(150, 151, true).to_s, "(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
|
||||
assert_equal(r1.with_internal_angle(0, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(10,0;10,20);(0,0;0,20)/(10,20;10,0);(0,0;0,10)/(10,0;10,10)")
|
||||
assert_equal(r1.with_internal_angle(0, 0, false).to_s, "")
|
||||
assert_equal(r1.with_internal_angle(0, true).to_s, "")
|
||||
|
||||
ep1 = RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 10), RBA::Edge::new(10, 20, 10, 0))
|
||||
ep2 = RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 10), RBA::Edge::new(20, 0, 30, 0))
|
||||
ep3 = RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 10), RBA::Edge::new(-20, 0, -30, 0))
|
||||
|
||||
r1 = RBA::EdgePairs::new([ ep1, ep2, ep3 ])
|
||||
|
||||
assert_equal(r1.with_distance(20, false).to_s, "(0,0;0,10)/(20,0;30,0);(0,0;0,10)/(-20,0;-30,0)")
|
||||
assert_equal(r1.with_distance(20, true).to_s, "(0,0;0,10)/(10,20;10,0)")
|
||||
|
||||
assert_equal(r1.with_internal_angle(0, false).to_s, "(0,0;0,10)/(10,20;10,0)")
|
||||
assert_equal(r1.with_internal_angle(90, false).to_s, "(0,0;0,10)/(20,0;30,0);(0,0;0,10)/(-20,0;-30,0)")
|
||||
assert_equal(r1.with_internal_angle(-90, false).to_s, "")
|
||||
|
||||
assert_equal(r1.with_angle(90, false).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(20,0;30,0);(0,0;0,10)/(-20,0;-30,0)")
|
||||
assert_equal(r1.with_angle(0, false).to_s, "(0,0;0,10)/(20,0;30,0);(0,0;0,10)/(-20,0;-30,0)")
|
||||
assert_equal(r1.with_angle(0, 90, false, true, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(20,0;30,0);(0,0;0,10)/(-20,0;-30,0)")
|
||||
assert_equal(r1.with_angle_both(90, false).to_s, "(0,0;0,10)/(10,20;10,0)")
|
||||
assert_equal(r1.with_angle_both(0, false).to_s, "")
|
||||
|
||||
ep1 = RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 10), RBA::Edge::new(10, 20, 10, 0))
|
||||
ep2 = RBA::EdgePair::new(RBA::Edge::new(0, 0, 0, 10), RBA::Edge::new(20, 10, 30, 0))
|
||||
|
||||
r1 = RBA::EdgePairs::new([ ep1, ep2 ])
|
||||
|
||||
assert_equal(r1.with_internal_angle(0, false).to_s, "(0,0;0,10)/(10,20;10,0)")
|
||||
assert_equal(r1.with_internal_angle(90, false).to_s, "")
|
||||
assert_equal(r1.with_internal_angle(90, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(20,10;30,0)")
|
||||
assert_equal(r1.with_internal_angle(45, false).to_s, "(0,0;0,10)/(20,10;30,0)")
|
||||
assert_equal(r1.with_internal_angle(0, 45, false, true, true).to_s, "(0,0;0,10)/(10,20;10,0);(0,0;0,10)/(20,10;30,0)")
|
||||
assert_equal(r1.with_internal_angle(0, 45, true, true, true).to_s, "")
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue