From 3dd1ed4c4d0229a4f0a64774048839b6703dfb00 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 19 Feb 2019 23:10:14 +0100 Subject: [PATCH] Refactoring of edges processor. --- src/db/db/dbAsIfFlatEdges.cc | 227 ++++------------------------------- src/db/db/dbAsIfFlatEdges.h | 140 ++------------------- src/db/db/dbDeepEdges.cc | 128 +++++++++++--------- src/db/db/dbDeepEdges.h | 6 +- src/db/db/dbEdges.cc | 65 ++++++++++ src/db/db/dbEdges.h | 61 ++++++---- src/db/db/dbEdgesDelegate.h | 34 +++++- src/db/db/dbEdgesUtils.cc | 177 +++++++++++++++++++++++++++ src/db/db/dbEdgesUtils.h | 136 +++++++++++++++++++++ src/db/db/dbEmptyEdges.h | 5 +- src/db/db/dbFlatEdges.cc | 29 +++++ src/db/db/dbFlatEdges.h | 1 + src/db/db/dbRegion.h | 4 +- 13 files changed, 583 insertions(+), 430 deletions(-) diff --git a/src/db/db/dbAsIfFlatEdges.cc b/src/db/db/dbAsIfFlatEdges.cc index dbd39d432..c2b0b4c45 100644 --- a/src/db/db/dbAsIfFlatEdges.cc +++ b/src/db/db/dbAsIfFlatEdges.cc @@ -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 objects_by_p1; - std::multimap 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::iterator j0 = objects_by_p1.begin (); - std::multimap::iterator j = j0; - do { - std::multimap::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 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::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 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 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 edges (new FlatEdges ()); + + if (filter.result_must_not_be_merged ()) { + edges->set_merged_semantics (false); + } + + std::vector 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::const_iterator er = res_edges.begin (); er != res_edges.end (); ++er) { + edges->insert (*er); + } + } + + return edges.release (); +} + EdgesDelegate * AsIfFlatEdges::filtered (const EdgeFilterBase &filter) const { diff --git a/src/db/db/dbAsIfFlatEdges.h b/src/db/db/dbAsIfFlatEdges.h index bac96e687..a4de96326 100644 --- a/src/db/db/dbAsIfFlatEdges.h +++ b/src/db/db/dbAsIfFlatEdges.h @@ -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 edge_interaction_filter - : public db::box_scanner_receiver -{ -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 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 edge_to_region_interaction_filter - : public db::box_scanner_receiver2 -{ -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 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 edge2edge_check_for_edges - : public db::box_scanner_receiver -{ -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 -{ - 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; }; } diff --git a/src/db/db/dbDeepEdges.cc b/src/db/db/dbDeepEdges.cc index 2ece77a73..48b2808c0 100644 --- a/src/db/db/dbDeepEdges.cc +++ b/src/db/db/dbDeepEdges.cc @@ -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 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 (m_merged_edges).separate_variants (*vars); + + } + + db::Layout &layout = m_merged_edges.layout (); + std::vector res_edges; + + std::auto_ptr 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 &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::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::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 res (new db::DeepEdges (m_merged_edges.derived ())); - - db::Layout &layout = const_cast (m_merged_edges.layout ()); - db::Cell &top_cell = const_cast (m_merged_edges.initial_cell ()); - - db::MagnificationReducer red; - db::cell_variants_collector vars (red); - vars.collect (m_merged_edges.layout (), m_merged_edges.initial_cell ()); - - std::map > to_commit; - - for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { - - const std::map &vv = vars.variants (c->cell_index ()); - for (std::map::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 { diff --git a/src/db/db/dbDeepEdges.h b/src/db/db/dbDeepEdges.h index 9e4790754..f61a9f027 100644 --- a/src/db/db/dbDeepEdges.h +++ b/src/db/db/dbDeepEdges.h @@ -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; }; diff --git a/src/db/db/dbEdges.cc b/src/db/db/dbEdges.cc index 24d8510c2..272f1a604 100644 --- a/src/db/db/dbEdges.cc +++ b/src/db/db/dbEdges.cc @@ -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 &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 Edges &Edges::transform (const T &trans) { diff --git a/src/db/db/dbEdges.h b/src/db/db/dbEdges.h index 3c2c7ab11..34a17a2c4 100644 --- a/src/db/db/dbEdges.h +++ b/src/db/db/dbEdges.h @@ -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 diff --git a/src/db/db/dbEdgesDelegate.h b/src/db/db/dbEdgesDelegate.h index cc3bd00d7..75809b135 100644 --- a/src/db/db/dbEdgesDelegate.h +++ b/src/db/db/dbEdgesDelegate.h @@ -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 &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; diff --git a/src/db/db/dbEdgesUtils.cc b/src/db/db/dbEdgesUtils.cc index e69de29bb..c7c71faf0 100644 --- a/src/db/db/dbEdgesUtils.cc +++ b/src/db/db/dbEdgesUtils.cc @@ -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 objects_by_p1; + std::multimap 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::iterator j0 = objects_by_p1.begin (); + std::multimap::iterator j = j0; + do { + std::multimap::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 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::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 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; +} + +} diff --git a/src/db/db/dbEdgesUtils.h b/src/db/db/dbEdgesUtils.h index a363ff157..33812c2f8 100644 --- a/src/db/db/dbEdgesUtils.h +++ b/src/db/db/dbEdgesUtils.h @@ -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 edge_interaction_filter + : public db::box_scanner_receiver +{ +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 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 edge_to_region_interaction_filter + : public db::box_scanner_receiver2 +{ +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 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 edge2edge_check_for_edges + : public db::box_scanner_receiver +{ +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 +{ + 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 diff --git a/src/db/db/dbEmptyEdges.h b/src/db/db/dbEmptyEdges.h index 85193b4ad..30644503b 100644 --- a/src/db/db/dbEmptyEdges.h +++ b/src/db/db/dbEmptyEdges.h @@ -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 (); } diff --git a/src/db/db/dbFlatEdges.cc b/src/db/db/dbFlatEdges.cc index 6fbc3fb60..75c977bee 100644 --- a/src/db/db/dbFlatEdges.cc +++ b/src/db/db/dbFlatEdges.cc @@ -182,6 +182,35 @@ Box FlatEdges::compute_bbox () const return m_edges.bbox (); } +EdgesDelegate * +FlatEdges::processed_in_place (const EdgeProcessorBase &filter) +{ + std::vector edge_res; + + edge_iterator_type pw = m_edges.get_layer ().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::const_iterator pr = edge_res.begin (); pr != edge_res.end (); ++pr) { + if (pw == m_edges.get_layer ().end ()) { + m_edges.get_layer ().insert (*pr); + pw = m_edges.get_layer ().end (); + } else { + m_edges.get_layer ().replace (pw++, *pr); + } + } + + } + + m_edges.get_layer ().erase (pw, m_edges.get_layer ().end ()); + m_merged_edges.clear (); + m_is_merged = filter.result_is_merged () && merged_semantics (); + + return this; +} + EdgesDelegate * FlatEdges::filter_in_place (const EdgeFilterBase &filter) { diff --git a/src/db/db/dbFlatEdges.h b/src/db/db/dbFlatEdges.h index 5216ce5fe..e1a80f014 100644 --- a/src/db/db/dbFlatEdges.h +++ b/src/db/db/dbFlatEdges.h @@ -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); diff --git a/src/db/db/dbRegion.h b/src/db/db/dbRegion.h index a7bcb771e..3d6544454 100644 --- a/src/db/db/dbRegion.h +++ b/src/db/db/dbRegion.h @@ -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. *