mirror of https://github.com/KLayout/klayout.git
Refactoring of edges processor.
This commit is contained in:
parent
496b695ef0
commit
3dd1ed4c4d
|
|
@ -25,6 +25,7 @@
|
|||
#include "dbFlatEdges.h"
|
||||
#include "dbEmptyEdges.h"
|
||||
#include "dbEdges.h"
|
||||
#include "dbEdgesUtils.h"
|
||||
#include "dbEdgeBoolean.h"
|
||||
#include "dbBoxConvert.h"
|
||||
#include "dbRegion.h"
|
||||
|
|
@ -41,127 +42,6 @@
|
|||
namespace db
|
||||
{
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
// JoinEdgesCluster implementation
|
||||
|
||||
JoinEdgesCluster::JoinEdgesCluster (db::PolygonSink *output, coord_type ext_b, coord_type ext_e, coord_type ext_o, coord_type ext_i)
|
||||
: mp_output (output), m_ext_b (ext_b), m_ext_e (ext_e), m_ext_o (ext_o), m_ext_i (ext_i)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void
|
||||
JoinEdgesCluster::finish ()
|
||||
{
|
||||
std::multimap<db::Point, iterator> objects_by_p1;
|
||||
std::multimap<db::Point, iterator> objects_by_p2;
|
||||
for (iterator o = begin (); o != end (); ++o) {
|
||||
if (o->first->p1 () != o->first->p2 ()) {
|
||||
objects_by_p1.insert (std::make_pair (o->first->p1 (), o));
|
||||
objects_by_p2.insert (std::make_pair (o->first->p2 (), o));
|
||||
}
|
||||
}
|
||||
|
||||
while (! objects_by_p2.empty ()) {
|
||||
|
||||
tl_assert (! objects_by_p1.empty ());
|
||||
|
||||
// Find the beginning of a new sequence
|
||||
std::multimap<db::Point, iterator>::iterator j0 = objects_by_p1.begin ();
|
||||
std::multimap<db::Point, iterator>::iterator j = j0;
|
||||
do {
|
||||
std::multimap<db::Point, iterator>::iterator jj = objects_by_p2.find (j->first);
|
||||
if (jj == objects_by_p2.end ()) {
|
||||
break;
|
||||
} else {
|
||||
j = objects_by_p1.find (jj->second->first->p1 ());
|
||||
tl_assert (j != objects_by_p1.end ());
|
||||
}
|
||||
} while (j != j0);
|
||||
|
||||
iterator i = j->second;
|
||||
|
||||
// determine a sequence
|
||||
// TODO: this chooses any solution in case of forks. Choose a specific one?
|
||||
std::vector<db::Point> pts;
|
||||
pts.push_back (i->first->p1 ());
|
||||
|
||||
do {
|
||||
|
||||
// record the next point
|
||||
pts.push_back (i->first->p2 ());
|
||||
|
||||
// remove the edge as it's taken
|
||||
std::multimap<db::Point, iterator>::iterator jj;
|
||||
for (jj = objects_by_p2.find (i->first->p2 ()); jj != objects_by_p2.end () && jj->first == i->first->p2 (); ++jj) {
|
||||
if (jj->second == i) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
tl_assert (jj != objects_by_p2.end () && jj->second == i);
|
||||
objects_by_p2.erase (jj);
|
||||
objects_by_p1.erase (j);
|
||||
|
||||
// process along the edge to the next one
|
||||
// TODO: this chooses any solution in case of forks. Choose a specific one?
|
||||
j = objects_by_p1.find (i->first->p2 ());
|
||||
if (j != objects_by_p1.end ()) {
|
||||
i = j->second;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
} while (true);
|
||||
|
||||
bool cyclic = (pts.back () == pts.front ());
|
||||
|
||||
if (! cyclic) {
|
||||
|
||||
// non-cyclic sequence
|
||||
db::Path path (pts.begin (), pts.end (), 0, m_ext_b, m_ext_e, false);
|
||||
std::vector<db::Point> hull;
|
||||
path.hull (hull, m_ext_o, m_ext_i);
|
||||
db::Polygon poly;
|
||||
poly.assign_hull (hull.begin (), hull.end ());
|
||||
mp_output->put (poly);
|
||||
|
||||
} else {
|
||||
|
||||
// we have a loop: form a contour by using the polygon size functions and a "Not" to form the hole
|
||||
db::Polygon poly;
|
||||
poly.assign_hull (pts.begin (), pts.end ());
|
||||
|
||||
db::EdgeProcessor ep;
|
||||
db::PolygonGenerator pg (*mp_output, false, true);
|
||||
|
||||
int mode_a = -1, mode_b = -1;
|
||||
|
||||
if (m_ext_o == 0) {
|
||||
ep.insert (poly, 0);
|
||||
} else {
|
||||
db::Polygon sized_poly (poly);
|
||||
sized_poly.size (m_ext_o, m_ext_o, 2 /*sizing mode*/);
|
||||
ep.insert (sized_poly, 0);
|
||||
mode_a = 1;
|
||||
}
|
||||
|
||||
if (m_ext_i == 0) {
|
||||
ep.insert (poly, 1);
|
||||
} else {
|
||||
db::Polygon sized_poly (poly);
|
||||
sized_poly.size (-m_ext_i, -m_ext_i, 2 /*sizing mode*/);
|
||||
ep.insert (sized_poly, 1);
|
||||
mode_b = 1;
|
||||
}
|
||||
|
||||
db::BooleanOp2 op (db::BooleanOp::ANotB, mode_a, mode_b);
|
||||
ep.process (pg, op);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
// AsIfFlagEdges implementation
|
||||
|
||||
|
|
@ -277,30 +157,6 @@ struct JoinEdgesClusterCollector
|
|||
|
||||
}
|
||||
|
||||
db::Polygon
|
||||
AsIfFlatEdges::extended_edge (const db::Edge &edge, coord_type ext_b, coord_type ext_e, coord_type ext_o, coord_type ext_i)
|
||||
{
|
||||
db::DVector d;
|
||||
if (edge.is_degenerate ()) {
|
||||
d = db::DVector (1.0, 0.0);
|
||||
} else {
|
||||
d = db::DVector (edge.d ()) * (1.0 / edge.double_length ());
|
||||
}
|
||||
|
||||
db::DVector n (-d.y (), d.x ());
|
||||
|
||||
db::Point pts[4] = {
|
||||
db::Point (db::DPoint (edge.p1 ()) - d * double (ext_b) + n * double (ext_o)),
|
||||
db::Point (db::DPoint (edge.p2 ()) + d * double (ext_e) + n * double (ext_o)),
|
||||
db::Point (db::DPoint (edge.p2 ()) + d * double (ext_e) - n * double (ext_i)),
|
||||
db::Point (db::DPoint (edge.p1 ()) - d * double (ext_b) - n * double (ext_i)),
|
||||
};
|
||||
|
||||
db::Polygon poly;
|
||||
poly.assign_hull (pts + 0, pts + 4);
|
||||
return poly;
|
||||
}
|
||||
|
||||
RegionDelegate *
|
||||
AsIfFlatEdges::extended (coord_type ext_b, coord_type ext_e, coord_type ext_o, coord_type ext_i, bool join) const
|
||||
{
|
||||
|
|
@ -337,65 +193,6 @@ AsIfFlatEdges::extended (coord_type ext_b, coord_type ext_e, coord_type ext_o, c
|
|||
}
|
||||
}
|
||||
|
||||
db::Edge
|
||||
AsIfFlatEdges::compute_partial (const db::Edge &edge, int mode, length_type length, double fraction)
|
||||
{
|
||||
double l = std::max (edge.double_length () * fraction, double (length));
|
||||
|
||||
if (mode < 0) {
|
||||
|
||||
return db::Edge (edge.p1 (), db::Point (db::DPoint (edge.p1 ()) + db::DVector (edge.d ()) * (l / edge.double_length ())));
|
||||
|
||||
} else if (mode > 0) {
|
||||
|
||||
return db::Edge (db::Point (db::DPoint (edge.p2 ()) - db::DVector (edge.d ()) * (l / edge.double_length ())), edge.p2 ());
|
||||
|
||||
} else {
|
||||
|
||||
db::DVector dl = db::DVector (edge.d ()) * (0.5 * l / edge.double_length ());
|
||||
db::DPoint center = db::DPoint (edge.p1 ()) + db::DVector (edge.p2 () - edge.p1 ()) * 0.5;
|
||||
|
||||
return db::Edge (db::Point (center - dl), db::Point (center + dl));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
AsIfFlatEdges::segments (int mode, length_type length, double fraction) const
|
||||
{
|
||||
std::auto_ptr<FlatEdges> edges (new FlatEdges ());
|
||||
edges->reserve (size ());
|
||||
|
||||
// zero-length edges would vanish in merged sematics, so we don't set it now
|
||||
if (length == 0) {
|
||||
edges->set_merged_semantics (false);
|
||||
}
|
||||
|
||||
for (EdgesIterator e (begin_merged ()); ! e.at_end (); ++e) {
|
||||
edges->insert (compute_partial (*e, mode, length, fraction));
|
||||
}
|
||||
|
||||
return edges.release ();
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
AsIfFlatEdges::start_segments (length_type length, double fraction) const
|
||||
{
|
||||
return segments (-1, length, fraction);
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
AsIfFlatEdges::end_segments (length_type length, double fraction) const
|
||||
{
|
||||
return segments (1, length, fraction);
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
AsIfFlatEdges::centers (length_type length, double fraction) const
|
||||
{
|
||||
return segments (0, length, fraction);
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
AsIfFlatEdges::selected_interacting_generic (const Edges &edges, bool inverse) const
|
||||
{
|
||||
|
|
@ -543,6 +340,28 @@ void AsIfFlatEdges::invalidate_bbox ()
|
|||
m_bbox_valid = false;
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
AsIfFlatEdges::processed (const EdgeProcessorBase &filter) const
|
||||
{
|
||||
std::auto_ptr<FlatEdges> edges (new FlatEdges ());
|
||||
|
||||
if (filter.result_must_not_be_merged ()) {
|
||||
edges->set_merged_semantics (false);
|
||||
}
|
||||
|
||||
std::vector<db::Edge> res_edges;
|
||||
|
||||
for (EdgesIterator e (filter.requires_raw_input () ? begin () : begin_merged ()); ! e.at_end (); ++e) {
|
||||
res_edges.clear ();
|
||||
filter.process (*e, res_edges);
|
||||
for (std::vector<db::Edge>::const_iterator er = res_edges.begin (); er != res_edges.end (); ++er) {
|
||||
edges->insert (*er);
|
||||
}
|
||||
}
|
||||
|
||||
return edges.release ();
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
AsIfFlatEdges::filtered (const EdgeFilterBase &filter) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -37,133 +37,6 @@ namespace db {
|
|||
|
||||
class PolygonSink;
|
||||
|
||||
/**
|
||||
* @brief A helper class for the edge interaction functionality which acts as an edge pair receiver
|
||||
*/
|
||||
template <class OutputContainer>
|
||||
class edge_interaction_filter
|
||||
: public db::box_scanner_receiver<db::Edge, size_t>
|
||||
{
|
||||
public:
|
||||
edge_interaction_filter (OutputContainer &output)
|
||||
: mp_output (&output)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void add (const db::Edge *o1, size_t p1, const db::Edge *o2, size_t p2)
|
||||
{
|
||||
// Select the edges which intersect
|
||||
if (p1 != p2) {
|
||||
const db::Edge *o = p1 > p2 ? o2 : o1;
|
||||
const db::Edge *oo = p1 > p2 ? o1 : o2;
|
||||
if (o->intersect (*oo)) {
|
||||
if (m_seen.insert (o).second) {
|
||||
mp_output->insert (*o);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
OutputContainer *mp_output;
|
||||
std::set<const db::Edge *> m_seen;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A helper class for the edge to region interaction functionality which acts as an edge pair receiver
|
||||
*
|
||||
* Note: This special scanner uses pointers to two different objects: edges and polygons.
|
||||
* It uses odd value pointers to indicate pointers to polygons and even value pointers to indicate
|
||||
* pointers to edges.
|
||||
*
|
||||
* There is a special box converter which is able to sort that out as well.
|
||||
*/
|
||||
template <class OutputContainer>
|
||||
class edge_to_region_interaction_filter
|
||||
: public db::box_scanner_receiver2<db::Edge, size_t, db::Polygon, size_t>
|
||||
{
|
||||
public:
|
||||
edge_to_region_interaction_filter (OutputContainer &output)
|
||||
: mp_output (&output)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void add (const db::Edge *e, size_t, const db::Polygon *p, size_t)
|
||||
{
|
||||
if (m_seen.find (e) == m_seen.end ()) {
|
||||
if (db::interact (*p, *e)) {
|
||||
m_seen.insert (e);
|
||||
mp_output->insert (*e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
OutputContainer *mp_output;
|
||||
std::set<const db::Edge *> m_seen;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A helper class for the DRC functionality which acts as an edge pair receiver
|
||||
*
|
||||
* If will perform a edge by edge check using the provided EdgeRelationFilter
|
||||
*/
|
||||
template <class Output>
|
||||
class edge2edge_check_for_edges
|
||||
: public db::box_scanner_receiver<db::Edge, size_t>
|
||||
{
|
||||
public:
|
||||
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;
|
||||
}
|
||||
|
||||
void add (const db::Edge *o1, size_t p1, const db::Edge *o2, size_t p2)
|
||||
{
|
||||
// Overlap or inside checks require input from different layers
|
||||
if (! 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)) {
|
||||
mp_output->insert (ep);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const EdgeRelationFilter *mp_check;
|
||||
Output *mp_output;
|
||||
bool m_requires_different_layers;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A helper class to turn joined edge sequences into polygons
|
||||
*
|
||||
* This object is an edge cluster so it can connect to a cluster collector
|
||||
* driven by a box scanner.
|
||||
*/
|
||||
struct JoinEdgesCluster
|
||||
: public db::cluster<db::Edge, size_t>
|
||||
{
|
||||
typedef db::Edge::coord_type coord_type;
|
||||
|
||||
JoinEdgesCluster (db::PolygonSink *output, coord_type ext_b, coord_type ext_e, coord_type ext_o, coord_type ext_i);
|
||||
void finish ();
|
||||
|
||||
private:
|
||||
db::PolygonSink *mp_output;
|
||||
coord_type m_ext_b, m_ext_e, m_ext_o, m_ext_i;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Provides default flat implementations
|
||||
*/
|
||||
|
|
@ -209,6 +82,13 @@ public:
|
|||
return run_check (db::InsideRelation, &other, d, whole_edges, metrics, ignore_angle, min_projection, max_projection);
|
||||
}
|
||||
|
||||
virtual EdgesDelegate *process_in_place (const EdgeProcessorBase &filter)
|
||||
{
|
||||
return processed (filter);
|
||||
}
|
||||
|
||||
virtual EdgesDelegate *processed (const EdgeProcessorBase &filter) const;
|
||||
|
||||
virtual EdgesDelegate *filter_in_place (const EdgeFilterBase &filter)
|
||||
{
|
||||
return filtered (filter);
|
||||
|
|
@ -274,9 +154,6 @@ public:
|
|||
}
|
||||
|
||||
virtual RegionDelegate *extended (coord_type ext_b, coord_type ext_e, coord_type ext_o, coord_type ext_i, bool join) const;
|
||||
virtual EdgesDelegate *start_segments (length_type length, double fraction) const;
|
||||
virtual EdgesDelegate *end_segments (length_type length, double fraction) const;
|
||||
virtual EdgesDelegate *centers (length_type length, double fraction) const;
|
||||
|
||||
virtual EdgesDelegate *selected_interacting (const Edges &) const;
|
||||
virtual EdgesDelegate *selected_not_interacting (const Edges &) const;
|
||||
|
|
@ -294,8 +171,6 @@ protected:
|
|||
void update_bbox (const db::Box &box);
|
||||
void invalidate_bbox ();
|
||||
EdgePairs run_check (db::edge_relation_type rel, const Edges *other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const;
|
||||
static db::Polygon extended_edge (const db::Edge &edge, coord_type ext_b, coord_type ext_e, coord_type ext_o, coord_type ext_i);
|
||||
static db::Edge compute_partial (const db::Edge &edge, int mode, length_type length, double fraction);
|
||||
virtual EdgesDelegate *selected_interacting_generic (const Edges &edges, bool inverse) const;
|
||||
virtual EdgesDelegate *selected_interacting_generic (const Region ®ion, bool inverse) const;
|
||||
|
||||
|
|
@ -308,7 +183,6 @@ private:
|
|||
virtual db::Box compute_bbox () const;
|
||||
EdgesDelegate *boolean (const Edges *other, EdgeBoolOp op) const;
|
||||
EdgesDelegate *edge_region_op (const Region &other, bool outside, bool include_borders) const;
|
||||
EdgesDelegate *segments (int mode, length_type length, double fraction) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
*/
|
||||
|
||||
#include "dbEdges.h"
|
||||
#include "dbEdgesUtils.h"
|
||||
#include "dbRegion.h"
|
||||
#include "dbDeepEdges.h"
|
||||
#include "dbDeepRegion.h"
|
||||
|
|
@ -476,6 +477,77 @@ std::string DeepEdges::to_string (size_t nmax) const
|
|||
return db::AsIfFlatEdges::to_string (nmax);
|
||||
}
|
||||
|
||||
EdgesDelegate *DeepEdges::process_in_place (const EdgeProcessorBase &filter)
|
||||
{
|
||||
// TODO: implement to be really in-place
|
||||
return processed (filter);
|
||||
}
|
||||
|
||||
EdgesDelegate *DeepEdges::processed (const EdgeProcessorBase &filter) const
|
||||
{
|
||||
ensure_merged_edges_valid ();
|
||||
|
||||
std::auto_ptr<VariantsCollectorBase> vars;
|
||||
|
||||
if (filter.vars ()) {
|
||||
|
||||
vars.reset (new db::VariantsCollectorBase (filter.vars ()));
|
||||
|
||||
vars->collect (m_merged_edges.layout (), m_merged_edges.initial_cell ());
|
||||
|
||||
// NOTE: m_merged_polygons is mutable, so why is the const_cast needed?
|
||||
const_cast<db::DeepLayer &> (m_merged_edges).separate_variants (*vars);
|
||||
|
||||
}
|
||||
|
||||
db::Layout &layout = m_merged_edges.layout ();
|
||||
std::vector<db::Edge> res_edges;
|
||||
|
||||
std::auto_ptr<db::DeepEdges> res (new db::DeepEdges (m_merged_edges.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_edges.layer ());
|
||||
db::Shapes &st = c->shapes (res->deep_layer ().layer ());
|
||||
|
||||
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Edges); ! si.at_end (); ++si) {
|
||||
res_edges.clear ();
|
||||
filter.process (si->edge ().transformed (tr), res_edges);
|
||||
for (std::vector<db::Edge>::const_iterator er = res_edges.begin (); er != res_edges.end (); ++er) {
|
||||
st.insert (er->transformed (trinv));
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
const db::Shapes &s = c->shapes (filter.requires_raw_input () ? m_deep_layer.layer () : m_merged_edges.layer ());
|
||||
db::Shapes &st = c->shapes (res->deep_layer ().layer ());
|
||||
|
||||
for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Edges); ! si.at_end (); ++si) {
|
||||
res_edges.clear ();
|
||||
filter.process (si->edge (), res_edges);
|
||||
for (std::vector<db::Edge>::const_iterator er = res_edges.begin (); er != res_edges.end (); ++er) {
|
||||
st.insert (*er);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (filter.result_is_merged ()) {
|
||||
res->set_is_merged (true);
|
||||
}
|
||||
|
||||
return res.release ();
|
||||
}
|
||||
|
||||
EdgesDelegate *DeepEdges::filter_in_place (const EdgeFilterBase &filter)
|
||||
{
|
||||
// TODO: implement to be really in-place
|
||||
|
|
@ -917,62 +989,6 @@ RegionDelegate *DeepEdges::extended (coord_type ext_b, coord_type ext_e, coord_t
|
|||
return res.release ();
|
||||
}
|
||||
|
||||
EdgesDelegate *DeepEdges::segments (int mode, length_type length, double fraction) const
|
||||
{
|
||||
ensure_merged_edges_valid ();
|
||||
|
||||
std::auto_ptr<db::DeepEdges> res (new db::DeepEdges (m_merged_edges.derived ()));
|
||||
|
||||
db::Layout &layout = const_cast<db::Layout &> (m_merged_edges.layout ());
|
||||
db::Cell &top_cell = const_cast<db::Cell &> (m_merged_edges.initial_cell ());
|
||||
|
||||
db::MagnificationReducer red;
|
||||
db::cell_variants_collector<db::MagnificationReducer> vars (red);
|
||||
vars.collect (m_merged_edges.layout (), m_merged_edges.initial_cell ());
|
||||
|
||||
std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> > to_commit;
|
||||
|
||||
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||
|
||||
const std::map<db::ICplxTrans, size_t> &vv = vars.variants (c->cell_index ());
|
||||
for (std::map<db::ICplxTrans, size_t>::const_iterator v = vv.begin (); v != vv.end (); ++v) {
|
||||
|
||||
db::Shapes *out;
|
||||
if (vv.size () == 1) {
|
||||
out = & c->shapes (res->deep_layer ().layer ());
|
||||
} else {
|
||||
out = & to_commit [c->cell_index ()][v->first];
|
||||
}
|
||||
|
||||
for (db::Shapes::shape_iterator si = c->shapes (m_merged_edges.layer ()).begin (db::ShapeIterator::Edges); ! si.at_end (); ++si) {
|
||||
out->insert (compute_partial (si->edge ().transformed (v->first), mode, length, fraction).transformed (v->first.inverted ()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// propagate results from variants
|
||||
vars.commit_shapes (layout, top_cell, res->deep_layer ().layer (), to_commit);
|
||||
|
||||
return res.release ();
|
||||
}
|
||||
|
||||
EdgesDelegate *DeepEdges::start_segments (length_type length, double fraction) const
|
||||
{
|
||||
return segments (-1, length, fraction);
|
||||
}
|
||||
|
||||
EdgesDelegate *DeepEdges::end_segments (length_type length, double fraction) const
|
||||
{
|
||||
return segments (1, length, fraction);
|
||||
}
|
||||
|
||||
EdgesDelegate *DeepEdges::centers (length_type length, double fraction) const
|
||||
{
|
||||
return segments (0, length, fraction);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
|
|
|
|||
|
|
@ -110,6 +110,8 @@ public:
|
|||
|
||||
virtual EdgesDelegate *filter_in_place (const EdgeFilterBase &filter);
|
||||
virtual EdgesDelegate *filtered (const EdgeFilterBase &) const;
|
||||
virtual EdgesDelegate *process_in_place (const EdgeProcessorBase &);
|
||||
virtual EdgesDelegate *processed (const EdgeProcessorBase &) const;
|
||||
|
||||
virtual EdgesDelegate *merged_in_place ();
|
||||
virtual EdgesDelegate *merged () const;
|
||||
|
|
@ -131,9 +133,6 @@ public:
|
|||
virtual EdgesDelegate *outside_part (const Region &other) const;
|
||||
|
||||
virtual RegionDelegate *extended (coord_type ext_b, coord_type ext_e, coord_type ext_o, coord_type ext_i, bool join) const;
|
||||
virtual EdgesDelegate *start_segments (length_type length, double fraction) const;
|
||||
virtual EdgesDelegate *end_segments (length_type length, double fraction) const;
|
||||
virtual EdgesDelegate *centers (length_type length, double fraction) const;
|
||||
|
||||
virtual EdgesDelegate *selected_interacting (const Edges &) const;
|
||||
virtual EdgesDelegate *selected_not_interacting (const Edges &) const;
|
||||
|
|
@ -173,7 +172,6 @@ private:
|
|||
DeepLayer and_or_not_with(const DeepEdges *other, bool and_op) const;
|
||||
DeepLayer edge_region_op (const DeepRegion *other, bool outside, bool include_borders) const;
|
||||
EdgePairs run_check (db::edge_relation_type rel, const Edges *other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const;
|
||||
EdgesDelegate *segments (int mode, length_type length, double fraction) const;
|
||||
EdgesDelegate *selected_interacting_generic (const Edges &edges, bool invert) const;
|
||||
EdgesDelegate *selected_interacting_generic (const Region ®ion, bool invert) const;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -30,6 +30,56 @@
|
|||
namespace db
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
// Smoothing processor
|
||||
|
||||
class EdgeSegmentSelector
|
||||
: public EdgeProcessorBase
|
||||
{
|
||||
public:
|
||||
EdgeSegmentSelector (int mode, db::Edges::length_type length, double fraction)
|
||||
: m_mode (mode), m_length (length), m_fraction (fraction)
|
||||
{ }
|
||||
|
||||
virtual void process (const db::Edge &edge, std::vector<db::Edge> &res) const
|
||||
{
|
||||
double l = std::max (edge.double_length () * m_fraction, double (m_length));
|
||||
|
||||
if (m_mode < 0) {
|
||||
|
||||
res.push_back (db::Edge (edge.p1 (), db::Point (db::DPoint (edge.p1 ()) + db::DVector (edge.d ()) * (l / edge.double_length ()))));
|
||||
|
||||
} else if (m_mode > 0) {
|
||||
|
||||
res.push_back (db::Edge (db::Point (db::DPoint (edge.p2 ()) - db::DVector (edge.d ()) * (l / edge.double_length ())), edge.p2 ()));
|
||||
|
||||
} else {
|
||||
|
||||
db::DVector dl = db::DVector (edge.d ()) * (0.5 * l / edge.double_length ());
|
||||
db::DPoint center = db::DPoint (edge.p1 ()) + db::DVector (edge.p2 () - edge.p1 ()) * 0.5;
|
||||
|
||||
res.push_back (db::Edge (db::Point (center - dl), db::Point (center + dl)));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
virtual const TransformationReducer *vars () const { return &m_vars; }
|
||||
virtual bool result_is_merged () const { return false; }
|
||||
virtual bool requires_raw_input () const { return false; }
|
||||
virtual bool result_must_not_be_merged () const { return m_length <= 0; }
|
||||
|
||||
private:
|
||||
int m_mode;
|
||||
db::Edges::length_type m_length;
|
||||
double m_fraction;
|
||||
db::MagnificationReducer m_vars;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
// Edges implementation
|
||||
|
||||
|
|
@ -140,6 +190,21 @@ void Edges::extended (Region &output, coord_type ext_b, coord_type ext_e, coord_
|
|||
output.set_delegate (mp_delegate->extended (ext_b, ext_e, ext_o, ext_i, join));
|
||||
}
|
||||
|
||||
Edges Edges::start_segments (length_type length, double fraction) const
|
||||
{
|
||||
return Edges (mp_delegate->processed (EdgeSegmentSelector (-1, length, fraction)));
|
||||
}
|
||||
|
||||
Edges Edges::end_segments (length_type length, double fraction) const
|
||||
{
|
||||
return Edges (mp_delegate->processed (EdgeSegmentSelector (1, length, fraction)));
|
||||
}
|
||||
|
||||
Edges Edges::centers (length_type length, double fraction) const
|
||||
{
|
||||
return Edges (mp_delegate->processed (EdgeSegmentSelector (0, length, fraction)));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Edges &Edges::transform (const T &trans)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -200,19 +200,6 @@ private:
|
|||
|
||||
class Edges;
|
||||
|
||||
/**
|
||||
* @brief A base class for edge filters
|
||||
*/
|
||||
class DB_PUBLIC EdgeFilterBase
|
||||
{
|
||||
public:
|
||||
EdgeFilterBase () { }
|
||||
virtual ~EdgeFilterBase () { }
|
||||
|
||||
virtual bool selected (const db::Edge &edge) const = 0;
|
||||
virtual const TransformationReducer *vars () const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An edge set
|
||||
*
|
||||
|
|
@ -603,6 +590,39 @@ public:
|
|||
return Edges (mp_delegate->filtered (filter));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Processes the (merged) edges
|
||||
*
|
||||
* This method will keep all edges which the processor returns.
|
||||
* The processing filter can apply modifications too. These modifications will be
|
||||
* kept in the output edge collection.
|
||||
*
|
||||
* Merged semantics applies. In merged semantics, the filter will run over
|
||||
* all merged edges.
|
||||
*/
|
||||
Edges &process (const EdgeProcessorBase &filter)
|
||||
{
|
||||
set_delegate (mp_delegate->process_in_place (filter));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the processed edges
|
||||
*
|
||||
* This method will keep all edges which the processor returns.
|
||||
* The processing filter can apply modifications too. These modifications will be
|
||||
* kept in the output edge collection.
|
||||
*
|
||||
* Merged semantics applies. In merged semantics, the filter will run over
|
||||
* all merged edges.
|
||||
*
|
||||
* This method will return a new edge collection with the modified and filtered edges.
|
||||
*/
|
||||
Edges processed (const EdgeProcessorBase &filter) const
|
||||
{
|
||||
return Edges (mp_delegate->processed (filter));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Applies a width check and returns EdgePairs which correspond to violation markers
|
||||
*
|
||||
|
|
@ -947,10 +967,7 @@ public:
|
|||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
Edges start_segments (length_type length, double fraction) const
|
||||
{
|
||||
return Edges (mp_delegate->start_segments (length, fraction));
|
||||
}
|
||||
Edges start_segments (length_type length, double fraction) const;
|
||||
|
||||
/**
|
||||
* @brief Returns edges (point-like) representing the end part of the edges
|
||||
|
|
@ -960,10 +977,7 @@ public:
|
|||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
Edges end_segments (length_type length, double fraction) const
|
||||
{
|
||||
return Edges (mp_delegate->end_segments (length, fraction));
|
||||
}
|
||||
Edges end_segments (length_type length, double fraction) const;
|
||||
|
||||
/**
|
||||
* @brief Returns edges (point-like) representing the center of the edges
|
||||
|
|
@ -973,10 +987,7 @@ public:
|
|||
*
|
||||
* Merged semantics applies.
|
||||
*/
|
||||
Edges centers (length_type length, double fraction) const
|
||||
{
|
||||
return Edges (mp_delegate->centers (length, fraction));
|
||||
}
|
||||
Edges centers (length_type length, double fraction) const;
|
||||
|
||||
/**
|
||||
* @brief Select the edges inside the given region
|
||||
|
|
|
|||
|
|
@ -34,6 +34,35 @@
|
|||
|
||||
namespace db {
|
||||
|
||||
/**
|
||||
* @brief A base class for edge filters
|
||||
*/
|
||||
class DB_PUBLIC EdgeFilterBase
|
||||
{
|
||||
public:
|
||||
EdgeFilterBase () { }
|
||||
virtual ~EdgeFilterBase () { }
|
||||
|
||||
virtual bool selected (const db::Edge &edge) const = 0;
|
||||
virtual const TransformationReducer *vars () const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A base class for polygon processors
|
||||
*/
|
||||
class DB_PUBLIC EdgeProcessorBase
|
||||
{
|
||||
public:
|
||||
EdgeProcessorBase () { }
|
||||
virtual ~EdgeProcessorBase () { }
|
||||
|
||||
virtual void process (const db::Edge &polygon, std::vector<db::Edge> &res) const = 0;
|
||||
virtual const TransformationReducer *vars () const = 0;
|
||||
virtual bool result_is_merged () const = 0;
|
||||
virtual bool requires_raw_input () const = 0;
|
||||
virtual bool result_must_not_be_merged () const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A common definition for the boolean operations available on edges
|
||||
*/
|
||||
|
|
@ -128,6 +157,8 @@ public:
|
|||
|
||||
virtual EdgesDelegate *filter_in_place (const EdgeFilterBase &filter) = 0;
|
||||
virtual EdgesDelegate *filtered (const EdgeFilterBase &filter) const = 0;
|
||||
virtual EdgesDelegate *process_in_place (const EdgeProcessorBase &filter) = 0;
|
||||
virtual EdgesDelegate *processed (const EdgeProcessorBase &filter) const = 0;
|
||||
|
||||
virtual EdgesDelegate *merged_in_place () = 0;
|
||||
virtual EdgesDelegate *merged () const = 0;
|
||||
|
|
@ -142,9 +173,6 @@ public:
|
|||
virtual EdgesDelegate *add (const Edges &other) const = 0;
|
||||
|
||||
virtual RegionDelegate *extended (coord_type ext_b, coord_type ext_e, coord_type ext_o, coord_type ext_i, bool join) const = 0;
|
||||
virtual EdgesDelegate *start_segments (length_type length, double fraction) const = 0;
|
||||
virtual EdgesDelegate *end_segments (length_type length, double fraction) const = 0;
|
||||
virtual EdgesDelegate *centers (length_type length, double fraction) const = 0;
|
||||
|
||||
virtual EdgesDelegate *inside_part (const Region &other) const = 0;
|
||||
virtual EdgesDelegate *outside_part (const Region &other) const = 0;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,177 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2019 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "dbEdgesUtils.h"
|
||||
#include "dbRegion.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
// JoinEdgesCluster implementation
|
||||
|
||||
JoinEdgesCluster::JoinEdgesCluster (db::PolygonSink *output, coord_type ext_b, coord_type ext_e, coord_type ext_o, coord_type ext_i)
|
||||
: mp_output (output), m_ext_b (ext_b), m_ext_e (ext_e), m_ext_o (ext_o), m_ext_i (ext_i)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void
|
||||
JoinEdgesCluster::finish ()
|
||||
{
|
||||
std::multimap<db::Point, iterator> objects_by_p1;
|
||||
std::multimap<db::Point, iterator> objects_by_p2;
|
||||
for (iterator o = begin (); o != end (); ++o) {
|
||||
if (o->first->p1 () != o->first->p2 ()) {
|
||||
objects_by_p1.insert (std::make_pair (o->first->p1 (), o));
|
||||
objects_by_p2.insert (std::make_pair (o->first->p2 (), o));
|
||||
}
|
||||
}
|
||||
|
||||
while (! objects_by_p2.empty ()) {
|
||||
|
||||
tl_assert (! objects_by_p1.empty ());
|
||||
|
||||
// Find the beginning of a new sequence
|
||||
std::multimap<db::Point, iterator>::iterator j0 = objects_by_p1.begin ();
|
||||
std::multimap<db::Point, iterator>::iterator j = j0;
|
||||
do {
|
||||
std::multimap<db::Point, iterator>::iterator jj = objects_by_p2.find (j->first);
|
||||
if (jj == objects_by_p2.end ()) {
|
||||
break;
|
||||
} else {
|
||||
j = objects_by_p1.find (jj->second->first->p1 ());
|
||||
tl_assert (j != objects_by_p1.end ());
|
||||
}
|
||||
} while (j != j0);
|
||||
|
||||
iterator i = j->second;
|
||||
|
||||
// determine a sequence
|
||||
// TODO: this chooses any solution in case of forks. Choose a specific one?
|
||||
std::vector<db::Point> pts;
|
||||
pts.push_back (i->first->p1 ());
|
||||
|
||||
do {
|
||||
|
||||
// record the next point
|
||||
pts.push_back (i->first->p2 ());
|
||||
|
||||
// remove the edge as it's taken
|
||||
std::multimap<db::Point, iterator>::iterator jj;
|
||||
for (jj = objects_by_p2.find (i->first->p2 ()); jj != objects_by_p2.end () && jj->first == i->first->p2 (); ++jj) {
|
||||
if (jj->second == i) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
tl_assert (jj != objects_by_p2.end () && jj->second == i);
|
||||
objects_by_p2.erase (jj);
|
||||
objects_by_p1.erase (j);
|
||||
|
||||
// process along the edge to the next one
|
||||
// TODO: this chooses any solution in case of forks. Choose a specific one?
|
||||
j = objects_by_p1.find (i->first->p2 ());
|
||||
if (j != objects_by_p1.end ()) {
|
||||
i = j->second;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
} while (true);
|
||||
|
||||
bool cyclic = (pts.back () == pts.front ());
|
||||
|
||||
if (! cyclic) {
|
||||
|
||||
// non-cyclic sequence
|
||||
db::Path path (pts.begin (), pts.end (), 0, m_ext_b, m_ext_e, false);
|
||||
std::vector<db::Point> hull;
|
||||
path.hull (hull, m_ext_o, m_ext_i);
|
||||
db::Polygon poly;
|
||||
poly.assign_hull (hull.begin (), hull.end ());
|
||||
mp_output->put (poly);
|
||||
|
||||
} else {
|
||||
|
||||
// we have a loop: form a contour by using the polygon size functions and a "Not" to form the hole
|
||||
db::Polygon poly;
|
||||
poly.assign_hull (pts.begin (), pts.end ());
|
||||
|
||||
db::EdgeProcessor ep;
|
||||
db::PolygonGenerator pg (*mp_output, false, true);
|
||||
|
||||
int mode_a = -1, mode_b = -1;
|
||||
|
||||
if (m_ext_o == 0) {
|
||||
ep.insert (poly, 0);
|
||||
} else {
|
||||
db::Polygon sized_poly (poly);
|
||||
sized_poly.size (m_ext_o, m_ext_o, 2 /*sizing mode*/);
|
||||
ep.insert (sized_poly, 0);
|
||||
mode_a = 1;
|
||||
}
|
||||
|
||||
if (m_ext_i == 0) {
|
||||
ep.insert (poly, 1);
|
||||
} else {
|
||||
db::Polygon sized_poly (poly);
|
||||
sized_poly.size (-m_ext_i, -m_ext_i, 2 /*sizing mode*/);
|
||||
ep.insert (sized_poly, 1);
|
||||
mode_b = 1;
|
||||
}
|
||||
|
||||
db::BooleanOp2 op (db::BooleanOp::ANotB, mode_a, mode_b);
|
||||
ep.process (pg, op);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------
|
||||
// extended_edge implementation
|
||||
|
||||
db::Polygon
|
||||
extended_edge (const db::Edge &edge, db::Coord ext_b, db::Coord ext_e, db::Coord ext_o, db::Coord ext_i)
|
||||
{
|
||||
db::DVector d;
|
||||
if (edge.is_degenerate ()) {
|
||||
d = db::DVector (1.0, 0.0);
|
||||
} else {
|
||||
d = db::DVector (edge.d ()) * (1.0 / edge.double_length ());
|
||||
}
|
||||
|
||||
db::DVector n (-d.y (), d.x ());
|
||||
|
||||
db::Point pts[4] = {
|
||||
db::Point (db::DPoint (edge.p1 ()) - d * double (ext_b) + n * double (ext_o)),
|
||||
db::Point (db::DPoint (edge.p2 ()) + d * double (ext_e) + n * double (ext_o)),
|
||||
db::Point (db::DPoint (edge.p2 ()) + d * double (ext_e) - n * double (ext_i)),
|
||||
db::Point (db::DPoint (edge.p1 ()) - d * double (ext_b) - n * double (ext_i)),
|
||||
};
|
||||
|
||||
db::Polygon poly;
|
||||
poly.assign_hull (pts + 0, pts + 4);
|
||||
return poly;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -25,9 +25,13 @@
|
|||
|
||||
#include "dbCommon.h"
|
||||
#include "dbEdges.h"
|
||||
#include "dbBoxScanner.h"
|
||||
#include "dbPolygonTools.h"
|
||||
|
||||
namespace db {
|
||||
|
||||
class PolygonSink;
|
||||
|
||||
/**
|
||||
* @brief An edge length filter for use with Edges::filter or Edges::filtered
|
||||
*
|
||||
|
|
@ -164,6 +168,138 @@ private:
|
|||
db::MagnificationAndOrientationReducer m_vars;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A helper class for the edge interaction functionality which acts as an edge pair receiver
|
||||
*/
|
||||
template <class OutputContainer>
|
||||
class edge_interaction_filter
|
||||
: public db::box_scanner_receiver<db::Edge, size_t>
|
||||
{
|
||||
public:
|
||||
edge_interaction_filter (OutputContainer &output)
|
||||
: mp_output (&output)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void add (const db::Edge *o1, size_t p1, const db::Edge *o2, size_t p2)
|
||||
{
|
||||
// Select the edges which intersect
|
||||
if (p1 != p2) {
|
||||
const db::Edge *o = p1 > p2 ? o2 : o1;
|
||||
const db::Edge *oo = p1 > p2 ? o1 : o2;
|
||||
if (o->intersect (*oo)) {
|
||||
if (m_seen.insert (o).second) {
|
||||
mp_output->insert (*o);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
OutputContainer *mp_output;
|
||||
std::set<const db::Edge *> m_seen;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A helper class for the edge to region interaction functionality which acts as an edge pair receiver
|
||||
*
|
||||
* Note: This special scanner uses pointers to two different objects: edges and polygons.
|
||||
* It uses odd value pointers to indicate pointers to polygons and even value pointers to indicate
|
||||
* pointers to edges.
|
||||
*
|
||||
* There is a special box converter which is able to sort that out as well.
|
||||
*/
|
||||
template <class OutputContainer>
|
||||
class edge_to_region_interaction_filter
|
||||
: public db::box_scanner_receiver2<db::Edge, size_t, db::Polygon, size_t>
|
||||
{
|
||||
public:
|
||||
edge_to_region_interaction_filter (OutputContainer &output)
|
||||
: mp_output (&output)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void add (const db::Edge *e, size_t, const db::Polygon *p, size_t)
|
||||
{
|
||||
if (m_seen.find (e) == m_seen.end ()) {
|
||||
if (db::interact (*p, *e)) {
|
||||
m_seen.insert (e);
|
||||
mp_output->insert (*e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
OutputContainer *mp_output;
|
||||
std::set<const db::Edge *> m_seen;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A helper class for the DRC functionality which acts as an edge pair receiver
|
||||
*
|
||||
* If will perform a edge by edge check using the provided EdgeRelationFilter
|
||||
*/
|
||||
template <class Output>
|
||||
class edge2edge_check_for_edges
|
||||
: public db::box_scanner_receiver<db::Edge, size_t>
|
||||
{
|
||||
public:
|
||||
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;
|
||||
}
|
||||
|
||||
void add (const db::Edge *o1, size_t p1, const db::Edge *o2, size_t p2)
|
||||
{
|
||||
// Overlap or inside checks require input from different layers
|
||||
if (! 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)) {
|
||||
mp_output->insert (ep);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const EdgeRelationFilter *mp_check;
|
||||
Output *mp_output;
|
||||
bool m_requires_different_layers;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A helper class to turn joined edge sequences into polygons
|
||||
*
|
||||
* This object is an edge cluster so it can connect to a cluster collector
|
||||
* driven by a box scanner.
|
||||
*/
|
||||
struct JoinEdgesCluster
|
||||
: public db::cluster<db::Edge, size_t>
|
||||
{
|
||||
typedef db::Edge::coord_type coord_type;
|
||||
|
||||
JoinEdgesCluster (db::PolygonSink *output, coord_type ext_b, coord_type ext_e, coord_type ext_o, coord_type ext_i);
|
||||
void finish ();
|
||||
|
||||
private:
|
||||
db::PolygonSink *mp_output;
|
||||
coord_type m_ext_b, m_ext_e, m_ext_o, m_ext_i;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Implements the extension algorithm to turn an edge into a polygon
|
||||
*/
|
||||
db::Polygon extended_edge (const db::Edge &edge, db::Coord ext_b, db::Coord ext_e, db::Coord ext_o, db::Coord ext_i);
|
||||
|
||||
} // namespace db
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -65,6 +65,8 @@ public:
|
|||
|
||||
virtual EdgesDelegate *filter_in_place (const EdgeFilterBase &) { return this; }
|
||||
virtual EdgesDelegate *filtered (const EdgeFilterBase &) const { return new EmptyEdges (); }
|
||||
virtual EdgesDelegate *process_in_place (const EdgeProcessorBase &) { return this; }
|
||||
virtual EdgesDelegate *processed (const EdgeProcessorBase &) const { return new EmptyEdges (); }
|
||||
|
||||
virtual EdgesDelegate *merged_in_place () { return this; }
|
||||
virtual EdgesDelegate *merged () const { return new EmptyEdges (); }
|
||||
|
|
@ -79,9 +81,6 @@ public:
|
|||
virtual EdgesDelegate *add (const Edges &other) const;
|
||||
|
||||
virtual RegionDelegate *extended (coord_type, coord_type, coord_type, coord_type, bool) const;
|
||||
virtual EdgesDelegate *start_segments (length_type, double) const { return new EmptyEdges (); }
|
||||
virtual EdgesDelegate *end_segments (length_type, double) const { return new EmptyEdges (); }
|
||||
virtual EdgesDelegate *centers (length_type, double) const { return new EmptyEdges (); }
|
||||
|
||||
virtual EdgesDelegate *inside_part (const Region &) const { return new EmptyEdges (); }
|
||||
virtual EdgesDelegate *outside_part (const Region &) const { return new EmptyEdges (); }
|
||||
|
|
|
|||
|
|
@ -182,6 +182,35 @@ Box FlatEdges::compute_bbox () const
|
|||
return m_edges.bbox ();
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
FlatEdges::processed_in_place (const EdgeProcessorBase &filter)
|
||||
{
|
||||
std::vector<db::Edge> edge_res;
|
||||
|
||||
edge_iterator_type pw = m_edges.get_layer<db::Edge, db::unstable_layer_tag> ().begin ();
|
||||
for (EdgesIterator p (filter.requires_raw_input () ? begin () : begin_merged ()); ! p.at_end (); ++p) {
|
||||
|
||||
edge_res.clear ();
|
||||
filter.process (*p, edge_res);
|
||||
|
||||
for (std::vector<db::Edge>::const_iterator pr = edge_res.begin (); pr != edge_res.end (); ++pr) {
|
||||
if (pw == m_edges.get_layer<db::Edge, db::unstable_layer_tag> ().end ()) {
|
||||
m_edges.get_layer<db::Edge, db::unstable_layer_tag> ().insert (*pr);
|
||||
pw = m_edges.get_layer<db::Edge, db::unstable_layer_tag> ().end ();
|
||||
} else {
|
||||
m_edges.get_layer<db::Edge, db::unstable_layer_tag> ().replace (pw++, *pr);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
m_edges.get_layer<db::Edge, db::unstable_layer_tag> ().erase (pw, m_edges.get_layer<db::Edge, db::unstable_layer_tag> ().end ());
|
||||
m_merged_edges.clear ();
|
||||
m_is_merged = filter.result_is_merged () && merged_semantics ();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
EdgesDelegate *
|
||||
FlatEdges::filter_in_place (const EdgeFilterBase &filter)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ public:
|
|||
|
||||
virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const;
|
||||
|
||||
virtual EdgesDelegate *processed_in_place (const EdgeProcessorBase &filter);
|
||||
virtual EdgesDelegate *filter_in_place (const EdgeFilterBase &filter);
|
||||
|
||||
virtual EdgesDelegate *add_in_place (const Edges &other);
|
||||
|
|
|
|||
|
|
@ -630,7 +630,7 @@ public:
|
|||
/**
|
||||
* @brief Processes the (merged) polygons
|
||||
*
|
||||
* This method will keep all polygons for which the processing filter returns true.
|
||||
* This method will keep all polygons which the processor returns.
|
||||
* The processing filter can apply modifications too. These modifications will be
|
||||
* kept in the output region.
|
||||
*
|
||||
|
|
@ -646,7 +646,7 @@ public:
|
|||
/**
|
||||
* @brief Returns the processed polygons
|
||||
*
|
||||
* This method will keep all polygons for which the processing filter returns true.
|
||||
* This method will keep all polygons which the processor returns.
|
||||
* The processing filter can apply modifications too. These modifications will be
|
||||
* kept in the output region.
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in New Issue