mirror of https://github.com/KLayout/klayout.git
Refactoring of the polygon processing in Region
This commit is contained in:
parent
90c1d212a4
commit
496b695ef0
|
|
@ -26,6 +26,7 @@
|
|||
#include "dbFlatEdgePairs.h"
|
||||
#include "dbEmptyRegion.h"
|
||||
#include "dbRegion.h"
|
||||
#include "dbRegionUtils.h"
|
||||
#include "dbShapeProcessor.h"
|
||||
#include "dbBoxConvert.h"
|
||||
#include "dbBoxScanner.h"
|
||||
|
|
@ -92,60 +93,6 @@ AsIfFlatRegion::edges (const EdgeFilterBase *filter) const
|
|||
return edges;
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatRegion::hulls () const
|
||||
{
|
||||
std::auto_ptr<FlatRegion> new_region (new FlatRegion (false));
|
||||
|
||||
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) {
|
||||
db::Polygon h;
|
||||
h.assign_hull (p->begin_hull (), p->end_hull ());
|
||||
new_region->insert (h);
|
||||
}
|
||||
|
||||
return new_region.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatRegion::holes () const
|
||||
{
|
||||
std::auto_ptr<FlatRegion> new_region (new FlatRegion (false));
|
||||
|
||||
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) {
|
||||
for (size_t i = 0; i < p->holes (); ++i) {
|
||||
db::Polygon h;
|
||||
h.assign_hull (p->begin_hole ((unsigned int) i), p->end_hole ((unsigned int) i));
|
||||
new_region->insert (h);
|
||||
}
|
||||
}
|
||||
|
||||
return new_region.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatRegion::rounded_corners (double rinner, double router, unsigned int n) const
|
||||
{
|
||||
std::auto_ptr<FlatRegion> new_region (new FlatRegion (false));
|
||||
|
||||
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) {
|
||||
new_region->insert (db::compute_rounded (*p, rinner, router, n));
|
||||
}
|
||||
|
||||
return new_region.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatRegion::smoothed (coord_type d) const
|
||||
{
|
||||
std::auto_ptr<FlatRegion> new_region (new FlatRegion (false));
|
||||
|
||||
for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) {
|
||||
new_region->insert (db::smooth (*p, d));
|
||||
}
|
||||
|
||||
return new_region.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatRegion::in (const Region &other, bool invert) const
|
||||
{
|
||||
|
|
@ -301,6 +248,25 @@ AsIfFlatRegion::filtered (const PolygonFilterBase &filter) const
|
|||
return new_region.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatRegion::processed (const PolygonProcessorBase &filter) const
|
||||
{
|
||||
std::auto_ptr<FlatRegion> new_region (new FlatRegion ());
|
||||
std::vector<db::Polygon> poly_res;
|
||||
|
||||
for (RegionIterator p (filter.requires_raw_input () ? begin () : begin_merged ()); ! p.at_end (); ++p) {
|
||||
|
||||
poly_res.clear ();
|
||||
filter.process (*p, poly_res);
|
||||
for (std::vector<db::Polygon>::const_iterator pr = poly_res.begin (); pr != poly_res.end (); ++pr) {
|
||||
new_region->insert (*pr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return new_region.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse) const
|
||||
{
|
||||
|
|
@ -593,41 +559,6 @@ AsIfFlatRegion::snapped (db::Coord gx, db::Coord gy)
|
|||
return new_region.release ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A helper class to implement the strange polygon detector
|
||||
*/
|
||||
struct DB_PUBLIC StrangePolygonInsideFunc
|
||||
{
|
||||
inline bool operator() (int wc) const
|
||||
{
|
||||
return wc < 0 || wc > 1;
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
AsIfFlatRegion::produce_shape_for_strange_polygon (const db::Polygon &poly, db::Shapes &shapes)
|
||||
{
|
||||
EdgeProcessor ep;
|
||||
ep.insert (poly);
|
||||
|
||||
StrangePolygonInsideFunc inside;
|
||||
db::GenericMerge<StrangePolygonInsideFunc> op (inside);
|
||||
db::ShapeGenerator pc (shapes, false);
|
||||
db::PolygonGenerator pg (pc, false, false);
|
||||
ep.process (pg, op);
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatRegion::strange_polygon_check () const
|
||||
{
|
||||
std::auto_ptr<FlatRegion> new_region (new FlatRegion (merged_semantics ()));
|
||||
for (RegionIterator p (begin ()); ! p.at_end (); ++p) {
|
||||
produce_shape_for_strange_polygon (*p, new_region->raw_polygons ());
|
||||
}
|
||||
|
||||
return new_region.release ();
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -36,329 +36,6 @@
|
|||
|
||||
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
|
||||
*/
|
||||
template <class OutputContainer>
|
||||
class DB_PUBLIC region_to_edge_interaction_filter
|
||||
: public db::box_scanner_receiver2<db::Polygon, size_t, db::Edge, size_t>
|
||||
{
|
||||
public:
|
||||
region_to_edge_interaction_filter (OutputContainer &output, bool inverse)
|
||||
: mp_output (&output), m_inverse (inverse)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void preset (const db::Polygon *poly)
|
||||
{
|
||||
m_seen.insert (poly);
|
||||
}
|
||||
|
||||
void add (const db::Polygon *p, size_t, const db::Edge *e, size_t)
|
||||
{
|
||||
if ((m_seen.find (p) == m_seen.end ()) != m_inverse) {
|
||||
|
||||
// A polygon and an edge interact if the edge is either inside completely
|
||||
// of at least one edge of the polygon intersects with the edge
|
||||
bool interacts = false;
|
||||
if (p->box ().contains (e->p1 ()) && db::inside_poly (p->begin_edge (), e->p1 ()) >= 0) {
|
||||
interacts = true;
|
||||
} else {
|
||||
for (db::Polygon::polygon_edge_iterator pe = p->begin_edge (); ! pe.at_end () && ! interacts; ++pe) {
|
||||
if ((*pe).intersect (*e)) {
|
||||
interacts = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (interacts) {
|
||||
if (m_inverse) {
|
||||
m_seen.erase (p);
|
||||
} else {
|
||||
m_seen.insert (p);
|
||||
mp_output->insert (*p);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void fill_output ()
|
||||
{
|
||||
for (std::set<const db::Polygon *>::const_iterator p = m_seen.begin (); p != m_seen.end (); ++p) {
|
||||
mp_output->insert (**p);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
OutputContainer *mp_output;
|
||||
std::set<const db::Polygon *> m_seen;
|
||||
bool m_inverse;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Provides default flat implementations
|
||||
*/
|
||||
|
|
@ -430,6 +107,13 @@ public:
|
|||
|
||||
virtual Edges edges (const EdgeFilterBase *) const;
|
||||
|
||||
virtual RegionDelegate *process_in_place (const PolygonProcessorBase &filter)
|
||||
{
|
||||
return processed (filter);
|
||||
}
|
||||
|
||||
virtual RegionDelegate *processed (const PolygonProcessorBase &filter) const;
|
||||
|
||||
virtual RegionDelegate *filter_in_place (const PolygonFilterBase &filter)
|
||||
{
|
||||
return filtered (filter);
|
||||
|
|
@ -454,8 +138,6 @@ public:
|
|||
|
||||
virtual RegionDelegate *merged (bool min_coherence, unsigned int min_wc) const;
|
||||
|
||||
virtual RegionDelegate *strange_polygon_check () const;
|
||||
|
||||
virtual RegionDelegate *sized (coord_type d, unsigned int mode) const;
|
||||
virtual RegionDelegate *sized (coord_type dx, coord_type dy, unsigned int mode) const;
|
||||
|
||||
|
|
@ -521,11 +203,7 @@ public:
|
|||
return selected_interacting_generic (other, 0, false, true);
|
||||
}
|
||||
|
||||
virtual RegionDelegate *holes () const;
|
||||
virtual RegionDelegate *hulls () const;
|
||||
virtual RegionDelegate *in (const Region &other, bool invert) const;
|
||||
virtual RegionDelegate *rounded_corners (double rinner, double router, unsigned int n) const;
|
||||
virtual RegionDelegate *smoothed (coord_type d) const;
|
||||
|
||||
virtual bool equals (const Region &other) const;
|
||||
virtual bool less (const Region &other) const;
|
||||
|
|
@ -541,7 +219,6 @@ protected:
|
|||
RegionDelegate *selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse) const;
|
||||
RegionDelegate *selected_interacting_generic (const Edges &other, bool inverse) const;
|
||||
|
||||
static void produce_shape_for_strange_polygon (const db::Polygon &poly, db::Shapes &shapes);
|
||||
template <class Trans>
|
||||
static void produce_markers_for_grid_check (const db::Polygon &poly, const Trans &tr, db::Coord gx, db::Coord gy, db::Shapes &shapes);
|
||||
template <class Trans>
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include "dbDeepShapeStore.h"
|
||||
#include "dbEmptyRegion.h"
|
||||
#include "dbRegion.h"
|
||||
#include "dbRegionUtils.h"
|
||||
#include "dbDeepEdges.h"
|
||||
#include "dbDeepEdgePairs.h"
|
||||
#include "dbShapeProcessor.h"
|
||||
|
|
@ -902,6 +903,83 @@ DeepRegion::edges (const EdgeFilterBase *filter) const
|
|||
return db::Edges (res.release ());
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::process_in_place (const PolygonProcessorBase &filter)
|
||||
{
|
||||
// TODO: implement to be really in-place
|
||||
return processed (filter);
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::processed (const PolygonProcessorBase &filter) const
|
||||
{
|
||||
ensure_merged_polygons_valid ();
|
||||
|
||||
std::auto_ptr<VariantsCollectorBase> vars;
|
||||
if (filter.vars ()) {
|
||||
|
||||
vars.reset (new db::VariantsCollectorBase (filter.vars ()));
|
||||
|
||||
vars->collect (m_merged_polygons.layout (), m_merged_polygons.initial_cell ());
|
||||
|
||||
// NOTE: m_merged_polygons is mutable, so why is the const_cast needed?
|
||||
const_cast<db::DeepLayer &> (m_merged_polygons).separate_variants (*vars);
|
||||
|
||||
}
|
||||
|
||||
db::Layout &layout = m_merged_polygons.layout ();
|
||||
|
||||
std::vector<db::Polygon> poly_res;
|
||||
|
||||
std::auto_ptr<db::DeepRegion> res (new db::DeepRegion (m_merged_polygons.derived ()));
|
||||
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||
|
||||
if (vars.get ()) {
|
||||
|
||||
const std::map<db::ICplxTrans, size_t> &v = vars->variants (c->cell_index ());
|
||||
tl_assert (v.size () == size_t (1));
|
||||
const db::ICplxTrans &tr = v.begin ()->first;
|
||||
db::ICplxTrans trinv = tr.inverted ();
|
||||
|
||||
const db::Shapes &s = c->shapes (filter.requires_raw_input () ? m_deep_layer.layer () : m_merged_polygons.layer ());
|
||||
db::Shapes &st = c->shapes (res->deep_layer ().layer ());
|
||||
|
||||
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) {
|
||||
db::Polygon poly;
|
||||
si->polygon (poly);
|
||||
poly.transform (tr);
|
||||
poly_res.clear ();
|
||||
filter.process (poly, poly_res);
|
||||
for (std::vector<db::Polygon>::const_iterator p = poly_res.begin (); p != poly_res.end (); ++p) {
|
||||
st.insert (p->transformed (trinv));
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
const db::Shapes &s = c->shapes (filter.requires_raw_input () ? m_deep_layer.layer () : m_merged_polygons.layer ());
|
||||
db::Shapes &st = c->shapes (res->deep_layer ().layer ());
|
||||
|
||||
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) {
|
||||
db::Polygon poly;
|
||||
si->polygon (poly);
|
||||
poly_res.clear ();
|
||||
filter.process (poly, poly_res);
|
||||
for (std::vector<db::Polygon>::const_iterator p = poly_res.begin (); p != poly_res.end (); ++p) {
|
||||
st.insert (*p);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (filter.result_is_merged ()) {
|
||||
res->set_is_merged (true);
|
||||
}
|
||||
return res.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::filter_in_place (const PolygonFilterBase &filter)
|
||||
{
|
||||
|
|
@ -1043,12 +1121,6 @@ DeepRegion::merged (bool min_coherence, unsigned int min_wc) const
|
|||
return res;
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::strange_polygon_check () const
|
||||
{
|
||||
throw tl::Exception (tl::to_string (tr ("A strange polygon check does not make sense on a processed region - polygons are already normalized")));
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::sized (coord_type d, unsigned int mode) const
|
||||
{
|
||||
|
|
@ -1173,72 +1245,6 @@ DeepRegion::sized (coord_type dx, coord_type dy, unsigned int mode) const
|
|||
return res.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::holes () const
|
||||
{
|
||||
ensure_merged_polygons_valid ();
|
||||
|
||||
db::Layout &layout = m_merged_polygons.layout ();
|
||||
|
||||
std::vector<db::Point> pts;
|
||||
|
||||
std::auto_ptr<db::DeepRegion> res (new db::DeepRegion (m_merged_polygons.derived ()));
|
||||
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||
|
||||
const db::Shapes &s = c->shapes (m_merged_polygons.layer ());
|
||||
db::Shapes &st = c->shapes (res->deep_layer ().layer ());
|
||||
db::PolygonRefToShapesGenerator pr (&layout, &st);
|
||||
|
||||
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) {
|
||||
for (size_t i = 0; i < si->holes (); ++i) {
|
||||
db::Polygon h;
|
||||
pts.clear ();
|
||||
for (db::Shape::point_iterator p = si->begin_hole ((unsigned int) i); p != si->end_hole ((unsigned int) i); ++p) {
|
||||
pts.push_back (*p);
|
||||
}
|
||||
h.assign_hull (pts.begin (), pts.end ());
|
||||
pr.put (h);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
res->set_is_merged (true);
|
||||
return res.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::hulls () const
|
||||
{
|
||||
ensure_merged_polygons_valid ();
|
||||
|
||||
db::Layout &layout = m_merged_polygons.layout ();
|
||||
|
||||
std::vector<db::Point> pts;
|
||||
|
||||
std::auto_ptr<db::DeepRegion> res (new db::DeepRegion (m_merged_polygons.derived ()));
|
||||
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||
|
||||
const db::Shapes &s = c->shapes (m_merged_polygons.layer ());
|
||||
db::Shapes &st = c->shapes (res->deep_layer ().layer ());
|
||||
db::PolygonRefToShapesGenerator pr (&layout, &st);
|
||||
|
||||
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) {
|
||||
db::Polygon h;
|
||||
pts.clear ();
|
||||
for (db::Shape::point_iterator p = si->begin_hull (); p != si->end_hull (); ++p) {
|
||||
pts.push_back (*p);
|
||||
}
|
||||
h.assign_hull (pts.begin (), pts.end ());
|
||||
pr.put (h);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
res->set_is_merged (true);
|
||||
return res.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::in (const Region &other, bool invert) const
|
||||
{
|
||||
|
|
@ -1246,79 +1252,6 @@ DeepRegion::in (const Region &other, bool invert) const
|
|||
return db::AsIfFlatRegion::in (other, invert);
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::rounded_corners (double rinner, double router, unsigned int n) const
|
||||
{
|
||||
ensure_merged_polygons_valid ();
|
||||
|
||||
db::cell_variants_collector<db::MagnificationReducer> vars;
|
||||
vars.collect (m_merged_polygons.layout (), m_merged_polygons.initial_cell ());
|
||||
|
||||
// NOTE: m_merged_polygons is mutable, so why is the const_cast needed?
|
||||
const_cast<db::DeepLayer &> (m_merged_polygons).separate_variants (vars);
|
||||
|
||||
db::Layout &layout = m_merged_polygons.layout ();
|
||||
|
||||
std::auto_ptr<db::DeepRegion> res (new db::DeepRegion (m_merged_polygons.derived ()));
|
||||
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||
|
||||
const std::map<db::ICplxTrans, size_t> &v = vars.variants (c->cell_index ());
|
||||
tl_assert (v.size () == size_t (1));
|
||||
double mag = v.begin ()->first.mag ();
|
||||
db::Coord rinner_with_mag = db::coord_traits<db::Coord>::rounded (rinner / mag);
|
||||
db::Coord router_with_mag = db::coord_traits<db::Coord>::rounded (router / mag);
|
||||
|
||||
const db::Shapes &s = c->shapes (m_merged_polygons.layer ());
|
||||
db::Shapes &st = c->shapes (res->deep_layer ().layer ());
|
||||
db::PolygonRefToShapesGenerator pr (&layout, &st);
|
||||
|
||||
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) {
|
||||
db::Polygon poly;
|
||||
si->polygon (poly);
|
||||
pr.put (db::compute_rounded (poly, rinner_with_mag, router_with_mag, n));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return res.release ();
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
DeepRegion::smoothed (coord_type d) const
|
||||
{
|
||||
ensure_merged_polygons_valid ();
|
||||
|
||||
db::cell_variants_collector<db::MagnificationReducer> vars;
|
||||
vars.collect (m_merged_polygons.layout (), m_merged_polygons.initial_cell ());
|
||||
|
||||
// NOTE: m_merged_polygons is mutable, so why is the const_cast needed?
|
||||
const_cast<db::DeepLayer &> (m_merged_polygons).separate_variants (vars);
|
||||
|
||||
db::Layout &layout = m_merged_polygons.layout ();
|
||||
|
||||
std::auto_ptr<db::DeepRegion> res (new db::DeepRegion (m_merged_polygons.derived ()));
|
||||
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||
|
||||
const std::map<db::ICplxTrans, size_t> &v = vars.variants (c->cell_index ());
|
||||
tl_assert (v.size () == size_t (1));
|
||||
double mag = v.begin ()->first.mag ();
|
||||
db::Coord d_with_mag = db::coord_traits<db::Coord>::rounded (d / mag);
|
||||
|
||||
const db::Shapes &s = c->shapes (m_merged_polygons.layer ());
|
||||
db::Shapes &st = c->shapes (res->deep_layer ().layer ());
|
||||
db::PolygonRefToShapesGenerator pr (&layout, &st);
|
||||
|
||||
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) {
|
||||
db::Polygon poly;
|
||||
si->polygon (poly);
|
||||
pr.put (db::smooth (poly, d_with_mag));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return res.release ();
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
|
|
|
|||
|
|
@ -138,6 +138,8 @@ public:
|
|||
|
||||
virtual Edges edges (const EdgeFilterBase *) const;
|
||||
|
||||
virtual RegionDelegate *process_in_place (const PolygonProcessorBase &filter);
|
||||
virtual RegionDelegate *processed (const PolygonProcessorBase &filter) const;
|
||||
virtual RegionDelegate *filter_in_place (const PolygonFilterBase &filter);
|
||||
virtual RegionDelegate *filtered (const PolygonFilterBase &filter) const;
|
||||
|
||||
|
|
@ -147,8 +149,6 @@ public:
|
|||
virtual RegionDelegate *merged () const;
|
||||
virtual RegionDelegate *merged (bool min_coherence, unsigned int min_wc) const;
|
||||
|
||||
virtual RegionDelegate *strange_polygon_check () const;
|
||||
|
||||
virtual RegionDelegate *sized (coord_type d, unsigned int mode) const;
|
||||
virtual RegionDelegate *sized (coord_type dx, coord_type dy, unsigned int mode) const;
|
||||
|
||||
|
|
@ -202,11 +202,7 @@ public:
|
|||
return selected_interacting_generic (other, 0, false, true);
|
||||
}
|
||||
|
||||
virtual RegionDelegate *holes () const;
|
||||
virtual RegionDelegate *hulls () const;
|
||||
virtual RegionDelegate *in (const Region &other, bool invert) const;
|
||||
virtual RegionDelegate *rounded_corners (double rinner, double router, unsigned int n) const;
|
||||
virtual RegionDelegate *smoothed (coord_type d) const;
|
||||
|
||||
virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const;
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ class EmptyEdgePairs;
|
|||
class Edges;
|
||||
class Region;
|
||||
class DeepShapeStore;
|
||||
class TransformationReducer;
|
||||
|
||||
/**
|
||||
* @brief An edge pair set iterator
|
||||
|
|
@ -213,6 +214,7 @@ public:
|
|||
virtual ~EdgePairFilterBase () { }
|
||||
|
||||
virtual bool selected (const db::EdgePair &edge) const = 0;
|
||||
virtual const TransformationReducer *vars () const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -73,11 +73,11 @@ public:
|
|||
virtual RegionDelegate *snapped_in_place (db::Coord, db::Coord) { return this; }
|
||||
virtual RegionDelegate *snapped (db::Coord, db::Coord) { return new EmptyRegion (); }
|
||||
|
||||
virtual RegionDelegate *strange_polygon_check () const { return new EmptyRegion (); }
|
||||
|
||||
virtual Edges edges (const EdgeFilterBase *) const { return db::Edges (); }
|
||||
virtual RegionDelegate *filter_in_place (const PolygonFilterBase &) { return this; }
|
||||
virtual RegionDelegate *filtered (const PolygonFilterBase &) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *process_in_place (const PolygonProcessorBase &) { return this; }
|
||||
virtual RegionDelegate *processed (const PolygonProcessorBase &) const { return new EmptyRegion (); }
|
||||
|
||||
virtual RegionDelegate *merged_in_place () { return this; }
|
||||
virtual RegionDelegate *merged_in_place (bool, unsigned int) { return this; }
|
||||
|
|
@ -104,12 +104,7 @@ public:
|
|||
virtual RegionDelegate *selected_not_interacting (const Edges &) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *selected_overlapping (const Region &) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *selected_not_overlapping (const Region &) const { return new EmptyRegion (); }
|
||||
|
||||
virtual RegionDelegate *holes () const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *hulls () const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *in (const Region &, bool) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *rounded_corners (double, double, unsigned int) const { return new EmptyRegion (); }
|
||||
virtual RegionDelegate *smoothed (coord_type) const { return new EmptyRegion (); }
|
||||
|
||||
virtual bool has_valid_polygons () const { return true; }
|
||||
virtual bool has_valid_merged_polygons () const { return true; }
|
||||
|
|
|
|||
|
|
@ -205,6 +205,34 @@ RegionDelegate *FlatRegion::filter_in_place (const PolygonFilterBase &filter)
|
|||
return this;
|
||||
}
|
||||
|
||||
RegionDelegate *FlatRegion::process_in_place (const PolygonProcessorBase &filter)
|
||||
{
|
||||
std::vector<db::Polygon> poly_res;
|
||||
|
||||
polygon_iterator_type pw = m_polygons.get_layer<db::Polygon, db::unstable_layer_tag> ().begin ();
|
||||
for (RegionIterator p (filter.requires_raw_input () ? begin () : begin_merged ()); ! p.at_end (); ++p) {
|
||||
|
||||
poly_res.clear ();
|
||||
filter.process (*p, poly_res);
|
||||
|
||||
for (std::vector<db::Polygon>::const_iterator pr = poly_res.begin (); pr != poly_res.end (); ++pr) {
|
||||
if (pw == m_polygons.get_layer<db::Polygon, db::unstable_layer_tag> ().end ()) {
|
||||
m_polygons.get_layer<db::Polygon, db::unstable_layer_tag> ().insert (*pr);
|
||||
pw = m_polygons.get_layer<db::Polygon, db::unstable_layer_tag> ().end ();
|
||||
} else {
|
||||
m_polygons.get_layer<db::Polygon, db::unstable_layer_tag> ().replace (pw++, *pr);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
m_polygons.get_layer<db::Polygon, db::unstable_layer_tag> ().erase (pw, m_polygons.get_layer<db::Polygon, db::unstable_layer_tag> ().end ());
|
||||
m_merged_polygons.clear ();
|
||||
m_is_merged = filter.result_is_merged () && merged_semantics ();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
RegionDelegate *FlatRegion::merged_in_place ()
|
||||
{
|
||||
if (! m_is_merged) {
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ public:
|
|||
return db::AsIfFlatRegion::merged (min_coherence, min_wc);
|
||||
}
|
||||
|
||||
virtual RegionDelegate *process_in_place (const PolygonProcessorBase &filter);
|
||||
virtual RegionDelegate *filter_in_place (const PolygonFilterBase &filter);
|
||||
|
||||
virtual RegionDelegate *add_in_place (const Region &other);
|
||||
|
|
|
|||
|
|
@ -26,10 +26,144 @@
|
|||
#include "dbEmptyRegion.h"
|
||||
#include "dbFlatRegion.h"
|
||||
#include "dbDeepRegion.h"
|
||||
#include "dbPolygonTools.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
// Strange polygon processor
|
||||
|
||||
/**
|
||||
* @brief A helper class to implement the strange polygon detector
|
||||
*/
|
||||
struct DB_PUBLIC StrangePolygonInsideFunc
|
||||
{
|
||||
inline bool operator() (int wc) const
|
||||
{
|
||||
return wc < 0 || wc > 1;
|
||||
}
|
||||
};
|
||||
|
||||
class StrangePolygonCheckProcessor
|
||||
: public PolygonProcessorBase
|
||||
{
|
||||
public:
|
||||
StrangePolygonCheckProcessor () { }
|
||||
|
||||
virtual void process (const db::Polygon &poly, std::vector<db::Polygon> &res) const
|
||||
{
|
||||
EdgeProcessor ep;
|
||||
ep.insert (poly);
|
||||
|
||||
StrangePolygonInsideFunc inside;
|
||||
db::GenericMerge<StrangePolygonInsideFunc> op (inside);
|
||||
db::PolygonContainer pc (res, false);
|
||||
db::PolygonGenerator pg (pc, false, false);
|
||||
ep.process (pg, op);
|
||||
}
|
||||
|
||||
virtual const TransformationReducer *vars () const { return 0; }
|
||||
virtual bool result_is_merged () const { return false; }
|
||||
virtual bool requires_raw_input () const { return true; }
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
// Smoothing processor
|
||||
|
||||
class SmoothingProcessor
|
||||
: public PolygonProcessorBase
|
||||
{
|
||||
public:
|
||||
SmoothingProcessor (db::Coord d) : m_d (d) { }
|
||||
|
||||
virtual void process (const db::Polygon &poly, std::vector<db::Polygon> &res) const
|
||||
{
|
||||
res.push_back (db::smooth (poly, m_d));
|
||||
}
|
||||
|
||||
virtual const TransformationReducer *vars () const { return &m_vars; }
|
||||
virtual bool result_is_merged () const { return false; }
|
||||
virtual bool requires_raw_input () const { return false; }
|
||||
|
||||
private:
|
||||
db::Coord m_d;
|
||||
db::MagnificationReducer m_vars;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
// Rounded corners processor
|
||||
|
||||
class RoundedCornersProcessor
|
||||
: public PolygonProcessorBase
|
||||
{
|
||||
public:
|
||||
RoundedCornersProcessor (double rinner, double router, unsigned int n)
|
||||
: m_rinner (rinner), m_router (router), m_n (n)
|
||||
{ }
|
||||
|
||||
virtual void process (const db::Polygon &poly, std::vector<db::Polygon> &res) const
|
||||
{
|
||||
res.push_back (db::compute_rounded (poly, m_rinner, m_router, m_n));
|
||||
}
|
||||
|
||||
virtual const TransformationReducer *vars () const { return &m_vars; }
|
||||
virtual bool result_is_merged () const { return true; } // we believe so ...
|
||||
virtual bool requires_raw_input () const { return false; }
|
||||
|
||||
private:
|
||||
double m_rinner, m_router;
|
||||
unsigned int m_n;
|
||||
db::MagnificationReducer m_vars;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
// Holes decomposition processor
|
||||
|
||||
class HolesExtractionProcessor
|
||||
: public PolygonProcessorBase
|
||||
{
|
||||
public:
|
||||
HolesExtractionProcessor () { }
|
||||
|
||||
virtual void process (const db::Polygon &poly, std::vector<db::Polygon> &res) const
|
||||
{
|
||||
for (size_t i = 0; i < poly.holes (); ++i) {
|
||||
res.push_back (db::Polygon ());
|
||||
res.back ().assign_hull (poly.begin_hole ((unsigned int) i), poly.end_hole ((unsigned int) i));
|
||||
}
|
||||
}
|
||||
|
||||
virtual const TransformationReducer *vars () const { return 0; }
|
||||
virtual bool result_is_merged () const { return true; } // we believe so ...
|
||||
virtual bool requires_raw_input () const { return false; }
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
// Hull extraction processor
|
||||
|
||||
class HullExtractionProcessor
|
||||
: public PolygonProcessorBase
|
||||
{
|
||||
public:
|
||||
HullExtractionProcessor () { }
|
||||
|
||||
virtual void process (const db::Polygon &poly, std::vector<db::Polygon> &res) const
|
||||
{
|
||||
res.push_back (db::Polygon ());
|
||||
res.back ().assign_hull (poly.begin_hull (), poly.end_hull ());
|
||||
}
|
||||
|
||||
virtual const TransformationReducer *vars () const { return 0; }
|
||||
virtual bool result_is_merged () const { return true; } // we believe so ...
|
||||
virtual bool requires_raw_input () const { return false; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
// Region implementation
|
||||
|
||||
|
|
@ -174,6 +308,86 @@ Region::flat_region ()
|
|||
return region;
|
||||
}
|
||||
|
||||
Region &
|
||||
Region::size (coord_type d, unsigned int mode)
|
||||
{
|
||||
set_delegate (mp_delegate->sized (d, mode));
|
||||
return *this;
|
||||
}
|
||||
|
||||
Region &
|
||||
Region::size (coord_type dx, coord_type dy, unsigned int mode)
|
||||
{
|
||||
set_delegate (mp_delegate->sized (dx, dy, mode));
|
||||
return *this;
|
||||
}
|
||||
|
||||
Region
|
||||
Region::sized (coord_type d, unsigned int mode) const
|
||||
{
|
||||
return Region (mp_delegate->sized (d, mode));
|
||||
}
|
||||
|
||||
Region
|
||||
Region::sized (coord_type dx, coord_type dy, unsigned int mode) const
|
||||
{
|
||||
return Region (mp_delegate->sized (dx, dy, mode));
|
||||
}
|
||||
|
||||
void
|
||||
Region::round_corners (double rinner, double router, unsigned int n)
|
||||
{
|
||||
process (RoundedCornersProcessor (rinner, router, n));
|
||||
}
|
||||
|
||||
Region
|
||||
Region::rounded_corners (double rinner, double router, unsigned int n) const
|
||||
{
|
||||
return processed (RoundedCornersProcessor (rinner, router, n));
|
||||
}
|
||||
|
||||
void
|
||||
Region::smooth (coord_type d)
|
||||
{
|
||||
process (SmoothingProcessor (d));
|
||||
}
|
||||
|
||||
Region
|
||||
Region::smoothed (coord_type d) const
|
||||
{
|
||||
return processed (SmoothingProcessor (d));
|
||||
}
|
||||
|
||||
void
|
||||
Region::snap (db::Coord gx, db::Coord gy)
|
||||
{
|
||||
set_delegate (mp_delegate->snapped_in_place (gx, gy));
|
||||
}
|
||||
|
||||
Region
|
||||
Region::snapped (db::Coord gx, db::Coord gy) const
|
||||
{
|
||||
return Region (mp_delegate->snapped (gx, gy));
|
||||
}
|
||||
|
||||
Region
|
||||
Region::strange_polygon_check () const
|
||||
{
|
||||
return Region (processed (StrangePolygonCheckProcessor ()));
|
||||
}
|
||||
|
||||
Region
|
||||
Region::holes () const
|
||||
{
|
||||
return Region (processed (HolesExtractionProcessor ()));
|
||||
}
|
||||
|
||||
Region
|
||||
Region::hulls () const
|
||||
{
|
||||
return Region (processed (HullExtractionProcessor ()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace tl
|
||||
|
|
|
|||
|
|
@ -42,19 +42,6 @@ class EmptyRegion;
|
|||
class DeepShapeStore;
|
||||
class TransformationReducer;
|
||||
|
||||
/**
|
||||
* @brief A base class for polygon filters
|
||||
*/
|
||||
class DB_PUBLIC PolygonFilterBase
|
||||
{
|
||||
public:
|
||||
PolygonFilterBase () { }
|
||||
virtual ~PolygonFilterBase () { }
|
||||
|
||||
virtual bool selected (const db::Polygon &polygon) const = 0;
|
||||
virtual const TransformationReducer *vars () const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A region iterator
|
||||
*
|
||||
|
|
@ -640,6 +627,39 @@ public:
|
|||
return Region (mp_delegate->filtered (filter));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Processes the (merged) polygons
|
||||
*
|
||||
* This method will keep all polygons for which the processing filter returns true.
|
||||
* The processing filter can apply modifications too. These modifications will be
|
||||
* kept in the output region.
|
||||
*
|
||||
* Merged semantics applies. In merged semantics, the filter will run over
|
||||
* all merged polygons.
|
||||
*/
|
||||
Region &process (const PolygonProcessorBase &filter)
|
||||
{
|
||||
set_delegate (mp_delegate->process_in_place (filter));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the processed polygons
|
||||
*
|
||||
* This method will keep all polygons for which the processing filter returns true.
|
||||
* The processing filter can apply modifications too. These modifications will be
|
||||
* kept in the output region.
|
||||
*
|
||||
* Merged semantics applies. In merged semantics, the filter will run over
|
||||
* all merged polygons.
|
||||
*
|
||||
* This method will return a new region with the modified and filtered polygons.
|
||||
*/
|
||||
Region processed (const PolygonProcessorBase &filter) const
|
||||
{
|
||||
return Region (mp_delegate->processed (filter));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Applies a width check and returns EdgePairs which correspond to violation markers
|
||||
*
|
||||
|
|
@ -844,18 +864,12 @@ public:
|
|||
* Snaps the vertices of the polygons to the specified grid.
|
||||
* different grids can be specified int x and y direction.
|
||||
*/
|
||||
void snap (db::Coord gx, db::Coord gy)
|
||||
{
|
||||
set_delegate (mp_delegate->snapped_in_place (gx, gy));
|
||||
}
|
||||
void snap (db::Coord gx, db::Coord gy);
|
||||
|
||||
/**
|
||||
* @brief Returns the snapped region
|
||||
*/
|
||||
Region snapped (db::Coord gx, db::Coord gy) const
|
||||
{
|
||||
return Region (mp_delegate->snapped (gx, gy));
|
||||
}
|
||||
Region snapped (db::Coord gx, db::Coord gy) const;
|
||||
|
||||
/**
|
||||
* @brief Performs a check for "strange" polygons
|
||||
|
|
@ -865,10 +879,7 @@ public:
|
|||
*
|
||||
* Naturally this method will ignore the merged_semantics setting.
|
||||
*/
|
||||
Region strange_polygon_check () const
|
||||
{
|
||||
return Region (mp_delegate->strange_polygon_check ());
|
||||
}
|
||||
Region strange_polygon_check () const;
|
||||
|
||||
/**
|
||||
* @brief Swap with the other region
|
||||
|
|
@ -948,11 +959,7 @@ public:
|
|||
* @param mode The sizing mode (see EdgeProcessor) for a description of the sizing mode which controls the miter distance.
|
||||
* @return A reference to self
|
||||
*/
|
||||
Region &size (coord_type d, unsigned int mode = 2)
|
||||
{
|
||||
set_delegate (mp_delegate->sized (d, mode));
|
||||
return *this;
|
||||
}
|
||||
Region &size (coord_type d, unsigned int mode = 2);
|
||||
|
||||
/**
|
||||
* @brief Anisotropic sizing
|
||||
|
|
@ -966,11 +973,7 @@ public:
|
|||
* @param dy The vertical sizing
|
||||
* @param mode The sizing mode (see EdgeProcessor) for a description of the sizing mode which controls the miter distance.
|
||||
*/
|
||||
Region &size (coord_type dx, coord_type dy, unsigned int mode = 2)
|
||||
{
|
||||
set_delegate (mp_delegate->sized (dx, dy, mode));
|
||||
return *this;
|
||||
}
|
||||
Region &size (coord_type dx, coord_type dy, unsigned int mode = 2);
|
||||
|
||||
/**
|
||||
* @brief Returns the sized region
|
||||
|
|
@ -980,10 +983,7 @@ public:
|
|||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
Region sized (coord_type d, unsigned int mode = 2) const
|
||||
{
|
||||
return Region (mp_delegate->sized (d, mode));
|
||||
}
|
||||
Region sized (coord_type d, unsigned int mode = 2) const;
|
||||
|
||||
/**
|
||||
* @brief Returns the sized region
|
||||
|
|
@ -993,10 +993,7 @@ public:
|
|||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
Region sized (coord_type dx, coord_type dy, unsigned int mode = 2) const
|
||||
{
|
||||
return Region (mp_delegate->sized (dx, dy, mode));
|
||||
}
|
||||
Region sized (coord_type dx, coord_type dy, unsigned int mode = 2) const;
|
||||
|
||||
/**
|
||||
* @brief Boolean AND operator
|
||||
|
|
@ -1333,10 +1330,7 @@ public:
|
|||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
Region holes () const
|
||||
{
|
||||
return Region (mp_delegate->holes ());
|
||||
}
|
||||
Region holes () const;
|
||||
|
||||
/**
|
||||
* @brief Returns the hulls
|
||||
|
|
@ -1346,10 +1340,7 @@ public:
|
|||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
Region hulls () const
|
||||
{
|
||||
return Region (mp_delegate->hulls ());
|
||||
}
|
||||
Region hulls () const;
|
||||
|
||||
/**
|
||||
* @brief Returns all polygons which are in the other region
|
||||
|
|
@ -1374,36 +1365,24 @@ public:
|
|||
* @param router The outer radius in DBU units
|
||||
* @param n The number of points to use per circle
|
||||
*/
|
||||
void round_corners (double rinner, double router, unsigned int n)
|
||||
{
|
||||
set_delegate (mp_delegate->rounded_corners (rinner, router, n));
|
||||
}
|
||||
void round_corners (double rinner, double router, unsigned int n);
|
||||
|
||||
/**
|
||||
* @brief Returns a new region with rounded corners (out of place)
|
||||
*/
|
||||
Region rounded_corners (double rinner, double router, unsigned int n) const
|
||||
{
|
||||
return Region (mp_delegate->rounded_corners (rinner, router, n));
|
||||
}
|
||||
Region rounded_corners (double rinner, double router, unsigned int n) const;
|
||||
|
||||
/**
|
||||
* @brief Smoothes the region (in-place)
|
||||
*/
|
||||
void smooth (coord_type d)
|
||||
{
|
||||
set_delegate (mp_delegate->smoothed (d));
|
||||
}
|
||||
void smooth (coord_type d);
|
||||
|
||||
/**
|
||||
* @brief Returns the smoothed region
|
||||
*
|
||||
* @param d The smoothing accuracy
|
||||
*/
|
||||
Region smoothed (coord_type d) const
|
||||
{
|
||||
return Region (mp_delegate->smoothed (d));
|
||||
}
|
||||
Region smoothed (coord_type d) const;
|
||||
|
||||
/**
|
||||
* @brief Returns the nth polygon
|
||||
|
|
|
|||
|
|
@ -37,7 +37,34 @@ namespace db {
|
|||
|
||||
class RecursiveShapeIterator;
|
||||
class EdgeFilterBase;
|
||||
class PolygonFilterBase;
|
||||
|
||||
/**
|
||||
* @brief A base class for polygon filters
|
||||
*/
|
||||
class DB_PUBLIC PolygonFilterBase
|
||||
{
|
||||
public:
|
||||
PolygonFilterBase () { }
|
||||
virtual ~PolygonFilterBase () { }
|
||||
|
||||
virtual bool selected (const db::Polygon &polygon) const = 0;
|
||||
virtual const TransformationReducer *vars () const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A base class for polygon processors
|
||||
*/
|
||||
class DB_PUBLIC PolygonProcessorBase
|
||||
{
|
||||
public:
|
||||
PolygonProcessorBase () { }
|
||||
virtual ~PolygonProcessorBase () { }
|
||||
|
||||
virtual void process (const db::Polygon &polygon, std::vector<db::Polygon> &res) const = 0;
|
||||
virtual const TransformationReducer *vars () const = 0;
|
||||
virtual bool result_is_merged () const = 0;
|
||||
virtual bool requires_raw_input () const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The region iterator delegate
|
||||
|
|
@ -141,14 +168,14 @@ public:
|
|||
virtual Edges edges (const EdgeFilterBase *filter) const = 0;
|
||||
virtual RegionDelegate *filter_in_place (const PolygonFilterBase &filter) = 0;
|
||||
virtual RegionDelegate *filtered (const PolygonFilterBase &filter) const = 0;
|
||||
virtual RegionDelegate *process_in_place (const PolygonProcessorBase &filter) = 0;
|
||||
virtual RegionDelegate *processed (const PolygonProcessorBase &filter) const = 0;
|
||||
|
||||
virtual RegionDelegate *merged_in_place () = 0;
|
||||
virtual RegionDelegate *merged_in_place (bool min_coherence, unsigned int min_wc) = 0;
|
||||
virtual RegionDelegate *merged () const = 0;
|
||||
virtual RegionDelegate *merged (bool min_coherence, unsigned int min_wc) const = 0;
|
||||
|
||||
virtual RegionDelegate *strange_polygon_check () const = 0;
|
||||
|
||||
virtual RegionDelegate *sized (coord_type d, unsigned int mode) const = 0;
|
||||
virtual RegionDelegate *sized (coord_type dx, coord_type dy, unsigned int mode) const = 0;
|
||||
|
||||
|
|
@ -169,12 +196,7 @@ public:
|
|||
virtual RegionDelegate *selected_not_interacting (const Edges &other) const = 0;
|
||||
virtual RegionDelegate *selected_overlapping (const Region &other) const = 0;
|
||||
virtual RegionDelegate *selected_not_overlapping (const Region &other) const = 0;
|
||||
|
||||
virtual RegionDelegate *holes () const = 0;
|
||||
virtual RegionDelegate *hulls () const = 0;
|
||||
virtual RegionDelegate *in (const Region &other, bool invert) const = 0;
|
||||
virtual RegionDelegate *rounded_corners (double rinner, double router, unsigned int n) const = 0;
|
||||
virtual RegionDelegate *smoothed (coord_type d) const = 0;
|
||||
|
||||
virtual const db::Polygon *nth (size_t n) const = 0;
|
||||
virtual bool has_valid_polygons () const = 0;
|
||||
|
|
|
|||
|
|
@ -23,9 +23,306 @@
|
|||
|
||||
#include "dbRegionUtils.h"
|
||||
|
||||
namespace db {
|
||||
namespace db
|
||||
{
|
||||
|
||||
// .. nothing yet ..
|
||||
// -------------------------------------------------------------------------------------
|
||||
// Edge2EdgeCheckBase implementation
|
||||
|
||||
Edge2EdgeCheckBase::Edge2EdgeCheckBase (const EdgeRelationFilter &check, bool different_polygons, bool requires_different_layers)
|
||||
: mp_check (&check), m_requires_different_layers (requires_different_layers), m_different_polygons (different_polygons),
|
||||
m_pass (0)
|
||||
{
|
||||
m_distance = check.distance ();
|
||||
}
|
||||
|
||||
bool
|
||||
Edge2EdgeCheckBase::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) {
|
||||
put (*ep);
|
||||
}
|
||||
++d;
|
||||
++ep;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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)) {
|
||||
|
||||
// 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
|
||||
Edge2EdgeCheckBase::requires_different_layers () const
|
||||
{
|
||||
return m_requires_different_layers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets a value indicating whether the check requires different layers
|
||||
*/
|
||||
void
|
||||
Edge2EdgeCheckBase::set_requires_different_layers (bool f)
|
||||
{
|
||||
m_requires_different_layers = f;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the check requires different layers
|
||||
*/
|
||||
bool
|
||||
Edge2EdgeCheckBase::different_polygons () const
|
||||
{
|
||||
return m_different_polygons;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets a value indicating whether the check requires different layers
|
||||
*/
|
||||
void
|
||||
Edge2EdgeCheckBase::set_different_polygons (bool f)
|
||||
{
|
||||
m_different_polygons = f;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the distance value
|
||||
*/
|
||||
EdgeRelationFilter::distance_type
|
||||
Edge2EdgeCheckBase::distance () const
|
||||
{
|
||||
return m_distance;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// Poly2PolyCheckBase implementation
|
||||
|
||||
Poly2PolyCheckBase::Poly2PolyCheckBase (Edge2EdgeCheckBase &output)
|
||||
: mp_output (& output)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void
|
||||
Poly2PolyCheckBase::finish (const db::Polygon *o, size_t p)
|
||||
{
|
||||
enter (*o, p);
|
||||
}
|
||||
|
||||
void
|
||||
Poly2PolyCheckBase::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
|
||||
Poly2PolyCheckBase::add (const db::Polygon *o1, size_t p1, const db::Polygon *o2, size_t p2)
|
||||
{
|
||||
enter (*o1, p1, *o2, p2);
|
||||
}
|
||||
|
||||
void
|
||||
Poly2PolyCheckBase::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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// RegionToEdgeInteractionFilterBase implementation
|
||||
|
||||
RegionToEdgeInteractionFilterBase::RegionToEdgeInteractionFilterBase (bool inverse)
|
||||
: m_inverse (inverse)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void
|
||||
RegionToEdgeInteractionFilterBase::preset (const db::Polygon *poly)
|
||||
{
|
||||
m_seen.insert (poly);
|
||||
}
|
||||
|
||||
void
|
||||
RegionToEdgeInteractionFilterBase::add (const db::Polygon *p, size_t, const db::Edge *e, size_t)
|
||||
{
|
||||
if ((m_seen.find (p) == m_seen.end ()) != m_inverse) {
|
||||
|
||||
// A polygon and an edge interact if the edge is either inside completely
|
||||
// of at least one edge of the polygon intersects with the edge
|
||||
bool interacts = false;
|
||||
if (p->box ().contains (e->p1 ()) && db::inside_poly (p->begin_edge (), e->p1 ()) >= 0) {
|
||||
interacts = true;
|
||||
} else {
|
||||
for (db::Polygon::polygon_edge_iterator pe = p->begin_edge (); ! pe.at_end () && ! interacts; ++pe) {
|
||||
if ((*pe).intersect (*e)) {
|
||||
interacts = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (interacts) {
|
||||
if (m_inverse) {
|
||||
m_seen.erase (p);
|
||||
} else {
|
||||
m_seen.insert (p);
|
||||
put (*p);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RegionToEdgeInteractionFilterBase::fill_output ()
|
||||
{
|
||||
for (std::set<const db::Polygon *>::const_iterator p = m_seen.begin (); p != m_seen.end (); ++p) {
|
||||
put (**p);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "dbCommon.h"
|
||||
#include "dbRegion.h"
|
||||
#include "dbCellVariants.h"
|
||||
#include "dbBoxScanner.h"
|
||||
|
||||
namespace db {
|
||||
|
||||
|
|
@ -310,6 +311,168 @@ private:
|
|||
db::MagnificationAndOrientationReducer m_anisotropic_vars;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A helper class for the DRC functionality which acts as an edge pair receiver
|
||||
*/
|
||||
class Edge2EdgeCheckBase
|
||||
: public db::box_scanner_receiver<db::Edge, size_t>
|
||||
{
|
||||
public:
|
||||
Edge2EdgeCheckBase (const EdgeRelationFilter &check, bool different_polygons, bool requires_different_layers);
|
||||
|
||||
/**
|
||||
* @brief Call this to initiate a new pass until the return value is false
|
||||
*/
|
||||
bool prepare_next_pass ();
|
||||
|
||||
/**
|
||||
* @brief Reimplementation of the box_scanner_receiver interface
|
||||
*/
|
||||
void add (const db::Edge *o1, size_t p1, const db::Edge *o2, size_t p2);
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the check requires different layers
|
||||
*/
|
||||
bool requires_different_layers () const;
|
||||
|
||||
/**
|
||||
* @brief Sets a value indicating whether the check requires different layers
|
||||
*/
|
||||
void set_requires_different_layers (bool f);
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the check requires different layers
|
||||
*/
|
||||
bool different_polygons () const;
|
||||
|
||||
/**
|
||||
* @brief Sets a value indicating whether the check requires different layers
|
||||
*/
|
||||
void set_different_polygons (bool f);
|
||||
|
||||
/**
|
||||
* @brief Gets the distance value
|
||||
*/
|
||||
EdgeRelationFilter::distance_type distance () const;
|
||||
|
||||
protected:
|
||||
virtual void put (const db::EdgePair &edge) const = 0;
|
||||
|
||||
private:
|
||||
const EdgeRelationFilter *mp_check;
|
||||
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 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)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
protected:
|
||||
void put (const db::EdgePair &edge) const
|
||||
{
|
||||
mp_output->insert (edge);
|
||||
}
|
||||
|
||||
private:
|
||||
Output *mp_output;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A helper class for the DRC functionality which acts as an edge pair receiver
|
||||
*/
|
||||
class Poly2PolyCheckBase
|
||||
: public db::box_scanner_receiver<db::Polygon, size_t>
|
||||
{
|
||||
public:
|
||||
Poly2PolyCheckBase (Edge2EdgeCheckBase &output);
|
||||
|
||||
void finish (const db::Polygon *o, size_t p);
|
||||
void enter (const db::Polygon &o, size_t p);
|
||||
void add (const db::Polygon *o1, size_t p1, const db::Polygon *o2, size_t p2);
|
||||
void enter (const db::Polygon &o1, size_t p1, const db::Polygon &o2, size_t p2);
|
||||
|
||||
private:
|
||||
db::Edge2EdgeCheckBase *mp_output;
|
||||
db::box_scanner<db::Edge, size_t> m_scanner;
|
||||
std::vector<db::Edge> m_edges;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A helper class for the DRC functionality which acts as an edge pair receiver
|
||||
*/
|
||||
template <class Output>
|
||||
class poly2poly_check
|
||||
: public Poly2PolyCheckBase
|
||||
{
|
||||
public:
|
||||
poly2poly_check (edge2edge_check<Output> &output)
|
||||
: Poly2PolyCheckBase (output)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A helper class for the region to edge interaction functionality
|
||||
*/
|
||||
class DB_PUBLIC RegionToEdgeInteractionFilterBase
|
||||
: public db::box_scanner_receiver2<db::Polygon, size_t, db::Edge, size_t>
|
||||
{
|
||||
public:
|
||||
RegionToEdgeInteractionFilterBase (bool inverse);
|
||||
|
||||
void preset (const db::Polygon *poly);
|
||||
void add (const db::Polygon *p, size_t, const db::Edge *e, size_t);
|
||||
void fill_output ();
|
||||
|
||||
protected:
|
||||
virtual void put (const db::Polygon &poly) const = 0;
|
||||
|
||||
private:
|
||||
std::set<const db::Polygon *> m_seen;
|
||||
bool m_inverse;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A helper class for the region to edge interaction functionality
|
||||
*/
|
||||
template <class OutputContainer>
|
||||
class DB_PUBLIC region_to_edge_interaction_filter
|
||||
: public RegionToEdgeInteractionFilterBase
|
||||
{
|
||||
public:
|
||||
region_to_edge_interaction_filter (OutputContainer &output, bool inverse)
|
||||
: RegionToEdgeInteractionFilterBase (inverse), mp_output (&output)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void put (const db::Polygon &poly) const
|
||||
{
|
||||
mp_output->insert (poly);
|
||||
}
|
||||
|
||||
private:
|
||||
OutputContainer *mp_output;
|
||||
};
|
||||
|
||||
} // namespace db
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -112,6 +112,14 @@ struct EPTestFilter
|
|||
{
|
||||
return ep.first ().double_length () < 50;
|
||||
}
|
||||
|
||||
const db::TransformationReducer *vars () const
|
||||
{
|
||||
return &m_vars;
|
||||
}
|
||||
|
||||
private:
|
||||
db::MagnificationReducer m_vars;
|
||||
};
|
||||
|
||||
TEST(3)
|
||||
|
|
|
|||
Binary file not shown.
Loading…
Reference in New Issue