Merge branch 'issue-374' into drc-enhancements

This commit is contained in:
Matthias Koefferlein 2020-06-05 14:07:01 +02:00
commit 689b3c5af9
4 changed files with 229 additions and 49 deletions

View File

@ -810,7 +810,7 @@ AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons,
check.set_min_projection (min_projection); check.set_min_projection (min_projection);
check.set_max_projection (max_projection); check.set_max_projection (max_projection);
edge2edge_check<db::FlatEdgePairs> edge_check (check, *result, different_polygons, other != 0); edge2edge_check<db::FlatEdgePairs> edge_check (check, *result, different_polygons, other != 0 /*requires different layers*/, true /*shielded*/);
poly2poly_check<db::FlatEdgePairs> poly_check (edge_check); poly2poly_check<db::FlatEdgePairs> poly_check (edge_check);
do { do {
@ -832,7 +832,7 @@ AsIfFlatRegion::run_single_polygon_check (db::edge_relation_type rel, db::Coord
check.set_min_projection (min_projection); check.set_min_projection (min_projection);
check.set_max_projection (max_projection); check.set_max_projection (max_projection);
edge2edge_check<db::FlatEdgePairs> edge_check (check, *result, false, false); edge2edge_check<db::FlatEdgePairs> edge_check (check, *result, false /*=same polygons*/, false /*=same layers*/, true /*shielded*/);
poly2poly_check<db::FlatEdgePairs> poly_check (edge_check); poly2poly_check<db::FlatEdgePairs> poly_check (edge_check);
do { do {

View File

@ -1269,7 +1269,7 @@ public:
virtual void compute_local (db::Layout * /*layout*/, const shape_interactions<db::PolygonRef, db::PolygonRef> &interactions, std::unordered_set<db::EdgePair> &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const virtual void compute_local (db::Layout * /*layout*/, const shape_interactions<db::PolygonRef, db::PolygonRef> &interactions, std::unordered_set<db::EdgePair> &result, size_t /*max_vertex_count*/, double /*area_ratio*/) const
{ {
edge2edge_check<std::unordered_set<db::EdgePair> > edge_check (m_check, result, m_different_polygons, m_has_other); edge2edge_check<std::unordered_set<db::EdgePair> > edge_check (m_check, result, m_different_polygons, m_has_other, true /*shielded*/);
poly2poly_check<std::unordered_set<db::EdgePair> > poly_check (edge_check); poly2poly_check<std::unordered_set<db::EdgePair> > poly_check (edge_check);
std::list<db::Polygon> heap; std::list<db::Polygon> heap;
@ -1408,7 +1408,7 @@ DeepRegion::run_single_polygon_check (db::edge_relation_type rel, db::Coord d, b
for (db::Shapes::shape_iterator s = shapes.begin (db::ShapeIterator::Polygons); ! s.at_end (); ++s) { for (db::Shapes::shape_iterator s = shapes.begin (db::ShapeIterator::Polygons); ! s.at_end (); ++s) {
edge2edge_check<db::Shapes> edge_check (check, result, false, false); edge2edge_check<db::Shapes> edge_check (check, result, false, false, true /*shielded*/);
poly2poly_check<db::Shapes> poly_check (edge_check); poly2poly_check<db::Shapes> poly_check (edge_check);
db::Polygon poly; db::Polygon poly;

View File

@ -22,6 +22,7 @@
#include "dbRegionUtils.h" #include "dbRegionUtils.h"
#include "dbEdgeBoolean.h"
#include "tlSelect.h" #include "tlSelect.h"
namespace db namespace db
@ -30,9 +31,9 @@ namespace db
// ------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------
// Edge2EdgeCheckBase implementation // Edge2EdgeCheckBase implementation
Edge2EdgeCheckBase::Edge2EdgeCheckBase (const EdgeRelationFilter &check, bool different_polygons, bool requires_different_layers) Edge2EdgeCheckBase::Edge2EdgeCheckBase (const EdgeRelationFilter &check, bool different_polygons, bool requires_different_layers, bool with_shielding)
: mp_check (&check), m_requires_different_layers (requires_different_layers), m_different_polygons (different_polygons), : mp_check (&check), m_requires_different_layers (requires_different_layers), m_different_polygons (different_polygons),
m_pass (0) m_with_shielding (with_shielding), m_has_edge_pair_output (true), m_has_negative_edge_output (false), m_pass (0)
{ {
m_distance = check.distance (); m_distance = check.distance ();
} }
@ -44,22 +45,29 @@ Edge2EdgeCheckBase::prepare_next_pass ()
if (m_pass == 1) { if (m_pass == 1) {
if (! m_ep.empty ()) { if (m_with_shielding && ! m_ep.empty ()) {
m_ep_discarded.resize (m_ep.size (), false); m_ep_discarded.resize (m_ep.size (), false);
return true; return true;
} }
} else if (m_pass == 2) { } else if (m_pass == 2) {
std::vector<bool>::const_iterator d = m_ep_discarded.begin (); if (m_has_edge_pair_output) {
std::vector<db::EdgePair>::const_iterator ep = m_ep.begin ();
while (ep != m_ep.end ()) { std::vector<bool>::const_iterator d = m_ep_discarded.begin ();
tl_assert (d != m_ep_discarded.end ()); std::vector<db::EdgePair>::const_iterator ep = m_ep.begin ();
if (! *d) { while (ep != m_ep.end ()) {
put (*ep); bool use_result = true;
if (d != m_ep_discarded.end ()) {
use_result = ! *d;
++d;
}
if (use_result) {
put (*ep);
}
++ep;
} }
++d;
++ep;
} }
} }
@ -82,6 +90,18 @@ static inline bool shields (const db::EdgePair &ep, const db::Edge &q)
} }
} }
void
Edge2EdgeCheckBase::finish (const Edge *o, const size_t &p)
{
if (m_has_negative_edge_output && m_pass == 1) {
// no interaction at all: create a single-edged edge pair
int l = int (p & size_t (1));
put_negative (*o, l);
}
}
void void
Edge2EdgeCheckBase::add (const db::Edge *o1, size_t p1, const db::Edge *o2, size_t p2) Edge2EdgeCheckBase::add (const db::Edge *o1, size_t p1, const db::Edge *o2, size_t p2)
{ {
@ -99,7 +119,8 @@ Edge2EdgeCheckBase::add (const db::Edge *o1, size_t p1, const db::Edge *o2, size
if (mp_check->check (l1 <= l2 ? *o1 : *o2, l1 <= l2 ? *o2 : *o1, &ep)) { if (mp_check->check (l1 <= l2 ? *o1 : *o2, l1 <= l2 ? *o2 : *o1, &ep)) {
// found a violation: store inside the local buffer for now. In the second // found a violation: store inside the local buffer for now. In the second
// pass we will eliminate those which are shielded completely. // pass we will eliminate those which are shielded completely (with shielding)
// and/or compute the negative edges.
size_t n = m_ep.size (); size_t n = m_ep.size ();
m_ep.push_back (ep); m_ep.push_back (ep);
m_e2ep.insert (std::make_pair (std::make_pair (*o1, p1), n)); m_e2ep.insert (std::make_pair (std::make_pair (*o1, p1), n));
@ -111,48 +132,97 @@ Edge2EdgeCheckBase::add (const db::Edge *o1, size_t p1, const db::Edge *o2, size
} else { } else {
// a simple (complete) shielding implementation which is based on the // set the discarded flags for shielded output
// assumption that shielding is relevant as soon as a foreign edge cuts through if (m_with_shielding) {
// both of the edge pair's connecting edges.
// TODO: this implementation does not take into account the nature of the // a simple (complete) shielding implementation which is based on the
// EdgePair - because of "whole_edge" it may not reflect the part actually // assumption that shielding is relevant as soon as a foreign edge cuts through
// violating the distance. // both of the edge pair's connecting edges.
std::vector<size_t> n1, n2; // TODO: this implementation does not take into account the nature of the
// EdgePair - because of "whole_edge" it may not reflect the part actually
// violating the distance.
for (unsigned int p = 0; p < 2; ++p) { std::vector<size_t> n1, n2;
for (unsigned int p = 0; p < 2; ++p) {
std::pair<db::Edge, size_t> k (*o1, p1);
for (std::multimap<std::pair<db::Edge, size_t>, size_t>::const_iterator i = m_e2ep.find (k); i != m_e2ep.end () && i->first == k; ++i) {
n1.push_back (i->second);
}
std::sort (n1.begin (), n1.end ());
std::swap (o1, o2);
std::swap (p1, p2);
n1.swap (n2);
std::pair<db::Edge, size_t> k (*o1, p1);
for (std::multimap<std::pair<db::Edge, size_t>, size_t>::const_iterator i = m_e2ep.find (k); i != m_e2ep.end () && i->first == k; ++i) {
n1.push_back (i->second);
} }
std::sort (n1.begin (), n1.end ()); for (unsigned int p = 0; p < 2; ++p) {
std::swap (o1, o2); std::vector<size_t> nn;
std::swap (p1, p2); std::set_difference (n1.begin (), n1.end (), n2.begin (), n2.end (), std::back_inserter (nn));
n1.swap (n2);
for (std::vector<size_t>::const_iterator i = nn.begin (); i != nn.end (); ++i) {
if (! m_ep_discarded [*i]) {
db::EdgePair ep = m_ep [*i].normalized ();
if (shields (ep, *o2)) {
m_ep_discarded [*i] = true;
}
}
}
std::swap (o1, o2);
std::swap (p1, p2);
n1.swap (n2);
}
} }
for (unsigned int p = 0; p < 2; ++p) { // prepare the negative edge output
if (m_has_negative_edge_output) {
std::vector<size_t> nn; // Overlap or inside checks require input from different layers
std::set_difference (n1.begin (), n1.end (), n2.begin (), n2.end (), std::back_inserter (nn)); if ((! m_different_polygons || p1 != p2) && (! m_requires_different_layers || ((p1 ^ p2) & 1) != 0)) {
for (std::vector<size_t>::const_iterator i = nn.begin (); i != nn.end (); ++i) { for (int p = 0; p < 2; ++p) {
if (! m_ep_discarded [*i]) {
db::EdgePair ep = m_ep [*i].normalized (); std::pair<db::Edge, size_t> k (*o1, p1);
if (shields (ep, *o2)) { std::multimap<std::pair<db::Edge, size_t>, size_t>::const_iterator i0 = m_e2ep.find (k);
m_ep_discarded [*i] = true;
bool fully_removed = false;
for (std::multimap<std::pair<db::Edge, size_t>, size_t>::const_iterator i = i0; ! fully_removed && i != m_e2ep.end () && i->first == k; ++i) {
fully_removed = (m_ep [i->second].first () == *o1);
} }
}
}
std::swap (o1, o2); if (! fully_removed) {
std::swap (p1, p2);
n1.swap (n2); std::set<db::Edge> partial_edges;
db::EdgeBooleanCluster<std::set<db::Edge> > ec (&partial_edges, db::EdgeNot);
ec.add (o1, 0);
for (std::multimap<std::pair<db::Edge, size_t>, size_t>::const_iterator i = i0; i != m_e2ep.end () && i->first == k; ++i) {
ec.add (&m_ep [i->second].first (), 1);
}
ec.finish ();
for (std::set<db::Edge>::const_iterator e = partial_edges.begin (); e != partial_edges.end (); ++e) {
put_negative (*e, p);
}
std::swap (o1, o2);
std::swap (p1, p2);
}
}
}
} }

View File

@ -368,7 +368,7 @@ class DB_PUBLIC Edge2EdgeCheckBase
: public db::box_scanner_receiver<db::Edge, size_t> : public db::box_scanner_receiver<db::Edge, size_t>
{ {
public: public:
Edge2EdgeCheckBase (const EdgeRelationFilter &check, bool different_polygons, bool requires_different_layers); Edge2EdgeCheckBase (const EdgeRelationFilter &check, bool different_polygons, bool requires_different_layers, bool with_shielding);
/** /**
* @brief Call this to initiate a new pass until the return value is false * @brief Call this to initiate a new pass until the return value is false
@ -380,6 +380,11 @@ public:
*/ */
void add (const db::Edge *o1, size_t p1, const db::Edge *o2, size_t p2); void add (const db::Edge *o1, size_t p1, const db::Edge *o2, size_t p2);
/**
* @brief Reimplementation of the box_scanner_receiver interface
*/
void finish (const Edge *o, const size_t &);
/** /**
* @brief Gets a value indicating whether the check requires different layers * @brief Gets a value indicating whether the check requires different layers
*/ */
@ -400,13 +405,37 @@ public:
*/ */
void set_different_polygons (bool f); void set_different_polygons (bool f);
/**
* @brief Sets a flag indicating that this class wants negative edge output
*/
void set_has_negative_edge_output (bool f)
{
m_has_negative_edge_output = f;
}
/**
* @brief Sets a flag indicating that this class wants normal edge pair output
*/
void set_has_edge_pair_output (bool f)
{
m_has_edge_pair_output = f;
}
/** /**
* @brief Gets the distance value * @brief Gets the distance value
*/ */
EdgeRelationFilter::distance_type distance () const; EdgeRelationFilter::distance_type distance () const;
protected: protected:
virtual void put (const db::EdgePair &edge) const = 0; /**
* @brief Normal edge pair output (violations)
*/
virtual void put (const db::EdgePair & /*edge*/) const { }
/**
* @brief Negative edge output
*/
virtual void put_negative (const db::Edge & /*edge*/, int /*layer*/) const { }
private: private:
const EdgeRelationFilter *mp_check; const EdgeRelationFilter *mp_check;
@ -416,19 +445,24 @@ private:
std::vector<db::EdgePair> m_ep; std::vector<db::EdgePair> m_ep;
std::multimap<std::pair<db::Edge, size_t>, size_t> m_e2ep; std::multimap<std::pair<db::Edge, size_t>, size_t> m_e2ep;
std::vector<bool> m_ep_discarded; std::vector<bool> m_ep_discarded;
bool m_with_shielding;
bool m_has_edge_pair_output;
bool m_has_negative_edge_output;
unsigned int m_pass; unsigned int m_pass;
}; };
/** /**
* @brief A helper class for the DRC functionality which acts as an edge pair receiver * @brief A helper class for the DRC functionality
*
* This class implements the edge-to-edge part of the polygon DRC.
*/ */
template <class Output> template <class Output>
class DB_PUBLIC_TEMPLATE edge2edge_check class DB_PUBLIC_TEMPLATE edge2edge_check
: public Edge2EdgeCheckBase : public Edge2EdgeCheckBase
{ {
public: public:
edge2edge_check (const EdgeRelationFilter &check, Output &output, bool different_polygons, bool requires_different_layers) edge2edge_check (const EdgeRelationFilter &check, Output &output, bool different_polygons, bool requires_different_layers, bool with_shielding)
: Edge2EdgeCheckBase (check, different_polygons, requires_different_layers), mp_output (&output) : Edge2EdgeCheckBase (check, different_polygons, requires_different_layers, with_shielding), mp_output (&output)
{ {
// .. nothing yet .. // .. nothing yet ..
} }
@ -443,6 +477,82 @@ private:
Output *mp_output; Output *mp_output;
}; };
/**
* @brief A helper class for the DRC functionality
*
* This class implements the edge-to-edge part of the polygon DRC.
* This version allows delivery of the negative edges.
*/
template <class Output, class NegativeEdgeOutput>
class DB_PUBLIC_TEMPLATE edge2edge_check_with_negative_output
: public Edge2EdgeCheckBase
{
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)
: Edge2EdgeCheckBase (check, different_polygons, requires_different_layers, with_shielding),
mp_output (&output),
mp_l1_negative_output (&l1_negative_output),
mp_l2_negative_output (&l2_negative_output)
{
set_has_negative_edge_output (true);
}
protected:
void put (const db::EdgePair &ep) const
{
mp_output->insert (ep);
}
void put_negative (const db::Edge &edge, int layer) const
{
if (layer == 0) {
mp_l1_negative_output->insert (edge);
}
if (layer == 1) {
mp_l2_negative_output->insert (edge);
}
}
private:
Output *mp_output;
NegativeEdgeOutput *mp_l1_negative_output, *mp_l2_negative_output;
};
/**
* @brief A helper class for the DRC functionality
*
* This class implements the edge-to-edge part of the polygon DRC.
* This version has only negative edge output.
*/
template <class Output, class NegativeEdgeOutput>
class DB_PUBLIC_TEMPLATE edge2edge_check_negative
: public Edge2EdgeCheckBase
{
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),
mp_l1_negative_output (&l1_negative_output),
mp_l2_negative_output (&l2_negative_output)
{
set_has_negative_edge_output (true);
set_has_edge_pair_output (false);
}
protected:
void put_negative (const db::Edge &edge, int layer) const
{
if (layer == 0) {
mp_l1_negative_output->insert (edge);
}
if (layer == 1) {
mp_l2_negative_output->insert (edge);
}
}
private:
NegativeEdgeOutput *mp_l1_negative_output, *mp_l2_negative_output;
};
/** /**
* @brief A helper class for the DRC functionality which acts as an edge pair receiver * @brief A helper class for the DRC functionality which acts as an edge pair receiver
*/ */