Major enhancements for DRC feature (universal DRC)

Main issue: universal DRC scheme and rectangle filtering/opposite filtering/shielding.

The space function required some enhancements to accomodate symmetric interactions.
Now there are symmetric edge pairs. Space initially runs twofold (primary to foreign)
but produces symmetric edge pairs. These are filtered later unless converted before.
This commit is contained in:
Matthias Koefferlein 2021-01-17 19:26:22 +01:00
parent fd90e66ee1
commit 9cf0a9e659
30 changed files with 430 additions and 101 deletions

View File

@ -1257,7 +1257,7 @@ AsIfFlatRegion::run_single_polygon_check (db::edge_relation_type rel, db::Coord
check.set_min_projection (options.min_projection);
check.set_max_projection (options.max_projection);
edge2edge_check_negative_or_positive<db::FlatEdgePairs> edge_check (check, *result, options.negative, false /*=same polygons*/, false /*=same layers*/, options.shielded);
edge2edge_check_negative_or_positive<db::FlatEdgePairs> edge_check (check, *result, options.negative, false /*=same polygons*/, false /*=same layers*/, options.shielded, true /*symmetric edge pairs*/);
poly2poly_check<db::Polygon> poly_check (edge_check);
do {

View File

@ -1494,7 +1494,7 @@ DeepRegion::run_single_polygon_check (db::edge_relation_type rel, db::Coord d, c
for (db::Shapes::shape_iterator s = shapes.begin (db::ShapeIterator::Polygons); ! s.at_end (); ++s) {
edge2edge_check_negative_or_positive<db::Shapes> edge_check (check, result, options.negative, false, false, options.shielded);
edge2edge_check_negative_or_positive<db::Shapes> edge_check (check, result, options.negative, false /*does not require different polygons*/, false /*does not require different layers*/, options.shielded, true /*symmetric edge pairs*/);
poly2poly_check<db::Polygon> poly_check (edge_check);
db::Polygon poly;

View File

@ -39,6 +39,16 @@
namespace db {
/**
* @brief A pair of edges
*
* An edge pair is a pair of edges which usually is used to mark a DRC violation. It flags the relationship of two edges.
* It's a compoisition of two edges: first and second.
*
* By default, an edge pair is directed: first and second are not commutable and indicate a relationship ("from first towards second").
* The edge pair carries a flag which allows indicating symmetric mode: in this mode, the first and second edge are commutable.
* As a consequence, when the symmetric flag is used, edge_pair(e1, e2, true) == edge_pair(e2, e1, true).
*/
template <class C>
class DB_PUBLIC_TEMPLATE edge_pair
{
@ -61,7 +71,7 @@ public:
* The default constructor creates an edge pair with two default edges.
*/
edge_pair ()
: m_first (), m_second ()
: m_first (), m_second (), m_symmetric (false)
{
// .. nothing else ..
}
@ -71,10 +81,11 @@ public:
*
* @param first The first edge
* @param second The second edge
* @param symmetric True, if the edge pair is symmetric
*/
template <class D>
edge_pair (const db::edge<D> &first, const db::edge<D> &second)
: m_first (first), m_second (second)
edge_pair (const db::edge<D> &first, const db::edge<D> &second, bool symmetric = false)
: m_first (first), m_second (second), m_symmetric (symmetric)
{
// .. nothing else ..
}
@ -84,11 +95,27 @@ public:
*/
template <class D>
edge_pair (const edge_pair<D> &e)
: m_first (e.first ()), m_second (e.second ())
: m_first (e.first ()), m_second (e.second ()), m_symmetric (e.is_symmetric ())
{
// .. nothing else ..
}
/**
* @brief Gets the symmetric flag
*/
bool is_symmetric () const
{
return m_symmetric;
}
/**
* @brief Sets the symmetric flag
*/
void set_symmetric (bool s)
{
m_symmetric = s;
}
/**
* @brief The (dummy) translation operator
*/
@ -112,7 +139,15 @@ public:
*/
bool operator< (const edge_pair<C> &b) const
{
return m_first < b.m_first || (m_first == b.m_first && m_second < b.m_second);
if (m_symmetric != b.m_symmetric) {
return m_symmetric < b.m_symmetric;
}
const edge_type &l = lesser ();
const edge_type &g = greater ();
const edge_type &bl = b.lesser ();
const edge_type &bg = b.greater ();
return l < bl || (l == bl && g < bg);
}
/**
@ -120,7 +155,10 @@ public:
*/
bool operator== (const edge_pair<C> &b) const
{
return m_first == b.m_first && m_second == b.m_second;
if (m_symmetric != b.m_symmetric) {
return false;
}
return lesser () == b.lesser () && greater () == b.greater ();
}
/**
@ -136,7 +174,15 @@ public:
*/
bool less (const edge_pair<C> &b) const
{
return m_first.less (b.m_first) || (m_first.equal (b.m_first) && m_second.less (b.m_second));
if (m_symmetric != b.m_symmetric) {
return m_symmetric < b.m_symmetric;
}
const edge_type &l = lesser ();
const edge_type &g = greater ();
const edge_type &bl = b.lesser ();
const edge_type &bg = b.greater ();
return l.less (bl) || (l.equal (bl) && g.less (bg));
}
/**
@ -144,7 +190,10 @@ public:
*/
bool equal (const edge_pair<C> &b) const
{
return m_first.equal (b.m_first) && m_second.equal (b.m_second);
if (m_symmetric != b.m_symmetric) {
return false;
}
return lesser ().equal (b.lesser ()) && greater ().equal (b.greater ());
}
/**
@ -160,7 +209,7 @@ public:
*/
edge_pair<C> scaled (double s) const
{
return edge_pair<C> (edge_type (first () * s), edge_type (second () * s));
return edge_pair<C> (edge_type (first () * s), edge_type (second () * s), m_symmetric);
}
/**
@ -193,7 +242,7 @@ public:
template <class Tr>
edge_pair<C> &transform (const Tr &t)
{
*this = edge_pair<C> (t * m_first, t * m_second);
*this = edge_pair<C> (t * m_first, t * m_second, m_symmetric);
return *this;
}
@ -210,7 +259,7 @@ public:
template <class Tr>
edge_pair<typename Tr::target_coord_type> transformed (const Tr &t) const
{
return edge_pair<typename Tr::target_coord_type> (t * m_first, t * m_second);
return edge_pair<typename Tr::target_coord_type> (t * m_first, t * m_second, m_symmetric);
}
/**
@ -278,6 +327,32 @@ public:
return m_second;
}
/**
* @brief The "lesser" edge.
* This feature is used for comparing symmetric edge pairs.
*/
const edge_type &lesser () const
{
if (m_symmetric) {
return m_first < m_second ? m_first : m_second;
} else {
return m_first;
}
}
/**
* @brief The "greater" edge.
* This feature is used for comparing symmetric edge pairs.
*/
const edge_type &greater () const
{
if (m_symmetric) {
return m_second < m_first ? m_first : m_second;
} else {
return m_second;
}
}
/**
* @brief returns the bounding box
*/
@ -310,7 +385,7 @@ public:
*/
std::string to_string (double dbu) const
{
return m_first.to_string (dbu) + "/" + m_second.to_string (dbu);
return lesser ().to_string (dbu) + (m_symmetric ? "|" : "/") + greater ().to_string (dbu);
}
/**
@ -466,6 +541,7 @@ public:
private:
edge_type m_first, m_second;
bool m_symmetric;
};
/**

View File

@ -89,6 +89,9 @@ public:
void process(const EdgePair &ep, std::vector<db::Edge> &res) const
{
res.push_back (ep.first ());
if (ep.is_symmetric ()) {
res.push_back (ep.second ());
}
}
};
@ -102,7 +105,9 @@ public:
void process(const EdgePair &ep, std::vector<db::Edge> &res) const
{
res.push_back (ep.second ());
if (! ep.is_symmetric ()) {
res.push_back (ep.second ());
}
}
};

View File

@ -141,7 +141,7 @@ namespace std
{
size_t operator() (const db::edge_pair<C> &o) const
{
return hfunc (o.first (), hfunc (o.second ()));
return hfunc (o.lesser (), hfunc (o.greater (), hfunc (int (o.is_symmetric ()))));
}
};

View File

@ -723,10 +723,12 @@ shape_interactions<TS, TI>::intruder_shape (unsigned int id) const
// explicit instantiations
template class DB_PUBLIC shape_interactions<db::Polygon, db::Polygon>;
template class DB_PUBLIC shape_interactions<db::Polygon, db::Text>;
template class DB_PUBLIC shape_interactions<db::PolygonRef, db::PolygonRef>;
template class DB_PUBLIC shape_interactions<db::PolygonRef, db::Edge>;
template class DB_PUBLIC shape_interactions<db::Polygon, db::TextRef>;
template class DB_PUBLIC shape_interactions<db::Polygon, db::Edge>;
template class DB_PUBLIC shape_interactions<db::PolygonRef, db::PolygonRef>;
template class DB_PUBLIC shape_interactions<db::PolygonRef, db::TextRef>;
template class DB_PUBLIC shape_interactions<db::PolygonRef, db::Text>;
template class DB_PUBLIC shape_interactions<db::PolygonRef, db::Edge>;
template class DB_PUBLIC shape_interactions<db::Edge, db::Edge>;
template class DB_PUBLIC shape_interactions<db::Edge, db::PolygonRef>;
template class DB_PUBLIC shape_interactions<db::TextRef, db::TextRef>;

View File

@ -89,17 +89,27 @@ void local_operation<TS, TI, TR>::compute_local (db::Layout *layout, const shape
// explicit instantiations
template class DB_PUBLIC local_operation<db::Polygon, db::Polygon, db::Polygon>;
template class DB_PUBLIC local_operation<db::Polygon, db::Polygon, db::Edge>;
template class DB_PUBLIC local_operation<db::Polygon, db::Text, db::Polygon>;
template class DB_PUBLIC local_operation<db::Polygon, db::Text, db::Text>;
template class DB_PUBLIC local_operation<db::Polygon, db::Edge, db::Polygon>;
template class DB_PUBLIC local_operation<db::Polygon, db::Edge, db::Edge>;
template class DB_PUBLIC local_operation<db::PolygonRef, db::PolygonRef, db::PolygonRef>;
template class DB_PUBLIC local_operation<db::PolygonRef, db::Text, db::PolygonRef>;
template class DB_PUBLIC local_operation<db::PolygonRef, db::TextRef, db::PolygonRef>;
template class DB_PUBLIC local_operation<db::PolygonRef, db::TextRef, db::TextRef>;
template class DB_PUBLIC local_operation<db::PolygonRef, db::Edge, db::PolygonRef>;
template class DB_PUBLIC local_operation<db::PolygonRef, db::Edge, db::Edge>;
template class DB_PUBLIC local_operation<db::PolygonRef, db::PolygonRef, db::EdgePair>;
template class DB_PUBLIC local_operation<db::PolygonRef, db::PolygonRef, db::Edge>;
template class DB_PUBLIC local_operation<db::Polygon, db::Polygon, db::EdgePair>;
template class DB_PUBLIC local_operation<db::Polygon, db::TextRef, db::TextRef>;
template class DB_PUBLIC local_operation<db::Edge, db::Edge, db::Edge>;
template class DB_PUBLIC local_operation<db::Edge, db::PolygonRef, db::Edge>;
template class DB_PUBLIC local_operation<db::Edge, db::PolygonRef, db::PolygonRef>;
template class DB_PUBLIC local_operation<db::Edge, db::Edge, db::EdgePair>;
template class DB_PUBLIC local_operation<db::TextRef, db::PolygonRef, db::PolygonRef>;
template class DB_PUBLIC local_operation<db::TextRef, db::PolygonRef, db::TextRef>;
// ---------------------------------------------------------------------------------------------
// BoolAndOrNotLocalOperation implementation

View File

@ -202,7 +202,10 @@ check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, const shape
tl_assert (results.size () == 1);
std::unordered_set<db::EdgePair> result, intra_polygon_result;
edge2edge_check_negative_or_positive<std::unordered_set<db::EdgePair> > edge_check (m_check, result, intra_polygon_result, m_options.negative, m_different_polygons, m_has_other, m_options.shielded);
// NOTE: the rectangle and opposite filters are unsymmetric
bool symmetric_edge_pairs = ! m_has_other && m_options.opposite_filter == db::NoOppositeFilter && m_options.rect_filter == RectFilter::NoSideAllowed;
edge2edge_check_negative_or_positive<std::unordered_set<db::EdgePair> > edge_check (m_check, result, intra_polygon_result, m_options.negative, m_different_polygons, m_has_other, m_options.shielded, symmetric_edge_pairs);
poly2poly_check<TS> poly_check (edge_check);
std::list<TS> heap;
@ -302,7 +305,6 @@ check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, const shape
scanner.process (poly_check, m_check.distance (), db::box_convert<TS> ());
} while (edge_check.prepare_next_pass ());
// detect and remove parts of the result which have or do not have results "opposite"
// ("opposite" is defined by the projection of edges "through" the subject shape)
if (m_options.opposite_filter != db::NoOppositeFilter && (! result.empty () || ! intra_polygon_result.empty ())) {
@ -313,6 +315,8 @@ check_local_operation<TS, TI>::do_compute_local (db::Layout *layout, const shape
if (m_has_other) {
tl_assert (intra_polygon_result.empty ());
// filter out opposite edges: this is the case of two-layer checks where we can maintain the edge pairs but
// strip them of the filtered-out part.

View File

@ -32,9 +32,14 @@ namespace db
// -------------------------------------------------------------------------------------
// Edge2EdgeCheckBase implementation
Edge2EdgeCheckBase::Edge2EdgeCheckBase (const EdgeRelationFilter &check, bool different_polygons, bool requires_different_layers, bool with_shielding)
Edge2EdgeCheckBase::Edge2EdgeCheckBase (const EdgeRelationFilter &check, bool different_polygons, bool requires_different_layers, bool with_shielding, bool symmetric_edges)
: mp_check (&check), m_requires_different_layers (requires_different_layers), m_different_polygons (different_polygons),
m_first_pseudo (std::numeric_limits<size_t>::max ()), m_with_shielding (with_shielding), m_has_edge_pair_output (true), m_has_negative_edge_output (false), m_pass (0)
m_first_pseudo (std::numeric_limits<size_t>::max ()),
m_with_shielding (with_shielding),
m_symmetric_edges (symmetric_edges),
m_has_edge_pair_output (true),
m_has_negative_edge_output (false),
m_pass (0)
{
m_distance = check.distance ();
}
@ -159,13 +164,42 @@ Edge2EdgeCheckBase::feed_pseudo_edges (db::box_scanner<db::Edge, size_t> &scanne
}
}
inline bool edges_considered (bool requires_different_polygons, bool requires_different_layers, size_t p1, size_t p2)
{
if (p1 == p2) {
if (requires_different_polygons) {
return false;
} else if ((p1 & size_t (1)) != 0) {
// edges from the same polygon are only considered on first layer.
// Reasoning: this case happens when "intruder" polygons are put on layer 1
// while "subject" polygons are put on layer 0. We don't want "intruders"
// to generate intra-polygon markers.
return false;
}
}
if (((p1 ^ p2) & size_t (1)) == 0) {
if (requires_different_layers) {
return false;
} else if ((p1 & size_t (1)) != 0) {
// edges on the same layer are only considered on first layer.
// Reasoning: this case happens when "intruder" polygons are put on layer 1
// while "subject" polygons are put on layer 0. We don't want "intruders"
// to generate inter-polygon markers between them.
return false;
}
}
return true;
}
void
Edge2EdgeCheckBase::add (const db::Edge *o1, size_t p1, const db::Edge *o2, size_t p2)
{
if (m_pass == 0) {
// Overlap or inside checks require input from different layers
if ((! m_different_polygons || p1 != p2) && (! m_requires_different_layers || ((p1 ^ p2) & 1) != 0)) {
if (edges_considered (m_different_polygons, m_requires_different_layers, p1, p2)) {
// ensure that the first check argument is of layer 1 and the second of
// layer 2 (unless both are of the same layer)
@ -180,6 +214,8 @@ Edge2EdgeCheckBase::add (const db::Edge *o1, size_t p1, const db::Edge *o2, size
db::EdgePair ep;
if (mp_check->check (*o1, *o2, &ep)) {
ep.set_symmetric (m_symmetric_edges);
// found a violation: store inside the local buffer for now. In the second
// pass we will eliminate those which are shielded completely (with shielding)
// and/or compute the negative edges.
@ -266,7 +302,7 @@ Edge2EdgeCheckBase::add (const db::Edge *o1, size_t p1, const db::Edge *o2, size
(m_pseudo_edges.find (std::make_pair (*o1, p1)) != m_pseudo_edges.end ()) != (m_pseudo_edges.find (std::make_pair (*o2, p2)) != m_pseudo_edges.end ())) {
// Overlap or inside checks require input from different layers
if ((! m_different_polygons || p1 != p2) && (! m_requires_different_layers || ((p1 ^ p2) & 1) != 0)) {
if (edges_considered (m_different_polygons, m_requires_different_layers, p1, p2)) {
// ensure that the first check argument is of layer 1 and the second of
// layer 2 (unless both are of the same layer)
@ -756,7 +792,7 @@ SinglePolygonCheck::process (const db::Polygon &polygon, std::vector<db::EdgePai
check.set_min_projection (m_options.min_projection);
check.set_max_projection (m_options.max_projection);
edge2edge_check_negative_or_positive <std::unordered_set<db::EdgePair> > edge_check (check, result, m_options.negative, false /*=same polygons*/, false /*=same layers*/, m_options.shielded);
edge2edge_check_negative_or_positive <std::unordered_set<db::EdgePair> > edge_check (check, result, m_options.negative, false /*=same polygons*/, false /*=same layers*/, m_options.shielded, true /*=symmetric*/);
poly2poly_check<db::Polygon> poly_check (edge_check);
do {

View File

@ -544,7 +544,7 @@ class DB_PUBLIC Edge2EdgeCheckBase
: public db::box_scanner_receiver<db::Edge, size_t>
{
public:
Edge2EdgeCheckBase (const EdgeRelationFilter &check, bool different_polygons, bool requires_different_layers, bool with_shielding);
Edge2EdgeCheckBase (const EdgeRelationFilter &check, bool different_polygons, bool requires_different_layers, bool with_shielding, bool symmetric_edges);
/**
* @brief Call this to initiate a new pass until the return value is false
@ -630,6 +630,7 @@ private:
size_t m_first_pseudo;
std::vector<bool> m_ep_discarded, m_ep_intra_polygon;
bool m_with_shielding;
bool m_symmetric_edges;
bool m_has_edge_pair_output;
bool m_has_negative_edge_output;
unsigned int m_pass;
@ -645,14 +646,14 @@ class DB_PUBLIC_TEMPLATE edge2edge_check
: public Edge2EdgeCheckBase
{
public:
edge2edge_check (const EdgeRelationFilter &check, Output &output, bool different_polygons, bool requires_different_layers, bool with_shielding)
: Edge2EdgeCheckBase (check, different_polygons, requires_different_layers, with_shielding), mp_output_inter (&output), mp_output_intra (0)
edge2edge_check (const EdgeRelationFilter &check, Output &output, bool different_polygons, bool requires_different_layers, bool with_shielding, bool symmetric_edges)
: Edge2EdgeCheckBase (check, different_polygons, requires_different_layers, with_shielding, symmetric_edges), mp_output_inter (&output), mp_output_intra (0)
{
// .. nothing yet ..
}
edge2edge_check (const EdgeRelationFilter &check, Output &output_inter, Output &output_intra, bool different_polygons, bool requires_different_layers, bool with_shielding)
: Edge2EdgeCheckBase (check, different_polygons, requires_different_layers, with_shielding), mp_output_inter (&output_inter), mp_output_intra (&output_intra)
edge2edge_check (const EdgeRelationFilter &check, Output &output_inter, Output &output_intra, bool different_polygons, bool requires_different_layers, bool with_shielding, bool symmetric_edges)
: Edge2EdgeCheckBase (check, different_polygons, requires_different_layers, with_shielding, symmetric_edges), mp_output_inter (&output_inter), mp_output_intra (&output_intra)
{
// .. nothing yet ..
}
@ -683,16 +684,16 @@ class DB_PUBLIC_TEMPLATE edge2edge_check_with_negative_output
: public edge2edge_check<Output>
{
public:
edge2edge_check_with_negative_output (const EdgeRelationFilter &check, Output &output, NegativeEdgeOutput &l1_negative_output, NegativeEdgeOutput &l2_negative_output, bool different_polygons, bool requires_different_layers, bool with_shielding)
: edge2edge_check<Output> (check, output, different_polygons, requires_different_layers, with_shielding),
edge2edge_check_with_negative_output (const EdgeRelationFilter &check, Output &output, NegativeEdgeOutput &l1_negative_output, NegativeEdgeOutput &l2_negative_output, bool different_polygons, bool requires_different_layers, bool with_shielding, bool symmetric_edges)
: edge2edge_check<Output> (check, output, different_polygons, requires_different_layers, with_shielding, symmetric_edges),
mp_l1_negative_output (&l1_negative_output),
mp_l2_negative_output (&l2_negative_output)
{
edge2edge_check<Output>::set_has_negative_edge_output (true);
}
edge2edge_check_with_negative_output (const EdgeRelationFilter &check, Output &output_inter, Output &output_intra, NegativeEdgeOutput &l1_negative_output, NegativeEdgeOutput &l2_negative_output, bool different_polygons, bool requires_different_layers, bool with_shielding)
: edge2edge_check<Output> (check, output_inter, output_intra, different_polygons, requires_different_layers, with_shielding),
edge2edge_check_with_negative_output (const EdgeRelationFilter &check, Output &output_inter, Output &output_intra, NegativeEdgeOutput &l1_negative_output, NegativeEdgeOutput &l2_negative_output, bool different_polygons, bool requires_different_layers, bool with_shielding, bool symmetric_edges)
: edge2edge_check<Output> (check, output_inter, output_intra, different_polygons, requires_different_layers, with_shielding, symmetric_edges),
mp_l1_negative_output (&l1_negative_output),
mp_l2_negative_output (&l2_negative_output)
{
@ -726,7 +727,7 @@ class DB_PUBLIC_TEMPLATE edge2edge_check_negative
{
public:
edge2edge_check_negative (const EdgeRelationFilter &check, NegativeEdgeOutput &l1_negative_output, NegativeEdgeOutput &l2_negative_output, bool different_polygons, bool requires_different_layers, bool with_shielding)
: Edge2EdgeCheckBase (check, different_polygons, requires_different_layers, with_shielding),
: Edge2EdgeCheckBase (check, different_polygons, requires_different_layers, with_shielding, false),
mp_l1_negative_output (&l1_negative_output),
mp_l2_negative_output (&l2_negative_output)
{
@ -761,15 +762,15 @@ class DB_PUBLIC_TEMPLATE edge2edge_check_negative_or_positive
: public edge2edge_check<Output>
{
public:
edge2edge_check_negative_or_positive (const EdgeRelationFilter &check, Output &output, bool negative_output, bool different_polygons, bool requires_different_layers, bool with_shielding)
: edge2edge_check<Output> (check, output, different_polygons, requires_different_layers, with_shielding)
edge2edge_check_negative_or_positive (const EdgeRelationFilter &check, Output &output, bool negative_output, bool different_polygons, bool requires_different_layers, bool with_shielding, bool symmetric)
: edge2edge_check<Output> (check, output, different_polygons, requires_different_layers, with_shielding, symmetric)
{
edge2edge_check<Output>::set_has_negative_edge_output (negative_output);
edge2edge_check<Output>::set_has_edge_pair_output (! negative_output);
}
edge2edge_check_negative_or_positive (const EdgeRelationFilter &check, Output &output_inter, Output &output_intra, bool negative_output, bool different_polygons, bool requires_different_layers, bool with_shielding)
: edge2edge_check<Output> (check, output_inter, output_intra, different_polygons, requires_different_layers, with_shielding)
edge2edge_check_negative_or_positive (const EdgeRelationFilter &check, Output &output_inter, Output &output_intra, bool negative_output, bool different_polygons, bool requires_different_layers, bool with_shielding, bool symmetric)
: edge2edge_check<Output> (check, output_inter, output_intra, different_polygons, requires_different_layers, with_shielding, symmetric)
{
edge2edge_check<Output>::set_has_negative_edge_output (negative_output);
edge2edge_check<Output>::set_has_edge_pair_output (! negative_output);

View File

@ -54,9 +54,9 @@ struct edge_pair_defs
return new C ();
}
static C *new_ee (const edge_type &first, const edge_type &second)
static C *new_ee (const edge_type &first, const edge_type &second, bool symmetric)
{
return new C (first, second);
return new C (first, second, symmetric);
}
static size_t hash_value (const C *ep)
@ -72,10 +72,11 @@ struct edge_pair_defs
"\n"
"This constructor creates an default edge pair.\n"
) +
constructor ("new", &new_ee,
constructor ("new", &new_ee, gsi::arg ("first"), gsi::arg ("second"), gsi::arg ("symmetric", false),
"@brief Constructor from two edges\n"
"\n"
"This constructor creates an edge pair from the two edges given.\n"
"See \\symmetric? for a description of this attribute."
) +
method ("first", (const edge_type &(C::*) () const) &C::first,
"@brief Gets the first edge\n"
@ -89,7 +90,34 @@ struct edge_pair_defs
method ("second=", &C::set_second, gsi::arg ("edge"),
"@brief Sets the second edge\n"
) +
method ("normalized", &C::normalized,
method ("symmetric?", &C::is_symmetric,
"@brief Returns a value indicating whether the edge pair is symmetric\n"
"For symmetric edge pairs, the edges are commutable. Specifically, a symmetric edge pair with (e1,e2) is identical to (e2,e1). "
"Symmetric edge pairs are generated by some checks for which there is no directed error marker (width, space, notch, isolated).\n"
"\n"
"Symmetric edge pairs have been introduced in version 0.27.\n"
) +
method ("symmetric=", &C::set_symmetric,
"@brief Sets a value indicating whether the edge pair is symmetric\n"
"See \\symmetric? for a description of this attribute.\n"
"\n"
"Symmetric edge pairs have been introduced in version 0.27.\n"
) +
method ("lesser", (const edge_type &(C::*) () const) &C::lesser,
"@brief Gets the 'lesser' edge for symmetric edge pairs\n"
"As first and second edges are commutable for symmetric edge pairs (see \\symmetric?), this accessor allows "
"retrieving a 'first' edge in a way independent on the actual assignment.\n"
"\n"
"This read-only attribute has been introduced in version 0.27.\n"
) +
method ("greater", (const edge_type &(C::*) () const) &C::greater,
"@brief Gets the 'greater' edge for symmetric edge pairs\n"
"As first and second edges are commutable for symmetric edge pairs (see \\symmetric?), this accessor allows "
"retrieving a 'second' edge in a way independent on the actual assignment.\n"
"\n"
"This read-only attribute has been introduced in version 0.27.\n"
) +
method ("normalized", &C::normalized,
"@brief Normalizes the edge pair\n"
"This method normalized the edge pair such that when connecting the edges at their \n"
"start and end points a closed loop is formed which is oriented clockwise. To "

View File

@ -23,8 +23,12 @@
#include "dbEdgePair.h"
#include "dbHash.h"
#include "tlUnitTest.h"
#include <set>
#include <unordered_set>
TEST(1)
{
db::EdgePair ep;
@ -147,3 +151,56 @@ TEST(2)
EXPECT_EQ (ep.normalized ().to_polygon (1).to_string (), "(1,-1;-1,19;-1,31;1,11)");
}
TEST(3_symmetric)
{
db::Edge e1 (db::Point (0, 0), db::Point (0, 100));
db::Edge e2 (db::Point (200, 100), db::Point (200, 0));
EXPECT_EQ (db::EdgePair (e1, e2, false) == db::EdgePair (e1, e2, false), true);
EXPECT_EQ (db::EdgePair (e1, e2, false) == db::EdgePair (e2, e1, false), false);
EXPECT_EQ (db::EdgePair (e1, e2, true) == db::EdgePair (e1, e2, false), false);
EXPECT_EQ (db::EdgePair (e1, e2, true) == db::EdgePair (e1, e2, true), true);
EXPECT_EQ (db::EdgePair (e1, e2, true) == db::EdgePair (e2, e1, true), true);
EXPECT_EQ (db::EdgePair (e1, e2, false) < db::EdgePair (e1, e2, false), false);
EXPECT_EQ (db::EdgePair (e1, e2, false) < db::EdgePair (e2, e1, false), true);
EXPECT_EQ (db::EdgePair (e2, e1, false) < db::EdgePair (e2, e1, false), false);
EXPECT_EQ (db::EdgePair (e1, e2, false) < db::EdgePair (e1, e2, true), true);
EXPECT_EQ (db::EdgePair (e1, e2, true) < db::EdgePair (e1, e2, false), false);
EXPECT_EQ (db::EdgePair (e1, e2, true) < db::EdgePair (e1, e2, true), false);
EXPECT_EQ (db::EdgePair (e1, e2, true) < db::EdgePair (e2, e1, true), false);
std::set<db::EdgePair> es;
es.clear ();
es.insert (db::EdgePair (e1, e2, false));
es.insert (db::EdgePair (e1, e2, true));
EXPECT_EQ (int (es.size ()), 2);
es.clear ();
es.insert (db::EdgePair (e1, e2, false));
es.insert (db::EdgePair (e2, e1, false));
EXPECT_EQ (int (es.size ()), 2);
es.clear ();
es.insert (db::EdgePair (e1, e2, true));
es.insert (db::EdgePair (e2, e1, true));
EXPECT_EQ (int (es.size ()), 1);
std::unordered_set<db::EdgePair> eh;
eh.clear ();
eh.insert (db::EdgePair (e1, e2, false));
eh.insert (db::EdgePair (e1, e2, true));
EXPECT_EQ (int (eh.size ()), 2);
eh.clear ();
eh.insert (db::EdgePair (e1, e2, false));
eh.insert (db::EdgePair (e2, e1, false));
EXPECT_EQ (int (eh.size ()), 2);
eh.clear ();
eh.insert (db::EdgePair (e1, e2, true));
eh.insert (db::EdgePair (e2, e1, true));
EXPECT_EQ (int (eh.size ()), 1);
}

View File

@ -505,14 +505,14 @@ TEST(15a)
db::Box bb[3] = { db::Box (db::Point (0, 0), db::Point (10, 10)), db::Box (), db::Box (db::Point (20, 20), db::Point (40, 50)) };
db::Region r (bb + 0, bb + 3);
EXPECT_EQ (r.width_check (15).to_string (), "(0,0;0,10)/(10,10;10,0);(0,10;10,10)/(10,0;0,0)");
EXPECT_EQ (r.width_check (15).to_string (), "(0,0;0,10)|(10,10;10,0);(10,0;0,0)|(0,10;10,10)");
EXPECT_EQ (r.width_check (5).to_string (), "");
EXPECT_EQ (r.width_check (5, db::RegionCheckOptions (false, db::Euclidian, 91)).to_string (), "(0,5;0,10)/(0,10;5,10);(0,0;0,5)/(5,0;0,0);(5,10;10,10)/(10,10;10,5);(10,5;10,0)/(10,0;5,0);(20,45;20,50)/(20,50;25,50);(20,20;20,25)/(25,20;20,20);(35,50;40,50)/(40,50;40,45);(40,25;40,20)/(40,20;35,20)");
EXPECT_EQ (r.space_check (15, db::RegionCheckOptions (false, db::Euclidian, 91)).to_string (), "(20,20;20,21)/(9,10;10,10);(20,20;20,21)/(10,10;10,9);(21,20;20,20)/(9,10;10,10);(21,20;20,20)/(10,10;10,9)");
EXPECT_EQ (r.space_check (15, db::RegionCheckOptions (false, db::Square, 91)).to_string (), "(20,20;20,25)/(5,10;10,10);(20,20;20,25)/(10,10;10,5);(25,20;20,20)/(5,10;10,10);(25,20;20,20)/(10,10;10,5)");
EXPECT_EQ (r.space_check (15).to_string (), "(20,20;20,21)/(10,10;10,9);(21,20;20,20)/(9,10;10,10)");
EXPECT_EQ (r.space_check (15, db::RegionCheckOptions (true)).to_string (), "(20,20;20,50)/(10,10;10,0);(40,20;20,20)/(0,10;10,10)");
EXPECT_EQ (r.space_check (15, db::RegionCheckOptions (false, db::Square)).to_string (), "(20,20;20,25)/(10,10;10,5);(25,20;20,20)/(5,10;10,10)");
EXPECT_EQ (r.width_check (5, db::RegionCheckOptions (false, db::Euclidian, 91)).to_string (), "(0,5;0,10)|(0,10;5,10);(0,0;0,5)|(5,0;0,0);(5,10;10,10)|(10,10;10,5);(10,0;5,0)|(10,5;10,0);(20,45;20,50)|(20,50;25,50);(20,20;20,25)|(25,20;20,20);(35,50;40,50)|(40,50;40,45);(40,20;35,20)|(40,25;40,20)");
EXPECT_EQ (r.space_check (15, db::RegionCheckOptions (false, db::Euclidian, 91)).to_string (), "(9,10;10,10)|(20,20;20,21);(10,10;10,9)|(20,20;20,21);(9,10;10,10)|(21,20;20,20);(10,10;10,9)|(21,20;20,20)");
EXPECT_EQ (r.space_check (15, db::RegionCheckOptions (false, db::Square, 91)).to_string (), "(5,10;10,10)|(20,20;20,25);(10,10;10,5)|(20,20;20,25);(5,10;10,10)|(25,20;20,20);(10,10;10,5)|(25,20;20,20)");
EXPECT_EQ (r.space_check (15).to_string (), "(10,10;10,9)|(20,20;20,21);(9,10;10,10)|(21,20;20,20)");
EXPECT_EQ (r.space_check (15, db::RegionCheckOptions (true)).to_string (), "(10,10;10,0)|(20,20;20,50);(0,10;10,10)|(40,20;20,20)");
EXPECT_EQ (r.space_check (15, db::RegionCheckOptions (false, db::Square)).to_string (), "(10,10;10,5)|(20,20;20,25);(5,10;10,10)|(25,20;20,20)");
r.clear ();
db::Point pts[] = {
@ -533,7 +533,7 @@ TEST(15a)
poly.assign_hull(pts + 0, pts + sizeof(pts)/sizeof(pts[0]));
r.insert (poly);
EXPECT_EQ (r.width_check (70000).to_string (), "(20550000,-18950000;20550000,-18920000)/(20570000,-18880000;20570000,-18890000);(20550000,-18920000;20530000,-18920000)/(20550000,-18880000;20570000,-18880000);(20550000,-18920000;20530000,-18920000)/(20570000,-18890000;20613246,-18890000);(20530000,-18920000;20530000,-18910000)/(20550000,-18850000;20550000,-18880000);(20530000,-18920000;20530000,-18910000)/(20570000,-18880000;20570000,-18890000);(20530000,-18910000;20450000,-18910000)/(20450000,-18850000;20550000,-18850000);(20530000,-18910000;20486754,-18910000)/(20550000,-18880000;20570000,-18880000);(20530000,-18910000;20502918,-18910000)/(20570000,-18890000;20597082,-18890000);(20570000,-18890000;20650000,-18890000)/(20650000,-18950000;20550000,-18950000)");
EXPECT_EQ (r.width_check (70000).to_string (), "(20550000,-18950000;20550000,-18920000)|(20570000,-18880000;20570000,-18890000);(20550000,-18920000;20530000,-18920000)|(20550000,-18880000;20570000,-18880000);(20550000,-18920000;20530000,-18920000)|(20570000,-18890000;20613246,-18890000);(20530000,-18920000;20530000,-18910000)|(20550000,-18850000;20550000,-18880000);(20530000,-18920000;20530000,-18910000)|(20570000,-18880000;20570000,-18890000);(20530000,-18910000;20450000,-18910000)|(20450000,-18850000;20550000,-18850000);(20530000,-18910000;20486754,-18910000)|(20550000,-18880000;20570000,-18880000);(20530000,-18910000;20502918,-18910000)|(20570000,-18890000;20597082,-18890000);(20650000,-18950000;20550000,-18950000)|(20570000,-18890000;20650000,-18890000)");
}
TEST(15b)
@ -544,10 +544,10 @@ TEST(15b)
r.insert (db::Box (db::Point (300, 300), db::Point (500, 500)));
r.insert (db::Box (db::Point (400, 200), db::Point (500, 300)));
EXPECT_EQ (r.width_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(400,200;400,300)/(500,300;500,200)");
EXPECT_EQ (r.space_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(300,0;300,200)/(200,200;200,0);(300,300;300,500)/(200,500;200,300);(300,200;400,200)/(400,300;300,300)");
EXPECT_EQ (r.notch_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(300,200;400,200)/(400,300;300,300)");
EXPECT_EQ (r.isolated_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(200,200;200,0)/(300,0;300,200);(200,500;200,300)/(300,300;300,500)");
EXPECT_EQ (r.width_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(400,200;400,300)|(500,300;500,200)");
EXPECT_EQ (r.space_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(300,0;300,200)|(200,200;200,0);(300,300;300,500)|(200,500;200,300);(300,200;400,200)|(400,300;300,300)");
EXPECT_EQ (r.notch_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(300,200;400,200)|(400,300;300,300)");
EXPECT_EQ (r.isolated_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(300,0;300,200)|(200,200;200,0);(300,300;300,500)|(200,500;200,300)");
}
TEST(15c)
@ -562,10 +562,10 @@ TEST(15c)
r.insert (db::Box (db::Point (400, 200), db::Point (500, 250)));
r.insert (db::Box (db::Point (400, 250), db::Point (500, 300)));
EXPECT_EQ (r.width_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(400,200;400,300)/(500,300;500,200)");
EXPECT_EQ (r.space_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(300,0;300,200)/(200,200;200,0);(300,300;300,500)/(200,500;200,300);(300,200;400,200)/(400,300;300,300)");
EXPECT_EQ (r.notch_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(300,200;400,200)/(400,300;300,300)");
EXPECT_EQ (r.isolated_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(200,200;200,0)/(300,0;300,200);(200,500;200,300)/(300,300;300,500)");
EXPECT_EQ (r.width_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(400,200;400,300)|(500,300;500,200)");
EXPECT_EQ (r.space_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(300,0;300,200)|(200,200;200,0);(300,300;300,500)|(200,500;200,300);(300,200;400,200)|(400,300;300,300)");
EXPECT_EQ (r.notch_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(300,200;400,200)|(400,300;300,300)");
EXPECT_EQ (r.isolated_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (), "(300,0;300,200)|(200,200;200,0);(300,300;300,500)|(200,500;200,300)");
}
TEST(15d)
@ -581,12 +581,12 @@ TEST(15d)
r.insert (db::Box (db::Point (0, 140), db::Point (350, 160)));
EXPECT_EQ (r.space_check (120, db::RegionCheckOptions (false, db::Projection)).to_string (),
"(100,140;0,140)/(0,100;100,100);"
"(350,140;300,140)/(300,100;350,100);"
"(100,200;0,200)/(0,160;100,160);"
"(400,200;300,200)/(300,100;400,100);"
"(350,200;300,200)/(300,160;350,160);"
"(700,200;600,200)/(600,100;700,100)"
"(300,100;350,100)|(350,140;300,140);"
"(0,100;100,100)|(100,140;0,140);"
"(0,160;100,160)|(100,200;0,200);"
"(300,160;350,160)|(350,200;300,200);"
"(300,100;400,100)|(400,200;300,200);"
"(600,100;700,100)|(700,200;600,200)"
);
}
@ -635,7 +635,7 @@ TEST(15e)
r.insert (poly);
}
EXPECT_EQ (r.space_check (1000).to_string (), "(20857,3600;20857,66000)/(19957,66000;19957,3600)");
EXPECT_EQ (r.space_check (1000).to_string (), "(20857,3600;20857,66000)|(19957,66000;19957,3600)");
}
TEST(15g)
@ -1235,14 +1235,14 @@ TEST(20)
{
db::Region r1 (db::RecursiveShapeIterator (ly, ly.cell (top), l2));
EXPECT_EQ (r1.width_check (20).to_string (), "(60,10;60,20)/(70,20;70,10);(60,20;70,20)/(70,10;60,10)");
EXPECT_EQ (r1.width_check (50).to_string (), "(60,10;60,20)/(70,20;70,10);(60,20;70,20)/(70,10;60,10);(10,10;10,40)/(40,40;40,10);(10,40;40,40)/(40,10;10,10);(80,70;140,70)/(140,40;80,40)");
EXPECT_EQ (r1.width_check (20).to_string (), "(60,10;60,20)|(70,20;70,10);(70,10;60,10)|(60,20;70,20)");
EXPECT_EQ (r1.width_check (50).to_string (), "(60,10;60,20)|(70,20;70,10);(70,10;60,10)|(60,20;70,20);(10,10;10,40)|(40,40;40,10);(40,10;10,10)|(10,40;40,40);(140,40;80,40)|(80,70;140,70)");
}
{
db::Region r1 (db::RecursiveShapeIterator (ly, ly.cell (top), l2));
EXPECT_EQ (r1.has_valid_polygons (), false);
EXPECT_EQ (r1.space_check (30).to_string (), "(40,40;40,10)/(60,10;60,20);(80,40;80,48)/(70,20;70,12);(92,40;80,40)/(60,20;70,20)");
EXPECT_EQ (r1.space_check (30).to_string (), "(60,10;60,20)|(40,40;40,10);(70,20;70,12)|(80,40;80,48);(60,20;70,20)|(92,40;80,40)");
EXPECT_EQ (r1.space_check (2).to_string (), "");
}

View File

@ -70,7 +70,40 @@ TEST(1_SimpleLShape)
db::EdgeRelationFilter er (db::WidthRelation, 1001, db::Projection);
db::edge2edge_check_with_negative_output<std::set<db::EdgePair>, std::set<db::Edge> > e2e (er, ep, ee1, ee2, false, false, false);
db::edge2edge_check_with_negative_output<std::set<db::EdgePair>, std::set<db::Edge> > e2e (er, ep, ee1, ee2, false, false, false, true);
db::Point pts[] = {
db::Point (0, 0),
db::Point (0, 2000),
db::Point (2000, 2000),
db::Point (2000, 1000),
db::Point (1000, 1000),
db::Point (1000, 0)
};
db::Polygon poly;
poly.assign_hull (pts, pts + sizeof (pts) / sizeof (pts[0]));
db::poly2poly_check<db::Polygon> poly_check (e2e);
do {
// single polygon check
poly_check.enter (poly, 0);
} while (e2e.prepare_next_pass ());
EXPECT_EQ (tl::to_string (ep), "(0,0;0,1000)|(1000,1000;1000,0),(2000,1000;1000,1000)|(1000,2000;2000,2000)");
EXPECT_EQ (tl::to_string (ee1), "");
EXPECT_EQ (tl::to_string (ee2), "");
}
TEST(1s_SimpleLShape)
{
std::set<db::EdgePair> ep;
std::set<db::Edge> ee1, ee2;
db::EdgeRelationFilter er (db::WidthRelation, 1001, db::Projection);
db::edge2edge_check_with_negative_output<std::set<db::EdgePair>, std::set<db::Edge> > e2e (er, ep, ee1, ee2, false, false, false, false);
db::Point pts[] = {
db::Point (0, 0),
@ -103,7 +136,7 @@ TEST(2_SimpleLWithBigPart)
db::EdgeRelationFilter er (db::WidthRelation, 1001, db::Projection);
db::edge2edge_check_with_negative_output<std::set<db::EdgePair>, std::set<db::Edge> > e2e (er, ep, ee1, ee2, false, false, false);
db::edge2edge_check_with_negative_output<std::set<db::EdgePair>, std::set<db::Edge> > e2e (er, ep, ee1, ee2, false, false, false, true);
db::Point pts[] = {
db::Point (0, 0),
@ -124,7 +157,7 @@ TEST(2_SimpleLWithBigPart)
poly_check.enter (poly, 0);
} while (e2e.prepare_next_pass ());
EXPECT_EQ (tl::to_string (ep), "(0,0;0,1000)/(1000,1000;1000,0)");
EXPECT_EQ (tl::to_string (ep), "(0,0;0,1000)|(1000,1000;1000,0)");
EXPECT_EQ (tl::to_string (ee1), "(0,1000;0,2500),(2000,1000;1000,1000),(0,2500;2000,2500),(2000,2500;2000,1000)");
EXPECT_EQ (tl::to_string (ee2), "");
}
@ -136,7 +169,7 @@ TEST(3_SimpleTWithBigPart)
db::EdgeRelationFilter er (db::WidthRelation, 1001, db::Projection);
db::edge2edge_check_with_negative_output<std::set<db::EdgePair>, std::set<db::Edge> > e2e (er, ep, ee1, ee2, false, false, false);
db::edge2edge_check_with_negative_output<std::set<db::EdgePair>, std::set<db::Edge> > e2e (er, ep, ee1, ee2, false, false, false, true);
db::Point pts[] = {
db::Point (0, 0),
@ -159,7 +192,7 @@ TEST(3_SimpleTWithBigPart)
poly_check.enter (poly, 0);
} while (e2e.prepare_next_pass ());
EXPECT_EQ (tl::to_string (ep), "(0,0;0,1000)/(1000,1000;1000,0),(0,2500;0,3500)/(1000,3500;1000,2500)");
EXPECT_EQ (tl::to_string (ep), "(0,0;0,1000)|(1000,1000;1000,0),(0,2500;0,3500)|(1000,3500;1000,2500)");
EXPECT_EQ (tl::to_string (ee1), "(0,1000;0,2500),(2000,1000;1000,1000),(1000,2500;2000,2500),(2000,2500;2000,1000)");
EXPECT_EQ (tl::to_string (ee2), "");
}
@ -171,7 +204,7 @@ TEST(4_SimpleNotch)
db::EdgeRelationFilter er (db::SpaceRelation, 1001, db::Projection);
db::edge2edge_check_with_negative_output<std::set<db::EdgePair>, std::set<db::Edge> > e2e (er, ep, ee1, ee2, false, false, false);
db::edge2edge_check_with_negative_output<std::set<db::EdgePair>, std::set<db::Edge> > e2e (er, ep, ee1, ee2, false, false, false, true);
db::Point pts[] = {
db::Point (0, 0),
@ -194,7 +227,7 @@ TEST(4_SimpleNotch)
poly_check.enter (poly, 0);
} while (e2e.prepare_next_pass ());
EXPECT_EQ (tl::to_string (ep), "(2000,2000;1000,2000)/(1000,1000;2000,1000)");
EXPECT_EQ (tl::to_string (ep), "(1000,1000;2000,1000)|(2000,2000;1000,2000)");
EXPECT_EQ (tl::to_string (ee1), "(0,0;0,3000),(2000,0;0,0),(2000,1000;2000,0),(0,3000;2000,3000),(2000,3000;2000,2000)");
EXPECT_EQ (tl::to_string (ee2), "");
}
@ -206,7 +239,7 @@ TEST(5_LShapeNotch)
db::EdgeRelationFilter er (db::SpaceRelation, 1001, db::Projection);
db::edge2edge_check_with_negative_output<std::set<db::EdgePair>, std::set<db::Edge> > e2e (er, ep, ee1, ee2, false, false, false);
db::edge2edge_check_with_negative_output<std::set<db::EdgePair>, std::set<db::Edge> > e2e (er, ep, ee1, ee2, false, false, false, true);
db::Point pts[] = {
db::Point (0, 0),
@ -231,7 +264,7 @@ TEST(5_LShapeNotch)
poly_check.enter (poly, 0);
} while (e2e.prepare_next_pass ());
EXPECT_EQ (tl::to_string (ep), "(1500,1500;1500,2500)/(500,2500;500,1500),(2000,1500;1500,1500)/(1500,500;2000,500)");
EXPECT_EQ (tl::to_string (ep), "(1500,500;2000,500)|(2000,1500;1500,1500),(1500,1500;1500,2500)|(500,2500;500,1500)");
EXPECT_EQ (tl::to_string (ee1), "(0,0;0,3000),(2000,0;0,0),(2000,500;2000,0),(0,3000;2000,3000),(2000,3000;2000,1500)");
EXPECT_EQ (tl::to_string (ee2), "");
}
@ -243,7 +276,7 @@ TEST(6_SeparationLvsBox)
db::EdgeRelationFilter er (db::SpaceRelation, 1001, db::Projection);
db::edge2edge_check_with_negative_output<std::set<db::EdgePair>, std::set<db::Edge> > e2e (er, ep, ee1, ee2, false, true /*different layers*/, false);
db::edge2edge_check_with_negative_output<std::set<db::EdgePair>, std::set<db::Edge> > e2e (er, ep, ee1, ee2, false, true /*different layers*/, false, false);
db::Point pts1[] = {
db::Point (0, 0),

View File

@ -1112,6 +1112,9 @@ CODE
#
# This method acts on edge pair expressions and returns the first edges of the
# edge pairs delivered by the expression.
#
# Some checks deliver symmetric edge pairs (e.g. space, width, etc.) for which the
# edges are commutable. "first_edges" will deliver both edges for such edge pairs.
# %DRC%
# @name second_edges
@ -1120,6 +1123,10 @@ CODE
#
# This method acts on edge pair expressions and returns the second edges of the
# edge pairs delivered by the expression.
#
# Some checks deliver symmetric edge pairs (e.g. space, width, etc.) for which the
# edges are commutable. "second_edges" will not deliver edges for such edge pairs.
# Instead, "first_edges" will deliver both.
def first_edges
DRCOpNodeFilter::new(@engine, self, :new_edge_pair_to_first_edges, "first_edges")

View File

@ -2755,6 +2755,9 @@ CODE
#
# Applies to edge pair collections only.
# Returns the first edges of the edge pairs in the collection.
#
# Some checks deliver symmetric edge pairs (e.g. space, width, etc.) for which the
# edges are commutable. "first_edges" will deliver both edges for such edge pairs.
# %DRC%
# @name second_edges
@ -2763,6 +2766,10 @@ CODE
#
# Applies to edge pair collections only.
# Returns the second edges of the edge pairs in the collection.
#
# Some checks deliver symmetric edge pairs (e.g. space, width, etc.) for which the
# edges are commutable. "second_edges" will not deliver edges for such edge pairs.
# Instead, "first_edges" will deliver both.
%w(first_edges second_edges).each do |f|
eval <<"CODE"

View File

@ -553,6 +553,9 @@ The plain function is equivalent to "primary.extents".
<p>
This method acts on edge pair expressions and returns the first edges of the
edge pairs delivered by the expression.
</p><p>
Some checks deliver symmetric edge pairs (e.g. space, width, etc.) for which the
edges are commutable. "first_edges" will deliver both edges for such edge pairs.
</p>
<a name="holes"/><h2>"holes" - Selects all holes from the input polygons</h2>
<keyword name="holes"/>
@ -860,6 +863,10 @@ The plain function is equivalent to "primary.rounded_corners".
<p>
This method acts on edge pair expressions and returns the second edges of the
edge pairs delivered by the expression.
</p><p>
Some checks deliver symmetric edge pairs (e.g. space, width, etc.) for which the
edges are commutable. "second_edges" will not deliver edges for such edge pairs.
Instead, "first_edges" will deliver both.
</p>
<a name="sized"/><h2>"sized" - Returns the sized version of the input</h2>
<keyword name="sized"/>

View File

@ -1032,6 +1032,9 @@ The following images show the effect of the extents method:
<p>
Applies to edge pair collections only.
Returns the first edges of the edge pairs in the collection.
</p><p>
Some checks deliver symmetric edge pairs (e.g. space, width, etc.) for which the
edges are commutable. "first_edges" will deliver both edges for such edge pairs.
</p>
<a name="flatten"/><h2>"flatten" - Flattens the layer</h2>
<keyword name="flatten"/>
@ -2178,6 +2181,10 @@ The following images shows the effect of the "scaled" method:
<p>
Applies to edge pair collections only.
Returns the second edges of the edge pairs in the collection.
</p><p>
Some checks deliver symmetric edge pairs (e.g. space, width, etc.) for which the
edges are commutable. "second_edges" will not deliver edges for such edge pairs.
Instead, "first_edges" will deliver both.
</p>
<a name="select"/><h2>"select" - Selects edges, edge pairs or polygons based on evaluation of a block</h2>
<keyword name="select"/>

View File

@ -20,6 +20,8 @@ l1.drc((space(projection) < 1.0).polygons).output(100, 0)
l1.drc((space(projection) < 1.0).edges).output(101, 0)
l1.drc((space(projection) < 1.0).first_edges).output(102, 0)
l1.drc((space(projection) < 1.0).second_edges).output(103, 0)
l1.drc((sep(l2, projection) < 1.0).first_edges).output(104, 0)
l1.drc((sep(l2, projection) < 1.0).second_edges).output(105, 0)
l2.drc(primary.edges).output(110, 0)
l2.drc(primary.edges.extended_in(0.1)).output(111, 0)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -163,6 +163,53 @@ class DBEdgePair_TestClass < TestBase
end
# Symmetric edge pairs
def test_5
b1 = RBA::DEdgePair::new(RBA::DEdge::new(1, 2, 3, 4), RBA::DEdge::new(11, 12, 13, 14), false)
b1x = RBA::DEdgePair::new(RBA::DEdge::new(11, 12, 13, 14), RBA::DEdge::new(1, 2, 3, 4), false)
b2a = RBA::DEdgePair::new(RBA::DEdge::new(1, 2, 3, 4), RBA::DEdge::new(11, 12, 13, 14), true)
b2b = RBA::DEdgePair::new(RBA::DEdge::new(11, 12, 13, 14), RBA::DEdge::new(1, 2, 3, 4), true)
assert_equal(b1.hash == b1x.hash, false)
assert_equal(b1.hash == b2a.hash, false)
assert_equal(b1.hash == b2b.hash, false)
assert_equal(b2a.hash == b2b.hash, true)
assert_equal(b1 < b1x, true)
assert_equal(b1 == b1x, false)
assert_equal(b1 < b2a, true)
assert_equal(b1 == b2a, false)
assert_equal(b1 < b2b, true)
assert_equal(b2a < b2b, false)
assert_equal(b2a == b2b, true)
assert_equal(b2b < b2a, false)
assert_equal(b1.to_s, "(1,2;3,4)/(11,12;13,14)")
assert_equal(b1x.to_s, "(11,12;13,14)/(1,2;3,4)")
assert_equal(b2a.to_s, "(1,2;3,4)|(11,12;13,14)")
assert_equal(b2b.to_s, "(1,2;3,4)|(11,12;13,14)")
h = {}
h[b1] = 1
h[b1x] = 2
assert_equal(h.size, 2)
assert_equal(h.keys.collect(&:to_s).join(","), "(1,2;3,4)/(11,12;13,14),(11,12;13,14)/(1,2;3,4)")
h = {}
h[b1] = 1
h[b2a] = 2
assert_equal(h.size, 2)
assert_equal(h.keys.collect(&:to_s).join(","), "(1,2;3,4)/(11,12;13,14),(1,2;3,4)|(11,12;13,14)")
h = {}
h[b2a] = 1
h[b2b] = 2
assert_equal(h.size, 1)
assert_equal(h.keys.collect(&:to_s).join(","), "(1,2;3,4)|(11,12;13,14)")
end
end
load("test_epilogue.rb")

View File

@ -478,38 +478,38 @@ class DBRegion_TestClass < TestBase
assert_equal(r3b.overlap_check(r1, 15, false, RBA::Region::Projection, nil, 380, 500).to_s, "")
assert_equal(r3b.overlap_check(r1, 15, false, RBA::Region::Projection, nil, 0, 300).to_s, "(0,10;10,10)/(10,0;0,0);(10,10;10,0)/(0,0;0,10)")
assert_equal((r1 | r2).merged.isolated_check(25).to_s, "(120,20;120,380)/(100,395;100,5)")
assert_equal((r1 | r2).merged.isolated_check(25, false, RBA::Region::Projection, nil, nil, nil).to_s, "(120,20;120,380)/(100,380;100,20)")
assert_equal((r1 | r2).merged.isolated_check(25, false, RBA::Region::Square, nil, nil, nil).to_s, "(120,20;120,380)/(100,400;100,0)")
assert_equal((r1 | r2).merged.isolated_check(25, false, RBA::Region::Euclidian, nil, nil, nil).to_s, "(120,20;120,380)/(100,395;100,5)")
assert_equal((r1 | r2).merged.isolated_check(25, true, RBA::Region::Euclidian, nil, nil, nil).to_s, "(120,20;120,380)/(100,400;100,0)")
assert_equal((r1 | r2).merged.isolated_check(25).to_s, "(120,20;120,380)|(100,395;100,5)")
assert_equal((r1 | r2).merged.isolated_check(25, false, RBA::Region::Projection, nil, nil, nil).to_s, "(120,20;120,380)|(100,380;100,20)")
assert_equal((r1 | r2).merged.isolated_check(25, false, RBA::Region::Square, nil, nil, nil).to_s, "(120,20;120,380)|(100,400;100,0)")
assert_equal((r1 | r2).merged.isolated_check(25, false, RBA::Region::Euclidian, nil, nil, nil).to_s, "(120,20;120,380)|(100,395;100,5)")
assert_equal((r1 | r2).merged.isolated_check(25, true, RBA::Region::Euclidian, nil, nil, nil).to_s, "(120,20;120,380)|(100,400;100,0)")
assert_equal((r1 | r2).merged.isolated_check(25, false, RBA::Region::Euclidian, 0.0, nil, nil).to_s, "")
assert_equal((r1 | r2).merged.isolated_check(25, false, RBA::Region::Euclidian, nil, 0, 300).to_s, "")
assert_equal((r1 | r2).merged.isolated_check(25, false, RBA::Region::Euclidian, nil, 300, 500).to_s, "(120,20;120,380)/(100,395;100,5)")
assert_equal((r1 | r2).merged.isolated_check(25, false, RBA::Region::Euclidian, nil, 300, nil).to_s, "(120,20;120,380)/(100,395;100,5)")
assert_equal((r1 | r2).merged.isolated_check(25, false, RBA::Region::Euclidian, nil, 300, 500).to_s, "(120,20;120,380)|(100,395;100,5)")
assert_equal((r1 | r2).merged.isolated_check(25, false, RBA::Region::Euclidian, nil, 300, nil).to_s, "(120,20;120,380)|(100,395;100,5)")
assert_equal((r1 | r2).merged.notch_check(25).to_s, "(0,200;50,200)/(50,220;10,220)")
assert_equal((r1 | r2).merged.notch_check(25, false, RBA::Region::Projection, nil, nil, nil).to_s, "(10,200;50,200)/(50,220;10,220)")
assert_equal((r1 | r2).merged.notch_check(25, true, RBA::Region::Projection, nil, nil, nil).to_s, "(0,200;50,200)/(50,220;10,220)")
assert_equal((r1 | r2).merged.notch_check(25).to_s, "(0,200;50,200)|(50,220;10,220)")
assert_equal((r1 | r2).merged.notch_check(25, false, RBA::Region::Projection, nil, nil, nil).to_s, "(10,200;50,200)|(50,220;10,220)")
assert_equal((r1 | r2).merged.notch_check(25, true, RBA::Region::Projection, nil, nil, nil).to_s, "(0,200;50,200)|(50,220;10,220)")
assert_equal((r1 | r2).merged.notch_check(25, true, RBA::Region::Projection, 0.0, nil, nil).to_s, "")
assert_equal((r1 | r2).merged.notch_check(25, true, RBA::Region::Projection, nil, 40, nil).to_s, "(0,200;50,200)/(50,220;10,220)")
assert_equal((r1 | r2).merged.notch_check(25, true, RBA::Region::Projection, nil, 40, nil).to_s, "(0,200;50,200)|(50,220;10,220)")
assert_equal((r1 | r2).merged.notch_check(25, true, RBA::Region::Projection, nil, 50, nil).to_s, "")
assert_equal((r1 | r2).merged.notch_check(25, true, RBA::Region::Projection, nil, 40, 50).to_s, "(0,200;50,200)/(50,220;10,220)")
assert_equal((r1 | r2).merged.notch_check(25, true, RBA::Region::Projection, nil, 40, 50).to_s, "(0,200;50,200)|(50,220;10,220)")
assert_equal((r1 | r2).merged.notch_check(25, true, RBA::Region::Projection, nil, nil, 40).to_s, "")
assert_equal((r1 | r2).merged.space_check(25).to_s, "(100,395;100,5)/(120,20;120,380);(0,200;50,200)/(50,220;10,220)")
assert_equal((r1 | r2).merged.space_check(25, false, RBA::Region::Projection, nil, nil, nil).to_s, "(100,380;100,20)/(120,20;120,380);(10,200;50,200)/(50,220;10,220)")
assert_equal((r1 | r2).merged.space_check(25, true, RBA::Region::Projection, nil, nil, nil).to_s, "(100,400;100,0)/(120,20;120,380);(0,200;50,200)/(50,220;10,220)")
assert_equal((r1 | r2).merged.space_check(25).to_s, "(120,20;120,380)|(100,395;100,5);(0,200;50,200)|(50,220;10,220)")
assert_equal((r1 | r2).merged.space_check(25, false, RBA::Region::Projection, nil, nil, nil).to_s, "(120,20;120,380)|(100,380;100,20);(10,200;50,200)|(50,220;10,220)")
assert_equal((r1 | r2).merged.space_check(25, true, RBA::Region::Projection, nil, nil, nil).to_s, "(120,20;120,380)|(100,400;100,0);(0,200;50,200)|(50,220;10,220)")
assert_equal((r1 | r2).merged.space_check(25, true, RBA::Region::Projection, 0.0, nil, nil).to_s, "")
assert_equal((r1 | r2).merged.space_check(25, true, RBA::Region::Projection, nil, 50, nil).to_s, "(100,400;100,0)/(120,20;120,380)")
assert_equal((r1 | r2).merged.space_check(25, true, RBA::Region::Projection, nil, nil, 50).to_s, "(0,200;50,200)/(50,220;10,220)")
assert_equal((r1 | r2).merged.space_check(25, true, RBA::Region::Projection, nil, 50, nil).to_s, "(120,20;120,380)|(100,400;100,0)")
assert_equal((r1 | r2).merged.space_check(25, true, RBA::Region::Projection, nil, nil, 50).to_s, "(0,200;50,200)|(50,220;10,220)")
assert_equal((r1 | r2).merged.width_check(60).to_s, "(120,20;120,380)/(130,380;130,20);(50,200;50,220)/(100,253;100,167)")
assert_equal((r1 | r2).merged.width_check(60, false, RBA::Region::Projection, nil, nil, nil).to_s, "(120,20;120,380)/(130,380;130,20);(50,200;50,220)/(100,220;100,200)")
assert_equal((r1 | r2).merged.width_check(60, true, RBA::Region::Projection, nil, nil, nil).to_s, "(120,20;120,380)/(130,380;130,20);(50,200;50,220)/(100,400;100,0)")
assert_equal((r1 | r2).merged.width_check(60).to_s, "(120,20;120,380)|(130,380;130,20);(50,200;50,220)|(100,253;100,167)")
assert_equal((r1 | r2).merged.width_check(60, false, RBA::Region::Projection, nil, nil, nil).to_s, "(120,20;120,380)|(130,380;130,20);(50,200;50,220)|(100,220;100,200)")
assert_equal((r1 | r2).merged.width_check(60, true, RBA::Region::Projection, nil, nil, nil).to_s, "(120,20;120,380)|(130,380;130,20);(50,200;50,220)|(100,400;100,0)")
assert_equal((r1 | r2).merged.width_check(60, true, RBA::Region::Projection, 0.0, nil, nil).to_s, "")
assert_equal((r1 | r2).merged.width_check(60, true, RBA::Region::Projection, nil, 50, nil).to_s, "(120,20;120,380)/(130,380;130,20)")
assert_equal((r1 | r2).merged.width_check(60, true, RBA::Region::Projection, nil, nil, 50).to_s, "(50,200;50,220)/(100,400;100,0)")
assert_equal((r1 | r2).merged.width_check(60, true, RBA::Region::Projection, nil, 50, nil).to_s, "(120,20;120,380)|(130,380;130,20)")
assert_equal((r1 | r2).merged.width_check(60, true, RBA::Region::Projection, nil, nil, 50).to_s, "(50,200;50,220)|(100,400;100,0)")
end