mirror of https://github.com/KLayout/klayout.git
WIP: preparations for an extended width/space concept
This commit is contained in:
parent
9f4ccaaedc
commit
476a2b3f09
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
|
||||
#include "dbRegionUtils.h"
|
||||
#include "dbEdgeBoolean.h"
|
||||
#include "tlSelect.h"
|
||||
|
||||
namespace db
|
||||
|
|
@ -30,9 +31,9 @@ namespace db
|
|||
// -------------------------------------------------------------------------------------
|
||||
// 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),
|
||||
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 ();
|
||||
}
|
||||
|
|
@ -44,22 +45,29 @@ Edge2EdgeCheckBase::prepare_next_pass ()
|
|||
|
||||
if (m_pass == 1) {
|
||||
|
||||
if (! m_ep.empty ()) {
|
||||
if (m_with_shielding && ! m_ep.empty ()) {
|
||||
m_ep_discarded.resize (m_ep.size (), false);
|
||||
return true;
|
||||
}
|
||||
|
||||
} else if (m_pass == 2) {
|
||||
|
||||
std::vector<bool>::const_iterator d = m_ep_discarded.begin ();
|
||||
std::vector<db::EdgePair>::const_iterator ep = m_ep.begin ();
|
||||
while (ep != m_ep.end ()) {
|
||||
tl_assert (d != m_ep_discarded.end ());
|
||||
if (! *d) {
|
||||
put (*ep);
|
||||
if (m_has_edge_pair_output) {
|
||||
|
||||
std::vector<bool>::const_iterator d = m_ep_discarded.begin ();
|
||||
std::vector<db::EdgePair>::const_iterator ep = m_ep.begin ();
|
||||
while (ep != m_ep.end ()) {
|
||||
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
|
||||
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)) {
|
||||
|
||||
// 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 ();
|
||||
m_ep.push_back (ep);
|
||||
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 {
|
||||
|
||||
// a simple (complete) shielding implementation which is based on the
|
||||
// assumption that shielding is relevant as soon as a foreign edge cuts through
|
||||
// both of the edge pair's connecting edges.
|
||||
// set the discarded flags for shielded output
|
||||
if (m_with_shielding) {
|
||||
|
||||
// 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.
|
||||
// a simple (complete) shielding implementation which is based on the
|
||||
// assumption that shielding is relevant as soon as a foreign edge cuts through
|
||||
// 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::swap (p1, p2);
|
||||
n1.swap (n2);
|
||||
std::vector<size_t> nn;
|
||||
std::set_difference (n1.begin (), n1.end (), n2.begin (), n2.end (), std::back_inserter (nn));
|
||||
|
||||
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;
|
||||
std::set_difference (n1.begin (), n1.end (), n2.begin (), n2.end (), std::back_inserter (nn));
|
||||
// Overlap or inside checks require input from different layers
|
||||
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) {
|
||||
if (! m_ep_discarded [*i]) {
|
||||
db::EdgePair ep = m_ep [*i].normalized ();
|
||||
if (shields (ep, *o2)) {
|
||||
m_ep_discarded [*i] = true;
|
||||
for (int p = 0; p < 2; ++p) {
|
||||
|
||||
std::pair<db::Edge, size_t> k (*o1, p1);
|
||||
std::multimap<std::pair<db::Edge, size_t>, size_t>::const_iterator i0 = m_e2ep.find (k);
|
||||
|
||||
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);
|
||||
std::swap (p1, p2);
|
||||
n1.swap (n2);
|
||||
if (! fully_removed) {
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -368,7 +368,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);
|
||||
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
|
||||
|
|
@ -380,6 +380,11 @@ public:
|
|||
*/
|
||||
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
|
||||
*/
|
||||
|
|
@ -400,13 +405,37 @@ public:
|
|||
*/
|
||||
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
|
||||
*/
|
||||
EdgeRelationFilter::distance_type distance () const;
|
||||
|
||||
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:
|
||||
const EdgeRelationFilter *mp_check;
|
||||
|
|
@ -416,19 +445,24 @@ private:
|
|||
std::vector<db::EdgePair> m_ep;
|
||||
std::multimap<std::pair<db::Edge, size_t>, size_t> m_e2ep;
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
* @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>
|
||||
class DB_PUBLIC_TEMPLATE edge2edge_check
|
||||
: public Edge2EdgeCheckBase
|
||||
{
|
||||
public:
|
||||
edge2edge_check (const EdgeRelationFilter &check, Output &output, bool different_polygons, bool requires_different_layers)
|
||||
: Edge2EdgeCheckBase (check, different_polygons, requires_different_layers), mp_output (&output)
|
||||
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 (&output)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
|
@ -443,6 +477,82 @@ private:
|
|||
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
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in New Issue