First steps towards hiearchical DRC - needs testing.

This commit is contained in:
Matthias Koefferlein 2019-02-16 00:35:29 +01:00
parent 6e35e80963
commit 5a994fef6d
4 changed files with 401 additions and 277 deletions

View File

@ -701,11 +701,12 @@ namespace
*
* If will perform a edge by edge check using the provided EdgeRelationFilter
*/
class Edge2EdgeCheck
template <class Output>
class edge2edge_check_for_edges
: public db::box_scanner_receiver<db::Edge, size_t>
{
public:
Edge2EdgeCheck (const EdgeRelationFilter &check, EdgePairs &output, bool requires_different_layers)
edge2edge_check_for_edges (const EdgeRelationFilter &check, Output &output, bool requires_different_layers)
: mp_check (&check), mp_output (&output)
{
m_requires_different_layers = requires_different_layers;
@ -731,7 +732,7 @@ public:
private:
const EdgeRelationFilter *mp_check;
EdgePairs *mp_output;
Output *mp_output;
bool m_requires_different_layers;
};
@ -771,7 +772,7 @@ AsIfFlatEdges::run_check (db::edge_relation_type rel, const Edges *other, db::Co
check.set_min_projection (min_projection);
check.set_max_projection (max_projection);
Edge2EdgeCheck edge_check (check, result, other != 0);
edge2edge_check_for_edges<db::EdgePairs> edge_check (check, result, other != 0);
scanner.process (edge_check, d, db::box_convert<db::Edge> ());
return result;

View File

@ -595,271 +595,6 @@ AsIfFlatRegion::strange_polygon_check () const
return new_region.release ();
}
namespace {
/**
* @brief A helper class for the DRC functionality which acts as an edge pair receiver
*/
class Edge2EdgeCheck
: public db::box_scanner_receiver<db::Edge, size_t>
{
public:
Edge2EdgeCheck (const EdgeRelationFilter &check, EdgePairs &output, bool different_polygons, bool requires_different_layers)
: mp_check (&check), mp_output (&output), m_requires_different_layers (requires_different_layers), m_different_polygons (different_polygons),
m_pass (0)
{
m_distance = check.distance ();
}
bool prepare_next_pass ()
{
++m_pass;
if (m_pass == 1) {
if (! 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) {
mp_output->insert (*ep);
}
++d;
++ep;
}
}
return false;
}
void 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)) {
// ensure that the first check argument is of layer 1 and the second of
// layer 2 (unless both are of the same layer)
int l1 = int (p1 & size_t (1));
int l2 = int (p2 & size_t (1));
db::EdgePair 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
// pass we will eliminate those which are shielded completely.
size_t n = m_ep.size ();
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 (*o2, p2), n));
}
}
} 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.
// 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.
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);
}
for (unsigned int p = 0; p < 2; ++p) {
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 (db::Edge (ep.first ().p1 (), ep.second ().p2 ()).intersect (*o2) &&
db::Edge (ep.second ().p1 (), ep.first ().p2 ()).intersect (*o2)) {
m_ep_discarded [*i] = true;
}
}
}
std::swap (o1, o2);
std::swap (p1, p2);
n1.swap (n2);
}
}
}
/**
* @brief Gets a value indicating whether the check requires different layers
*/
bool requires_different_layers () const
{
return m_requires_different_layers;
}
/**
* @brief Sets a value indicating whether the check requires different layers
*/
void set_requires_different_layers (bool f)
{
m_requires_different_layers = f;
}
/**
* @brief Gets a value indicating whether the check requires different layers
*/
bool different_polygons () const
{
return m_different_polygons;
}
/**
* @brief Sets a value indicating whether the check requires different layers
*/
void set_different_polygons (bool f)
{
m_different_polygons = f;
}
/**
* @brief Gets the distance value
*/
EdgeRelationFilter::distance_type distance () const
{
return m_distance;
}
private:
const EdgeRelationFilter *mp_check;
EdgePairs *mp_output;
bool m_requires_different_layers;
bool m_different_polygons;
EdgeRelationFilter::distance_type m_distance;
std::vector<db::EdgePair> m_ep;
std::multimap<std::pair<db::Edge, size_t>, size_t> m_e2ep;
std::vector<bool> m_ep_discarded;
unsigned int m_pass;
};
/**
* @brief A helper class for the DRC functionality which acts as an edge pair receiver
*/
class Poly2PolyCheck
: public db::box_scanner_receiver<db::Polygon, size_t>
{
public:
Poly2PolyCheck (Edge2EdgeCheck &output)
: mp_output (&output)
{
// .. nothing yet ..
}
void finish (const db::Polygon *o, size_t p)
{
enter (*o, p);
}
void enter (const db::Polygon &o, size_t p)
{
if (! mp_output->requires_different_layers () && ! mp_output->different_polygons ()) {
// finally we check the polygons vs. itself for checks involving intra-polygon interactions
m_scanner.clear ();
m_scanner.reserve (o.vertices ());
m_edges.clear ();
m_edges.reserve (o.vertices ());
for (db::Polygon::polygon_edge_iterator e = o.begin_edge (); ! e.at_end (); ++e) {
m_edges.push_back (*e);
m_scanner.insert (& m_edges.back (), p);
}
tl_assert (m_edges.size () == o.vertices ());
m_scanner.process (*mp_output, mp_output->distance (), db::box_convert<db::Edge> ());
}
}
void add (const db::Polygon *o1, size_t p1, const db::Polygon *o2, size_t p2)
{
enter (*o1, p1, *o2, p2);
}
void enter (const db::Polygon &o1, size_t p1, const db::Polygon &o2, size_t p2)
{
if ((! mp_output->different_polygons () || p1 != p2) && (! mp_output->requires_different_layers () || ((p1 ^ p2) & 1) != 0)) {
m_scanner.clear ();
m_scanner.reserve (o1.vertices () + o2.vertices ());
m_edges.clear ();
m_edges.reserve (o1.vertices () + o2.vertices ());
for (db::Polygon::polygon_edge_iterator e = o1.begin_edge (); ! e.at_end (); ++e) {
m_edges.push_back (*e);
m_scanner.insert (& m_edges.back (), p1);
}
for (db::Polygon::polygon_edge_iterator e = o2.begin_edge (); ! e.at_end (); ++e) {
m_edges.push_back (*e);
m_scanner.insert (& m_edges.back (), p2);
}
tl_assert (m_edges.size () == o1.vertices () + o2.vertices ());
// temporarily disable intra-polygon check in that step .. we do that later in finish()
// if required (#650).
bool no_intra = mp_output->different_polygons ();
mp_output->set_different_polygons (true);
m_scanner.process (*mp_output, mp_output->distance (), db::box_convert<db::Edge> ());
mp_output->set_different_polygons (no_intra);
}
}
private:
db::box_scanner<db::Edge, size_t> m_scanner;
Edge2EdgeCheck *mp_output;
std::vector<db::Edge> m_edges;
};
}
EdgePairs
AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons, const Region *other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const
{
@ -897,8 +632,8 @@ AsIfFlatRegion::run_check (db::edge_relation_type rel, bool different_polygons,
check.set_min_projection (min_projection);
check.set_max_projection (max_projection);
Edge2EdgeCheck edge_check (check, result, different_polygons, other != 0);
Poly2PolyCheck poly_check (edge_check);
edge2edge_check<db::EdgePairs> edge_check (check, result, different_polygons, other != 0);
poly2poly_check<db::EdgePairs> poly_check (edge_check);
do {
scanner.process (poly_check, d, db::box_convert<db::Polygon> ());
@ -918,8 +653,8 @@ AsIfFlatRegion::run_single_polygon_check (db::edge_relation_type rel, db::Coord
check.set_min_projection (min_projection);
check.set_max_projection (max_projection);
Edge2EdgeCheck edge_check (check, result, false, false);
Poly2PolyCheck poly_check (edge_check);
edge2edge_check<db::EdgePairs> edge_check (check, result, false, false);
poly2poly_check<db::EdgePairs> poly_check (edge_check);
do {

View File

@ -30,11 +30,274 @@
#include "dbPolygon.h"
#include "dbEdge.h"
#include "dbBoxScanner.h"
#include "dbEdgePairRelations.h"
#include <set>
namespace db {
/**
* @brief A helper class for the DRC functionality which acts as an edge pair receiver
*/
template <class Output>
class edge2edge_check
: public db::box_scanner_receiver<db::Edge, size_t>
{
public:
edge2edge_check (const EdgeRelationFilter &check, Output &output, bool different_polygons, bool requires_different_layers)
: mp_check (&check), mp_output (&output), m_requires_different_layers (requires_different_layers), m_different_polygons (different_polygons),
m_pass (0)
{
m_distance = check.distance ();
}
bool prepare_next_pass ()
{
++m_pass;
if (m_pass == 1) {
if (! 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) {
mp_output->insert (*ep);
}
++d;
++ep;
}
}
return false;
}
void 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)) {
// ensure that the first check argument is of layer 1 and the second of
// layer 2 (unless both are of the same layer)
int l1 = int (p1 & size_t (1));
int l2 = int (p2 & size_t (1));
db::EdgePair 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
// pass we will eliminate those which are shielded completely.
size_t n = m_ep.size ();
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 (*o2, p2), n));
}
}
} 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.
// 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.
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);
}
for (unsigned int p = 0; p < 2; ++p) {
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 (db::Edge (ep.first ().p1 (), ep.second ().p2 ()).intersect (*o2) &&
db::Edge (ep.second ().p1 (), ep.first ().p2 ()).intersect (*o2)) {
m_ep_discarded [*i] = true;
}
}
}
std::swap (o1, o2);
std::swap (p1, p2);
n1.swap (n2);
}
}
}
/**
* @brief Gets a value indicating whether the check requires different layers
*/
bool requires_different_layers () const
{
return m_requires_different_layers;
}
/**
* @brief Sets a value indicating whether the check requires different layers
*/
void set_requires_different_layers (bool f)
{
m_requires_different_layers = f;
}
/**
* @brief Gets a value indicating whether the check requires different layers
*/
bool different_polygons () const
{
return m_different_polygons;
}
/**
* @brief Sets a value indicating whether the check requires different layers
*/
void set_different_polygons (bool f)
{
m_different_polygons = f;
}
/**
* @brief Gets the distance value
*/
EdgeRelationFilter::distance_type distance () const
{
return m_distance;
}
private:
const EdgeRelationFilter *mp_check;
Output *mp_output;
bool m_requires_different_layers;
bool m_different_polygons;
EdgeRelationFilter::distance_type m_distance;
std::vector<db::EdgePair> m_ep;
std::multimap<std::pair<db::Edge, size_t>, size_t> m_e2ep;
std::vector<bool> m_ep_discarded;
unsigned int m_pass;
};
/**
* @brief A helper class for the DRC functionality which acts as an edge pair receiver
*/
template <class Output>
class poly2poly_check
: public db::box_scanner_receiver<db::Polygon, size_t>
{
public:
poly2poly_check (edge2edge_check<Output> &output)
: mp_output (&output)
{
// .. nothing yet ..
}
void finish (const db::Polygon *o, size_t p)
{
enter (*o, p);
}
void enter (const db::Polygon &o, size_t p)
{
if (! mp_output->requires_different_layers () && ! mp_output->different_polygons ()) {
// finally we check the polygons vs. itself for checks involving intra-polygon interactions
m_scanner.clear ();
m_scanner.reserve (o.vertices ());
m_edges.clear ();
m_edges.reserve (o.vertices ());
for (db::Polygon::polygon_edge_iterator e = o.begin_edge (); ! e.at_end (); ++e) {
m_edges.push_back (*e);
m_scanner.insert (& m_edges.back (), p);
}
tl_assert (m_edges.size () == o.vertices ());
m_scanner.process (*mp_output, mp_output->distance (), db::box_convert<db::Edge> ());
}
}
void add (const db::Polygon *o1, size_t p1, const db::Polygon *o2, size_t p2)
{
enter (*o1, p1, *o2, p2);
}
void enter (const db::Polygon &o1, size_t p1, const db::Polygon &o2, size_t p2)
{
if ((! mp_output->different_polygons () || p1 != p2) && (! mp_output->requires_different_layers () || ((p1 ^ p2) & 1) != 0)) {
m_scanner.clear ();
m_scanner.reserve (o1.vertices () + o2.vertices ());
m_edges.clear ();
m_edges.reserve (o1.vertices () + o2.vertices ());
for (db::Polygon::polygon_edge_iterator e = o1.begin_edge (); ! e.at_end (); ++e) {
m_edges.push_back (*e);
m_scanner.insert (& m_edges.back (), p1);
}
for (db::Polygon::polygon_edge_iterator e = o2.begin_edge (); ! e.at_end (); ++e) {
m_edges.push_back (*e);
m_scanner.insert (& m_edges.back (), p2);
}
tl_assert (m_edges.size () == o1.vertices () + o2.vertices ());
// temporarily disable intra-polygon check in that step .. we do that later in finish()
// if required (#650).
bool no_intra = mp_output->different_polygons ();
mp_output->set_different_polygons (true);
m_scanner.process (*mp_output, mp_output->distance (), db::box_convert<db::Edge> ());
mp_output->set_different_polygons (no_intra);
}
}
private:
db::box_scanner<db::Edge, size_t> m_scanner;
edge2edge_check<Output> *mp_output;
std::vector<db::Edge> m_edges;
};
/**
* @brief A helper class for the region to edge interaction functionality
*/

View File

@ -26,6 +26,7 @@
#include "dbEmptyRegion.h"
#include "dbRegion.h"
#include "dbDeepEdges.h"
#include "dbDeepEdgePairs.h"
#include "dbShapeProcessor.h"
#include "dbFlatRegion.h"
#include "dbHierProcessor.h"
@ -1233,18 +1234,142 @@ DeepRegion::smoothed (coord_type d) const
return res.release ();
}
namespace
{
class CheckLocalOperation
: public local_operation<db::PolygonRef, db::PolygonRef, db::EdgePair>
{
public:
CheckLocalOperation (const EdgeRelationFilter &check, bool different_polygons)
: m_check (check), m_different_polygons (different_polygons)
{
// .. nothing yet ..
}
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, false, false);
poly2poly_check<std::unordered_set<db::EdgePair> > poly_check (edge_check);
std::set<db::PolygonRef> others;
for (shape_interactions<db::PolygonRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i) {
for (shape_interactions<db::PolygonRef, db::PolygonRef>::iterator2 j = i->second.begin (); j != i->second.end (); ++j) {
others.insert (interactions.intruder_shape (*j));
}
}
size_t n = 0;
for (shape_interactions<db::PolygonRef, db::PolygonRef>::iterator i = interactions.begin (); i != interactions.end (); ++i, ++n) {
const db::PolygonRef &subject = interactions.subject_shape (i->first);
db::Polygon poly = subject.obj ().transformed (subject.trans ());
poly_check.enter (poly, n);
n += 2;
}
n = 1;
for (std::set<db::PolygonRef>::const_iterator o = others.begin (); o != others.end (); ++o) {
db::Polygon poly = o->obj ().transformed (o->trans ());
poly_check.enter (poly, n);
n += 2;
}
db::box_scanner<db::Polygon, size_t> scanner;
do {
scanner.process (poly_check, m_check.distance (), db::box_convert<db::Polygon> ());
} while (edge_check.prepare_next_pass ());
}
virtual db::Coord dist () const
{
// TODO: will the distance be sufficient? Or should be take somewhat more?
return m_check.distance ();
}
virtual on_empty_intruder_mode on_empty_intruder_hint () const
{
return m_different_polygons ? Drop : Ignore;
}
virtual std::string description () const
{
return tl::to_string (tr ("Generic DRC check"));
}
private:
EdgeRelationFilter m_check;
bool m_different_polygons;
};
}
EdgePairs
DeepRegion::run_check (db::edge_relation_type rel, bool different_polygons, const Region *other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const
{
// TODO: implement hierarchically
return db::AsIfFlatRegion::run_check (rel, different_polygons, other, d, whole_edges, metrics, ignore_angle, min_projection, max_projection);
const db::DeepRegion *other_deep = dynamic_cast<const db::DeepRegion *> (other->delegate ());
if (! other_deep) {
return db::AsIfFlatRegion::run_check (rel, different_polygons, other, d, whole_edges, metrics, ignore_angle, min_projection, max_projection);
}
ensure_merged_polygons_valid ();
EdgeRelationFilter check (rel, d, metrics);
check.set_whole_edges (whole_edges);
check.set_ignore_angle (ignore_angle);
check.set_min_projection (min_projection);
check.set_max_projection (max_projection);
DeepLayer dl_out (m_deep_layer.derived ());
std::auto_ptr<db::DeepEdgePairs> res (new db::DeepEdgePairs (m_merged_polygons.derived ()));
db::CheckLocalOperation op (check, different_polygons);
db::local_processor<db::PolygonRef, db::PolygonRef, db::EdgePair> proc (const_cast<db::Layout *> (&m_deep_layer.layout ()), const_cast<db::Cell *> (&m_deep_layer.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ());
proc.set_base_verbosity (base_verbosity ());
proc.set_threads (m_deep_layer.store ()->threads ());
proc.run (&op, m_merged_polygons.layer (), other_deep->deep_layer ().layer (), dl_out.layer ());
return db::EdgePairs (res.release ());
}
EdgePairs
DeepRegion::run_single_polygon_check (db::edge_relation_type rel, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const
{
// TODO: implement hierarchically
return db::AsIfFlatRegion::run_single_polygon_check (rel, d, whole_edges, metrics, ignore_angle, min_projection, max_projection);
ensure_merged_polygons_valid ();
EdgeRelationFilter check (rel, d, metrics);
check.set_whole_edges (whole_edges);
check.set_ignore_angle (ignore_angle);
check.set_min_projection (min_projection);
check.set_max_projection (max_projection);
db::Layout &layout = m_merged_polygons.layout ();
std::auto_ptr<db::DeepEdgePairs> res (new db::DeepEdgePairs (m_merged_polygons.derived ()));
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
const db::Shapes &shapes = c->shapes (m_merged_polygons.layer ());
db::Shapes &result = c->shapes (res->deep_layer ().layer ());
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);
poly2poly_check<db::Shapes> poly_check (edge_check);
db::Polygon poly;
s->polygon (poly);
do {
poly_check.enter (poly, 0);
} while (edge_check.prepare_next_pass ());
}
}
return db::EdgePairs (res.release ());
}
namespace