Tests, so bug fixes, some refactoring

This commit is contained in:
Matthias Koefferlein 2021-05-29 09:43:12 +02:00
parent c8548709bb
commit e57d573a42
10 changed files with 166 additions and 23 deletions

View File

@ -46,7 +46,17 @@ AsIfFlatEdgePairs::AsIfFlatEdgePairs ()
AsIfFlatEdgePairs::AsIfFlatEdgePairs (const AsIfFlatEdgePairs &other)
: EdgePairsDelegate (other), m_bbox_valid (other.m_bbox_valid), m_bbox (other.m_bbox)
{
// .. nothing yet ..
operator= (other);
}
AsIfFlatEdgePairs &
AsIfFlatEdgePairs::operator= (const AsIfFlatEdgePairs &other)
{
if (this != &other) {
m_bbox_valid = other.m_bbox_valid;
m_bbox = other.m_bbox;
}
return *this;
}
AsIfFlatEdgePairs::~AsIfFlatEdgePairs ()

View File

@ -81,6 +81,8 @@ protected:
void invalidate_bbox ();
private:
friend class DeepEdgePairs;
AsIfFlatEdgePairs &operator= (const AsIfFlatEdgePairs &other);
mutable bool m_bbox_valid;

View File

@ -532,4 +532,14 @@ void DeepEdgePairs::insert_into_as_polygons (Layout *layout, db::cell_index_type
deep_layer ().insert_into_as_polygons (layout, into_cell, into_layer, enl);
}
DeepEdgePairs &DeepEdgePairs::operator= (const DeepEdgePairs &other)
{
if (this != &other) {
AsIfFlatEdgePairs::operator= (other);
DeepShapeCollectionDelegateBase::operator= (other);
}
return *this;
}
}

View File

@ -856,6 +856,9 @@ public:
* line through the edge. If the edge is degenerated, the distance
* is not defined.
*
* The distance is through as a distance of the point from the line
* through the edge.
*
* @param p The point to test.
*
* @return The distance
@ -877,6 +880,27 @@ public:
}
}
/**
* @brief Gets the distance of the point from the edge.
*
* The distance is computed as the minimum distance of the point to any of the edge's
* points.
*
* @param p The point whose distance is to be computed
*
* @return The distance
*/
distance_type euclidian_distance (const db::point<C> &p)
{
if (db::sprod_sign (p - p1 (), d ()) < 0) {
return p1 ().distance (p);
} else if (db::sprod_sign (p - p2 (), d ()) > 0) {
return p2 ().distance (p);
} else {
return std::abs (distance (p));
}
}
/**
* @brief Side of the point
*

View File

@ -204,6 +204,24 @@ public:
return !equal (b);
}
/**
* @brief Computes the distance of the edges in the edge pair
*
* The distance is the minimum distance of any of the points from
* each edge.
*/
distance_type distance () const
{
db::edge<C> e1 = first (), e2 = second ();
if (! e1.intersect (e2)) {
distance_type d12 = std::min (e2.euclidian_distance (e1.p1 ()), e2.euclidian_distance (e1.p2 ()));
distance_type d21 = std::min (e1.euclidian_distance (e2.p1 ()), e1.euclidian_distance (e2.p2 ()));
return std::min (d12, d21);
} else {
return 0;
}
}
/**
* @brief A method binding of operator* (mainly for automation purposes)
*/

View File

@ -71,28 +71,9 @@ EdgePairFilterByDistance::EdgePairFilterByDistance (distance_type min_distance,
// .. nothing yet ..
}
static db::coord_traits<db::Coord>::distance_type
distance_of_point_from_edge (const db::Edge &e, const db::Point &p)
{
if (db::sprod_sign (p - e.p1 (), e.d ()) < 0) {
return e.p1 ().distance (p);
} else if (db::sprod_sign (p - e.p2 (), e.d ()) > 0) {
return e.p2 ().distance (p);
} else {
return e.distance (p);
}
}
bool EdgePairFilterByDistance::selected (const db::EdgePair &edge_pair) const
{
distance_type dist = 0;
db::Edge e1 = edge_pair.first (), e2 = edge_pair.second ();
if (! e1.intersect (e2)) {
distance_type d12 = std::min (distance_of_point_from_edge (e2, e1.p1 ()), distance_of_point_from_edge (e2, e1.p2 ()));
distance_type d21 = std::min (distance_of_point_from_edge (e1, e2.p1 ()), distance_of_point_from_edge (e1, e2.p2 ()));
dist = std::min (d12, d21);
}
distance_type dist = edge_pair.distance ();
bool sel = (dist >= m_min_distance && dist < m_max_distance);
return m_inverted ? !sel : sel;
}

View File

@ -202,3 +202,17 @@ TEST(3_symmetric)
eh.insert (db::EdgePair (e2, e1, true));
EXPECT_EQ (int (eh.size ()), 1);
}
TEST(4_distance)
{
db::Edge e1 (db::Point (0, 0), db::Point (0, 100));
db::Edge e2 (db::Point (200, 100), db::Point (200, 0));
db::Edge e3 (db::Point (0, 0), db::Point (100, 0));
db::Edge e4 (db::Point (200, 0), db::Point (300, 0));
db::Edge e5 (db::Point (200, 100), db::Point (300, 100));
EXPECT_EQ (db::EdgePair (e1, e1).distance (), 0);
EXPECT_EQ (db::EdgePair (e1, e2).distance (), 200);
EXPECT_EQ (db::EdgePair (e3, e2).distance (), 100);
EXPECT_EQ (db::EdgePair (e3, e5).distance (), 141);
}

View File

@ -106,6 +106,17 @@ TEST(2)
EXPECT_EQ (db::Edge (10,20,110,222).distance_abs (db::Point (100, 200)), db::Edge::distance_type (1));
EXPECT_EQ (db::Edge (10,20,110,222).contains (db::Point (0, 0)), false);
EXPECT_EQ (db::Edge (10,20,110,222).contains (db::Point (100, 200)), false);
EXPECT_EQ (db::Edge (10,20,110,20).euclidian_distance (db::Point (100, 120)), 100);
EXPECT_EQ (db::Edge (10,20,110,20).euclidian_distance (db::Point (100, -80)), 100);
EXPECT_EQ (db::Edge (10,20,110,20).euclidian_distance (db::Point (-90, 120)), 141);
EXPECT_EQ (db::Edge (10,20,110,20).euclidian_distance (db::Point (-90, -80)), 141);
EXPECT_EQ (db::Edge (10,20,110,20).euclidian_distance (db::Point (210, 120)), 141);
EXPECT_EQ (db::Edge (10,20,110,20).euclidian_distance (db::Point (210, -80)), 141);
EXPECT_EQ (db::Edge (10,20,110,20).euclidian_distance (db::Point (-90, 20)), 100);
EXPECT_EQ (db::Edge (10,20,110,20).euclidian_distance (db::Point (10, 20)), 0);
EXPECT_EQ (db::Edge (10,20,110,20).euclidian_distance (db::Point (50, 20)), 0);
EXPECT_EQ (db::Edge (10,20,110,20).euclidian_distance (db::Point (110, 20)), 0);
}
TEST(3)

View File

@ -706,12 +706,21 @@ CODE
# version is similar to the first one, but allows specification of nil for min or
# max indicating that there is no lower or upper limit.
#
# This method is available for edge and edge pair layers.
#
# When called on an edge pair layer, this method will select edge pairs if one
# or both of the edges meet the length criterion. Use the additional argument
# and pass "both" (plain word) to specify that both edges need to be within the given interval.
# By default, it's sufficient for one edge to meet the criterion.
#
# Here are examples for "with_length" on edge pair layers:
#
# This method is available for edge and edge pair layers.
# @code
# # at least one edge needs to have a length of 1.0 <= l < 2.0
# ep1 = edge_pairs.with_length(1.um .. 2.um)
# # both edges need to have a length of exactly 2 um
# ep2 = edge_pairs.with_length(2.um, both)
# @/code
# %DRC%
# @name without_length
@ -725,6 +734,15 @@ CODE
# not inside the given interval (first and third form).
#
# This method is available for edge and edge pair layers.
#
# A note on the "both" modifier (without_length called on edge pairs): "both" means that
# both edges need to be "without_length". For example
#
# @code
# # both edges are not exactly 1 um in length, or:
# # the edge pair is skipped if one edge has a length of exactly 1 um
# ep = edge_pairs.without_length(1.um, both)
# @/code
%w(length).each do |f|
[true, false].each do |inv|
@ -862,6 +880,15 @@ CODE
# either "both" (plain word) to indicate that both edges have to be within the given interval.
# Without this argument, it is sufficient for one edge to meet the criterion.
#
# Here are examples for "with_angle" on edge pair layers:
#
# @code
# # at least one edge needs to be horizontal
# ep1 = edge_pairs.with_angle(0)
# # both edges need to vertical
# ep2 = edge_pairs.with_angle(90, both)
# @/code
#
# A method delivering all objects not matching the angle criterion is \without_angle.
#
# The following images demonstrate some use cases of \with_angle and \without_angle:
@ -888,6 +915,16 @@ CODE
# 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).
#
# A note on the "both" modifier (without_angle called on edge pairs): "both" means that
# both edges need to be "without_angle". For example
#
# @code
# # both edges are not horizontal or:
# # the edge pair is skipped if one edge is horizontal
# ep = edge_pairs.without_angle(0, both)
# @/code
#
%w(angle).each do |f|
[true, false].each do |inv|

View File

@ -3182,6 +3182,15 @@ meeting the angle criterion. In this case an additional argument is accepted whi
either "both" (plain word) to indicate that both edges have to be within the given interval.
Without this argument, it is sufficient for one edge to meet the criterion.
</p><p>
Here are examples for "with_angle" on edge pair layers:
</p><p>
<pre>
# at least one edge needs to be horizontal
ep1 = edge_pairs.with_angle(0)
# both edges need to vertical
ep2 = edge_pairs.with_angle(90, both)
</pre>
</p><p>
A method delivering all objects not matching the angle criterion is <a href="#without_angle">without_angle</a>.
</p><p>
The following images demonstrate some use cases of <a href="#with_angle">with_angle</a> and <a href="#without_angle:">without_angle:</a>
@ -3424,12 +3433,21 @@ The second version selects edges with exactly the given length. The third
version is similar to the first one, but allows specification of nil for min or
max indicating that there is no lower or upper limit.
</p><p>
This method is available for edge and edge pair layers.
</p><p>
When called on an edge pair layer, this method will select edge pairs if one
or both of the edges meet the length criterion. Use the additional argument
and pass "both" (plain word) to specify that both edges need to be within the given interval.
By default, it's sufficient for one edge to meet the criterion.
</p><p>
This method is available for edge and edge pair layers.
Here are examples for "with_length" on edge pair layers:
</p><p>
<pre>
# at least one edge needs to have a length of 1.0 &lt;= l &lt; 2.0
ep1 = edge_pairs.with_length(1.um .. 2.um)
# both edges need to have a length of exactly 2 um
ep2 = edge_pairs.with_length(2.um, both)
</pre>
</p>
<a name="with_perimeter"/><h2>"with_perimeter" - Selects polygons by perimeter</h2>
<keyword name="with_perimeter"/>
@ -3480,6 +3498,15 @@ This method is available for polygon layers only.
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).
</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
</p><p>
<pre>
# both edges are not horizontal or:
# the edge pair is skipped if one edge is horizontal
ep = edge_pairs.without_angle(0, both)
</pre>
</p>
<a name="without_area"/><h2>"without_area" - Selects polygons by area</h2>
<keyword name="without_area"/>
@ -3622,6 +3649,15 @@ of the edge layer which do not have the given length (second form) or are
not inside the given interval (first and third form).
</p><p>
This method is available for edge and edge pair layers.
</p><p>
A note on the "both" modifier (without_length called on edge pairs): "both" means that
both edges need to be "without_length". For example
</p><p>
<pre>
# both edges are not exactly 1 um in length, or:
# the edge pair is skipped if one edge has a length of exactly 1 um
ep = edge_pairs.without_length(1.um, both)
</pre>
</p>
<a name="without_perimeter"/><h2>"without_perimeter" - Selects polygons by perimeter</h2>
<keyword name="without_perimeter"/>