diff --git a/src/db/db/db.pro b/src/db/db/db.pro index c87a0ee0d..eafb681ba 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -167,7 +167,9 @@ SOURCES = \ gsiDeclDbDeepShapeStore.cc \ dbNetlistSpiceWriter.cc \ dbNetlistWriter.cc \ - dbCellVariants.cc + dbCellVariants.cc \ + dbDeepEdges.cc \ + dbDeepEdgePairs.cc HEADERS = \ dbArray.h \ @@ -299,7 +301,9 @@ HEADERS = \ dbDeepRegion.h \ dbNetlistSpiceWriter.h \ dbNetlistWriter.h \ - dbCellVariants.h + dbCellVariants.h \ + dbDeepEdges.h \ + dbDeepEdgePairs.h !equals(HAVE_QT, "0") { diff --git a/src/db/db/dbAsIfFlatEdges.h b/src/db/db/dbAsIfFlatEdges.h index e1541d75c..93c2e6401 100644 --- a/src/db/db/dbAsIfFlatEdges.h +++ b/src/db/db/dbAsIfFlatEdges.h @@ -157,6 +157,7 @@ public: 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; private: AsIfFlatEdges &operator= (const AsIfFlatEdges &other); @@ -165,7 +166,6 @@ private: mutable db::Box m_bbox; virtual db::Box compute_bbox () 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 *boolean (const Edges *other, EdgeBoolOp op) const; EdgesDelegate *edge_region_op (const Region &other, bool outside, bool include_borders) const; }; diff --git a/src/db/db/dbDeepEdgePairs.cc b/src/db/db/dbDeepEdgePairs.cc new file mode 100644 index 000000000..e573e589b --- /dev/null +++ b/src/db/db/dbDeepEdgePairs.cc @@ -0,0 +1,34 @@ + +/* + + 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 "dbDeepEdgePairs.h" + +#include + +namespace db +{ + +// @@@ TODO: implement + +} + diff --git a/src/db/db/dbDeepEdgePairs.h b/src/db/db/dbDeepEdgePairs.h new file mode 100644 index 000000000..8bcada294 --- /dev/null +++ b/src/db/db/dbDeepEdgePairs.h @@ -0,0 +1,38 @@ + +/* + + 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 + +*/ + + +#ifndef HDR_dbDeepEdgePairs +#define HDR_dbDeepEdgePairs + +#include "dbCommon.h" + +#include "dbAsIfFlatEdgePairs.h" + +namespace db { + +// @@@ TODO: implement + +} + +#endif + diff --git a/src/db/db/dbDeepEdges.cc b/src/db/db/dbDeepEdges.cc new file mode 100644 index 000000000..6b2aad875 --- /dev/null +++ b/src/db/db/dbDeepEdges.cc @@ -0,0 +1,673 @@ + +/* + + 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 "dbEdges.h" +#include "dbDeepEdges.h" +#include "dbHierNetworkProcessor.h" +#include "dbCellGraphUtils.h" +#include "dbCellVariants.h" +#include "dbEdgeBoolean.h" +#include "dbCellMapping.h" +#include "dbLayoutUtils.h" + +namespace db +{ + +/** + * @brief An iterator delegate for the deep edge collection + * TODO: this is kind of redundant with OriginalLayerIterator .. + */ +class DB_PUBLIC DeepEdgesIterator + : public EdgesIteratorDelegate +{ +public: + DeepEdgesIterator (const db::RecursiveShapeIterator &iter) + : m_iter (iter) + { + set (); + } + + virtual ~DeepEdgesIterator () { } + + virtual bool at_end () const + { + return m_iter.at_end (); + } + + virtual void increment () + { + ++m_iter; + set (); + } + + virtual const value_type *get () const + { + return &m_edge; + } + + virtual EdgesIteratorDelegate *clone () const + { + return new DeepEdgesIterator (*this); + } + +private: + friend class Edges; + + db::RecursiveShapeIterator m_iter; + mutable value_type m_edge; + + void set () const + { + if (! m_iter.at_end ()) { + m_iter.shape ().edge (m_edge); + m_edge.transform (m_iter.trans ()); + } + } +}; + +// ------------------------------------------------------------------------------------------------------------- +// DeepEdges implementation + +DeepEdges::DeepEdges (const RecursiveShapeIterator &si, DeepShapeStore &dss) + : AsIfFlatEdges (), m_deep_layer (dss.create_edge_layer (si)), m_merged_edges () +{ + init (); +} + +DeepEdges::DeepEdges (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans, bool merged_semantics) + : AsIfFlatEdges (), m_deep_layer (dss.create_edge_layer (si)), m_merged_edges () +{ + init (); + + tl_assert (trans.is_unity ()); // TODO: implement + set_merged_semantics (merged_semantics); +} + +DeepEdges::DeepEdges () + : AsIfFlatEdges () +{ + init (); +} + +DeepEdges::DeepEdges (const DeepLayer &dl) + : AsIfFlatEdges (), m_deep_layer (dl) +{ + init (); +} + +DeepEdges::~DeepEdges () +{ + // .. nothing yet .. +} + +DeepEdges::DeepEdges (const DeepEdges &other) + : AsIfFlatEdges (other), + m_deep_layer (other.m_deep_layer.copy ()), + m_merged_edges_valid (other.m_merged_edges_valid) +{ + if (m_merged_edges_valid) { + m_merged_edges = other.m_merged_edges; + } +} + +void DeepEdges::init () +{ + m_merged_edges_valid = false; + m_merged_edges = db::DeepLayer (); +} + +EdgesDelegate * +DeepEdges::clone () const +{ + return new DeepEdges (*this); +} + +void DeepEdges::merged_semantics_changed () +{ + // .. nothing yet .. +} + +EdgesIteratorDelegate * +DeepEdges::begin () const +{ + return new DeepEdgesIterator (begin_iter ().first); +} + +EdgesIteratorDelegate * +DeepEdges::begin_merged () const +{ + if (! merged_semantics ()) { + return begin (); + } else { + return new DeepEdgesIterator (begin_merged_iter ().first); + } +} + +std::pair +DeepEdges::begin_iter () const +{ + const db::Layout &layout = m_deep_layer.layout (); + if (layout.cells () == 0) { + + return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ()); + + } else { + + const db::Cell &top_cell = layout.cell (*layout.begin_top_down ()); + db::RecursiveShapeIterator iter (m_deep_layer.layout (), top_cell, m_deep_layer.layer ()); + return std::make_pair (iter, db::ICplxTrans ()); + + } +} + +std::pair +DeepEdges::begin_merged_iter () const +{ + if (! merged_semantics ()) { + + return begin_iter (); + + } else { + + ensure_merged_edges_valid (); + + const db::Layout &layout = m_merged_edges.layout (); + if (layout.cells () == 0) { + + return std::make_pair (db::RecursiveShapeIterator (), db::ICplxTrans ()); + + } else { + + const db::Cell &top_cell = layout.cell (*layout.begin_top_down ()); + db::RecursiveShapeIterator iter (m_merged_edges.layout (), top_cell, m_merged_edges.layer ()); + return std::make_pair (iter, db::ICplxTrans ()); + + } + + } +} + +bool +DeepEdges::empty () const +{ + return begin_iter ().first.at_end (); +} + +bool +DeepEdges::is_merged () const +{ + // TODO: there is no such thing as a "surely merged" state except after merged() maybe + return false; +} + +const db::Edge * +DeepEdges::nth (size_t /*n*/) const +{ + throw tl::Exception (tl::to_string (tr ("Random access to edges is available only for flat edge collections"))); +} + +bool +DeepEdges::has_valid_edges () const +{ + return false; +} + +bool +DeepEdges::has_valid_merged_edges () const +{ + return merged_semantics (); +} + +const db::RecursiveShapeIterator * +DeepEdges::iter () const +{ + return 0; +} + +bool DeepEdges::equals (const Edges &other) const +{ + const DeepEdges *other_delegate = dynamic_cast (other.delegate ()); + if (other_delegate && &other_delegate->m_deep_layer.layout () == &m_deep_layer.layout () + && other_delegate->m_deep_layer.layer () == m_deep_layer.layer ()) { + return true; + } else { + return AsIfFlatEdges::equals (other); + } +} + +bool DeepEdges::less (const Edges &other) const +{ + const DeepEdges *other_delegate = dynamic_cast (other.delegate ()); + if (other_delegate && &other_delegate->m_deep_layer.layout () == &m_deep_layer.layout ()) { + return other_delegate->m_deep_layer.layer () < m_deep_layer.layer (); + } else { + return AsIfFlatEdges::less (other); + } +} + +namespace { + +class ClusterMerger +{ +public: + ClusterMerger (unsigned int layer, const db::hier_clusters &hc, bool report_progress, const std::string &progress_desc) + : m_layer (layer), mp_hc (&hc), m_scanner (report_progress, progress_desc) + { + // .. nothing yet .. + } + + void set_base_verbosity (int /*vb*/) + { + /* TODO: No such thing currently: + m_scanner.set_base_verbosity (vb); + */ + } + + db::Shapes &merged (size_t cid, db::cell_index_type ci, bool initial = true) + { + std::map, db::Shapes>::iterator s = m_merged_cluster.find (std::make_pair (cid, ci)); + + // some sanity checks: initial clusters are single-use, are never generated twice and cannot be retrieved again + if (initial) { + tl_assert (s == m_merged_cluster.end ()); + m_done.insert (std::make_pair (cid, ci)); + } else { + tl_assert (m_done.find (std::make_pair (cid, ci)) == m_done.end ()); + } + + if (s != m_merged_cluster.end ()) { + return s->second; + } + + s = m_merged_cluster.insert (std::make_pair (std::make_pair (cid, ci), db::Shapes (false))).first; + + const db::connected_clusters &cc = mp_hc->clusters_per_cell (ci); + const db::local_cluster &c = cc.cluster_by_id (cid); + + std::list > merged_child_clusters; + + const db::connected_clusters::connections_type &conn = cc.connections_for_cluster (cid); + for (db::connected_clusters::connections_type::const_iterator i = conn.begin (); i != conn.end (); ++i) { + const db::Shapes &cc_shapes = merged (i->id (), i->inst ().inst_ptr.cell_index (), false); + merged_child_clusters.push_back (std::make_pair (&cc_shapes, i->inst ().complex_trans ())); + } + + // collect the edges to merge .. + + std::list heap; + m_scanner.clear (); + + for (std::list >::const_iterator i = merged_child_clusters.begin (); i != merged_child_clusters.end (); ++i) { + for (db::Shapes::shape_iterator s = i->first->begin (db::ShapeIterator::All); ! s.at_end (); ++s) { + if (s->is_edge ()) { + heap.push_back (s->edge ().transformed (i->second)); + m_scanner.insert (&heap.back (), 0); + } + } + } + + for (db::local_cluster::shape_iterator s = c.begin (m_layer); !s.at_end (); ++s) { + heap.push_back (*s); + m_scanner.insert (&heap.back (), 0); + } + + // .. and run the merge operation + + s->second.clear (); + EdgeBooleanClusterCollector cluster_collector (&s->second, EdgeOr); + m_scanner.process (cluster_collector, 1, db::box_convert ()); + + return s->second; + } + +private: + std::map, db::Shapes> m_merged_cluster; + std::set > m_done; + unsigned int m_layer; + const db::hier_clusters *mp_hc; + db::box_scanner m_scanner; +}; + +} + +void +DeepEdges::ensure_merged_edges_valid () const +{ + if (! m_merged_edges_valid) { + + m_merged_edges = m_deep_layer.new_layer (); + + tl::SelfTimer timer (tl::verbosity () > base_verbosity (), "Ensure merged polygons"); + + db::Layout &layout = const_cast (m_deep_layer.layout ()); + + db::hier_clusters hc; + db::Connectivity conn; + conn.connect (m_deep_layer); + // TODO: this uses the wrong verbosity inside ... + hc.build (layout, m_deep_layer.initial_cell (), db::ShapeIterator::Edges, conn); + + // collect the clusters and merge them into big polygons + // NOTE: using the ClusterMerger we merge bottom-up forming bigger and bigger polygons. This is + // hopefully more efficient that collecting everything and will lead to reuse of parts. + + ClusterMerger cm (m_deep_layer.layer (), hc, report_progress (), progress_desc ()); + cm.set_base_verbosity (base_verbosity ()); + + // TODO: iterate only over the called cells? + for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { + const db::connected_clusters &cc = hc.clusters_per_cell (c->cell_index ()); + for (db::connected_clusters::all_iterator cl = cc.begin_all (); ! cl.at_end (); ++cl) { + if (cc.is_root (*cl)) { + db::Shapes &s = cm.merged (*cl, c->cell_index ()); + c->shapes (m_merged_edges.layer ()).insert (s); + s.clear (); // not needed anymore + } + } + } + + m_merged_edges_valid = true; + + } +} + +void +DeepEdges::insert_into (db::Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const +{ + m_deep_layer.insert_into (layout, into_cell, into_layer); +} + +size_t DeepEdges::size () const +{ + size_t n = 0; + + const db::Layout &layout = m_deep_layer.layout (); + db::CellCounter cc (&layout); + for (db::Layout::top_down_const_iterator c = layout.begin_top_down (); c != layout.end_top_down (); ++c) { + n += cc.weight (*c) * layout.cell (*c).shapes (m_deep_layer.layer ()).size (); + } + + return n; +} + +Box DeepEdges::bbox () const +{ + return m_deep_layer.initial_cell ().bbox (m_deep_layer.layer ()); +} + +DeepEdges::length_type DeepEdges::length (const db::Box &box) const +{ + if (box.empty ()) { + + ensure_merged_edges_valid (); + + db::MagnificationReducer red; + db::cell_variants_collector vars (red); + vars.collect (m_merged_edges.layout (), m_merged_edges.initial_cell ()); + + DeepEdges::length_type l = 0; + + const db::Layout &layout = m_merged_edges.layout (); + for (db::Layout::top_down_const_iterator c = layout.begin_top_down (); c != layout.end_top_down (); ++c) { + DeepEdges::length_type lc = 0; + for (db::ShapeIterator s = layout.cell (*c).shapes (m_merged_edges.layer ()).begin (db::ShapeIterator::Edges); ! s.at_end (); ++s) { + lc += s->edge ().length (); + } + const std::map &vv = vars.variants (*c); + for (std::map::const_iterator v = vv.begin (); v != vv.end (); ++v) { + double mag = v->first.mag (); + l += v->second * lc * mag; + } + } + + return l; + + } else { + // In the clipped case fall back to flat mode + return db::AsIfFlatEdges::length (box); + } +} + +std::string DeepEdges::to_string (size_t nmax) const +{ + return db::AsIfFlatEdges::to_string (nmax); +} + +EdgesDelegate *DeepEdges::filter_in_place (const EdgeFilterBase &filter) +{ + // TODO: implement + return AsIfFlatEdges::filter_in_place (filter); +} + +EdgesDelegate *DeepEdges::filtered (const EdgeFilterBase &filter) const +{ + // TODO: implement + return AsIfFlatEdges::filtered (filter); +} + +EdgesDelegate *DeepEdges::merged_in_place () +{ + ensure_merged_edges_valid (); + + // NOTE: this makes both layers share the same resource + m_deep_layer = m_merged_edges; + + return this; +} + +EdgesDelegate *DeepEdges::merged () const +{ + ensure_merged_edges_valid (); + + db::Layout &layout = const_cast (m_merged_edges.layout ()); + + std::auto_ptr res (new db::DeepEdges (m_merged_edges.new_layer ())); + for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { + c->shapes (res->deep_layer ().layer ()) = c->shapes (m_merged_edges.layer ()); + } + + res->deep_layer ().layer (); + + return res.release (); +} + +EdgesDelegate *DeepEdges::and_with (const Edges &other) const +{ + // TODO: implement + return AsIfFlatEdges::and_with (other); +} + +EdgesDelegate *DeepEdges::and_with (const Region &other) const +{ + // TODO: implement + return AsIfFlatEdges::and_with (other); +} + +EdgesDelegate *DeepEdges::not_with (const Edges &other) const +{ + // TODO: implement + return AsIfFlatEdges::not_with (other); +} + +EdgesDelegate *DeepEdges::not_with (const Region &other) const +{ + // TODO: implement + return AsIfFlatEdges::not_with (other); +} + +EdgesDelegate *DeepEdges::xor_with (const Edges &other) const +{ + // TODO: implement + return AsIfFlatEdges::xor_with (other); +} + +EdgesDelegate *DeepEdges::or_with (const Edges &other) const +{ + // TODO: implement + return AsIfFlatEdges::or_with (other); +} + +void +DeepEdges::add_from (const DeepLayer &dl) +{ + if (&dl.layout () == &deep_layer ().layout ()) { + + // intra-layout merge + + deep_layer ().layout ().copy_layer (dl.layer (), deep_layer ().layer ()); + + } else { + + // inter-layout merge + + db::cell_index_type into_cell = deep_layer ().initial_cell ().cell_index (); + db::Layout *into_layout = &deep_layer ().layout (); + db::cell_index_type source_cell = dl.initial_cell ().cell_index (); + const db::Layout *source_layout = &dl.layout (); + + db::CellMapping cm; + cm.create_from_geometry_full (*into_layout, into_cell, *source_layout, source_cell); + + // Actually copy the shapes + + std::map lm; + lm.insert (std::make_pair (dl.layer (), deep_layer ().layer ())); + + std::vector source_cells; + source_cells.push_back (source_cell); + db::copy_shapes (*into_layout, *source_layout, db::ICplxTrans (), source_cells, cm.table (), lm); + + } +} + +EdgesDelegate * +DeepEdges::add_in_place (const Edges &other) +{ + if (other.empty ()) { + return this; + } + + const DeepEdges *other_deep = dynamic_cast (other.delegate ()); + if (other_deep) { + + add_from (other_deep->deep_layer ()); + + } else { + + // non-deep to deep merge (flat) + + db::Shapes &shapes = deep_layer ().initial_cell ().shapes (deep_layer ().layer ()); + for (db::Edges::const_iterator p = other.begin (); ! p.at_end (); ++p) { + shapes.insert (*p); + } + + } + + return this; +} + +EdgesDelegate *DeepEdges::add (const Edges &other) const +{ + if (other.empty ()) { + return clone (); + } else if (empty ()) { + return other.delegate ()->clone (); + } else { + DeepEdges *new_edges = dynamic_cast (clone ()); + new_edges->add_in_place (other); + return new_edges; + } +} + +EdgesDelegate *DeepEdges::inside_part (const Region &other) const +{ + // TODO: implement + return AsIfFlatEdges::inside_part (other); +} + +EdgesDelegate *DeepEdges::outside_part (const Region &other) const +{ + // TODO: implement + return AsIfFlatEdges::outside_part (other); +} + +RegionDelegate *DeepEdges::extended (coord_type ext_b, coord_type ext_e, coord_type ext_o, coord_type ext_i, bool join) const +{ + // TODO: implement + return AsIfFlatEdges::extended (ext_b, ext_e, ext_o, ext_i, join); +} + +EdgesDelegate *DeepEdges::start_segments (length_type length, double fraction) const +{ + // TODO: implement + return AsIfFlatEdges::start_segments (length, fraction); +} + +EdgesDelegate *DeepEdges::end_segments (length_type length, double fraction) const +{ + // TODO: implement + return AsIfFlatEdges::end_segments (length, fraction); +} + +EdgesDelegate *DeepEdges::centers (length_type length, double fraction) const +{ + // TODO: implement + return AsIfFlatEdges::centers (length, fraction); +} + +EdgesDelegate *DeepEdges::selected_interacting (const Edges &other) const +{ + // TODO: implement + return AsIfFlatEdges::selected_interacting (other); +} + +EdgesDelegate *DeepEdges::selected_not_interacting (const Edges &other) const +{ + // TODO: implement + return AsIfFlatEdges::selected_not_interacting (other); +} + +EdgesDelegate *DeepEdges::selected_interacting (const Region &other) const +{ + // TODO: implement + return AsIfFlatEdges::selected_interacting (other); +} + +EdgesDelegate *DeepEdges::selected_not_interacting (const Region &other) const +{ + // TODO: implement + return AsIfFlatEdges::selected_not_interacting (other); +} + +EdgesDelegate *DeepEdges::in (const Edges &other, bool invert) const +{ + // TODO: implement + return AsIfFlatEdges::in (other, invert); +} + +EdgePairs DeepEdges::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 +{ + // TODO: implement + return AsIfFlatEdges::run_check (rel, other, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); +} + +} diff --git a/src/db/db/dbDeepEdges.h b/src/db/db/dbDeepEdges.h new file mode 100644 index 000000000..338a5ba83 --- /dev/null +++ b/src/db/db/dbDeepEdges.h @@ -0,0 +1,175 @@ + +/* + + 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 + +*/ + + +#ifndef HDR_dbDeepEdges +#define HDR_dbDeepEdges + +#include "dbCommon.h" + +#include "dbAsIfFlatEdges.h" +#include "dbDeepShapeStore.h" +#include "dbEdgePairs.h" + +namespace db { + +class Edges; + +/** + * @brief Provides hierarchical edges implementation + */ +class DB_PUBLIC DeepEdges + : public db::AsIfFlatEdges +{ +public: + DeepEdges (); + DeepEdges (const RecursiveShapeIterator &si, DeepShapeStore &dss); + DeepEdges (const RecursiveShapeIterator &si, DeepShapeStore &dss, const db::ICplxTrans &trans, bool merged_semantics = true); + + DeepEdges (const DeepEdges &other); + DeepEdges (const DeepLayer &dl); + + virtual ~DeepEdges (); + + EdgesDelegate *clone () const; + + virtual EdgesIteratorDelegate *begin () const; + virtual EdgesIteratorDelegate *begin_merged () const; + + virtual std::pair begin_iter () const; + virtual std::pair begin_merged_iter () const; + + virtual bool empty () const; + virtual bool is_merged () const; + + virtual const db::Edge *nth (size_t n) const; + virtual bool has_valid_edges () const; + virtual bool has_valid_merged_edges () const; + + virtual const db::RecursiveShapeIterator *iter () const; + + virtual bool equals (const Edges &other) const; + virtual bool less (const Edges &other) const; + + virtual size_t size () const; + virtual Box bbox () const; + + virtual DeepEdges::length_type length (const db::Box &) const; + + virtual std::string to_string (size_t nmax) const; + + virtual EdgePairs width_check (db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const + { + return run_check (db::WidthRelation, 0, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); + } + + virtual EdgePairs space_check (db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const + { + return run_check (db::SpaceRelation, 0, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); + } + + virtual EdgePairs enclosing_check (const Edges &other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const + { + return run_check (db::OverlapRelation, &other, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); + } + + virtual EdgePairs overlap_check (const Edges &other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const + { + return run_check (db::WidthRelation, &other, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); + } + + virtual EdgePairs separation_check (const Edges &other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const + { + return run_check (db::SpaceRelation, &other, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); + } + + virtual EdgePairs inside_check (const Edges &other, db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const + { + return run_check (db::InsideRelation, &other, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); + } + + virtual EdgesDelegate *filter_in_place (const EdgeFilterBase &filter); + virtual EdgesDelegate *filtered (const EdgeFilterBase &) const; + + virtual EdgesDelegate *merged_in_place (); + virtual EdgesDelegate *merged () const; + + virtual EdgesDelegate *and_with (const Edges &other) const; + virtual EdgesDelegate *and_with (const Region &other) const; + + virtual EdgesDelegate *not_with (const Edges &other) const; + virtual EdgesDelegate *not_with (const Region &other) const; + + virtual EdgesDelegate *xor_with (const Edges &other) const; + + virtual EdgesDelegate *or_with (const Edges &other) const; + + virtual EdgesDelegate *add_in_place (const Edges &other); + virtual EdgesDelegate *add (const Edges &other) const; + + virtual EdgesDelegate *inside_part (const Region &other) const; + 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; + virtual EdgesDelegate *selected_interacting (const Region &) const; + virtual EdgesDelegate *selected_not_interacting (const Region &) const; + + virtual EdgesDelegate *in (const Edges &, bool) const; + + virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const; + + const DeepLayer &deep_layer () const + { + return m_deep_layer; + } + + DeepLayer &deep_layer () + { + return m_deep_layer; + } + +protected: + virtual void merged_semantics_changed (); + +private: + DeepEdges &operator= (const DeepEdges &other); + + DeepLayer m_deep_layer; + mutable DeepLayer m_merged_edges; + mutable bool m_merged_edges_valid; + + void init (); + void ensure_merged_edges_valid () const; + void add_from (const DeepLayer &dl); + 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; +}; + +} + +#endif + diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index 99b5ed41e..2372dc596 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -225,6 +225,7 @@ DeepRegion::empty () const bool DeepRegion::is_merged () const { + // TODO: there is no such thing as a "surely merged" state except after merged() maybe return false; } @@ -539,7 +540,6 @@ DeepRegion::add_from (const DeepLayer &dl) } } - RegionDelegate * DeepRegion::add_in_place (const Region &other) { @@ -564,7 +564,6 @@ DeepRegion::add_in_place (const Region &other) } return this; - } RegionDelegate * diff --git a/src/db/db/dbDeepRegion.h b/src/db/db/dbDeepRegion.h index df214e093..63a19078c 100644 --- a/src/db/db/dbDeepRegion.h +++ b/src/db/db/dbDeepRegion.h @@ -59,7 +59,6 @@ public: virtual std::pair begin_merged_iter () const; virtual bool empty () const; - virtual bool is_merged () const; virtual const db::Polygon *nth (size_t n) const; @@ -71,13 +70,6 @@ public: virtual bool equals (const Region &other) const; virtual bool less (const Region &other) const; - virtual RegionDelegate *and_with (const Region &other) const; - virtual RegionDelegate *not_with (const Region &other) const; - virtual RegionDelegate *xor_with (const Region &other) const; - - virtual RegionDelegate *add_in_place (const Region &other); - virtual RegionDelegate *add (const Region &other) const; - virtual bool is_box () const; virtual size_t size () const; @@ -87,6 +79,13 @@ public: virtual std::string to_string (size_t nmax) const; + virtual RegionDelegate *and_with (const Region &other) const; + virtual RegionDelegate *not_with (const Region &other) const; + virtual RegionDelegate *xor_with (const Region &other) const; + + virtual RegionDelegate *add_in_place (const Region &other); + virtual RegionDelegate *add (const Region &other) const; + EdgePairs width_check (db::Coord d, bool whole_edges, metrics_type metrics, double ignore_angle, distance_type min_projection, distance_type max_projection) const { return run_single_polygon_check (db::WidthRelation, d, whole_edges, metrics, ignore_angle, min_projection, max_projection); diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index 011184929..e9c58493e 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -330,21 +330,13 @@ void DeepShapeStore::remove_ref (unsigned int layout, unsigned int layer) } } -DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator &si, double max_area_ratio, size_t max_vertex_count) +unsigned int +DeepShapeStore::layout_for_iter (const db::RecursiveShapeIterator &si) { - if (max_area_ratio == 0.0) { - max_area_ratio = m_max_area_ratio; - } - if (max_vertex_count == 0) { - max_vertex_count = m_max_vertex_count; - } - - unsigned int layout_index = 0; - layout_map_type::iterator l = m_layout_map.find (si); if (l == m_layout_map.end ()) { - layout_index = (unsigned int) m_layouts.size (); + unsigned int layout_index = (unsigned int) m_layouts.size (); m_layouts.push_back (new LayoutHolder ()); @@ -355,12 +347,23 @@ DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator } m_layout_map[si] = layout_index; + return layout_index; } else { - - layout_index = l->second; - + return l->second; } +} + +DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator &si, double max_area_ratio, size_t max_vertex_count) +{ + if (max_area_ratio == 0.0) { + max_area_ratio = m_max_area_ratio; + } + if (max_vertex_count == 0) { + max_vertex_count = m_max_vertex_count; + } + + unsigned int layout_index = layout_for_iter (si); db::Layout &layout = m_layouts[layout_index]->layout; db::HierarchyBuilder &builder = m_layouts[layout_index]->builder; @@ -376,7 +379,7 @@ DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator // Build the working hierarchy from the recursive shape iterator try { - tl::SelfTimer timer (tl::verbosity () >= 21, tl::to_string (tr ("Building working hierarchy"))); + tl::SelfTimer timer (tl::verbosity () >= 41, tl::to_string (tr ("Building working hierarchy"))); builder.set_shape_receiver (&clip); db::RecursiveShapeIterator (si).push (& builder); @@ -390,6 +393,36 @@ DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator return DeepLayer (this, layout_index, layer_index); } +DeepLayer DeepShapeStore::create_edge_layer (const db::RecursiveShapeIterator &si) +{ + unsigned int layout_index = layout_for_iter (si); + + db::Layout &layout = m_layouts[layout_index]->layout; + db::HierarchyBuilder &builder = m_layouts[layout_index]->builder; + + unsigned int layer_index = layout.insert_layer (); + builder.set_target_layer (layer_index); + + // The chain of operators for producing clipped and reduced polygon references + db::EdgeBuildingHierarchyBuilderShapeReceiver refs; + + // Build the working hierarchy from the recursive shape iterator + try { + + tl::SelfTimer timer (tl::verbosity () >= 41, tl::to_string (tr ("Building working hierarchy"))); + + builder.set_shape_receiver (&refs); + db::RecursiveShapeIterator (si).push (& builder); + builder.set_shape_receiver (0); + + } catch (...) { + builder.set_shape_receiver (0); + throw; + } + + return DeepLayer (this, layout_index, layer_index); +} + void DeepShapeStore::invalidate_hier () { diff --git a/src/db/db/dbDeepShapeStore.h b/src/db/db/dbDeepShapeStore.h index aea037f10..6cfaab83a 100644 --- a/src/db/db/dbDeepShapeStore.h +++ b/src/db/db/dbDeepShapeStore.h @@ -240,6 +240,15 @@ public: */ DeepLayer create_polygon_layer (const db::RecursiveShapeIterator &si, double max_area_ratio = 0.0, size_t max_vertex_count = 0); + /** + * @brief Inserts an edge layer into the deep shape store + * + * This method will create a new layer inside the deep shape store as a + * working copy of the original layer. This method creates a layer + * for edges. + */ + DeepLayer create_edge_layer (const db::RecursiveShapeIterator &si); + /** * @brief Inserts the deep layer's shapes into some target layout */ @@ -459,6 +468,8 @@ private: void add_ref (unsigned int layout, unsigned int layer); void remove_ref (unsigned int layout, unsigned int layer); + unsigned int layout_for_iter (const db::RecursiveShapeIterator &si); + void require_singular () const; void issue_variants (unsigned int layout, const std::map > &var_map); diff --git a/src/db/db/dbEdges.h b/src/db/db/dbEdges.h index c4dfc493f..82b013198 100644 --- a/src/db/db/dbEdges.h +++ b/src/db/db/dbEdges.h @@ -439,6 +439,26 @@ public: return mp_delegate; } + /** + * @brief Sets the base verbosity + * + * Setting this value will make timing measurements appear at least at + * the given verbosity level and more detailed timing at the given level + * plus 10. The default level is 30. + */ + void set_base_verbosity (int vb) + { + mp_delegate->set_base_verbosity (vb); + } + + /** + * @brief Gets the base verbosity + */ + unsigned int base_verbosity () const + { + return mp_delegate->base_verbosity (); + } + /** * @brief Enable progress reporting * diff --git a/src/db/db/dbEdgesDelegate.cc b/src/db/db/dbEdgesDelegate.cc index 65f840892..d160e0b46 100644 --- a/src/db/db/dbEdgesDelegate.cc +++ b/src/db/db/dbEdgesDelegate.cc @@ -30,6 +30,7 @@ namespace db EdgesDelegate::EdgesDelegate () { + m_base_verbosity = 30; m_report_progress = false; m_merged_semantics = true; m_strict_handling = false; @@ -44,6 +45,7 @@ EdgesDelegate & EdgesDelegate::operator= (const EdgesDelegate &other) { if (this != &other) { + m_base_verbosity = other.m_base_verbosity; m_report_progress = other.m_report_progress; m_merged_semantics = other.m_merged_semantics; m_strict_handling = other.m_strict_handling; @@ -56,6 +58,11 @@ EdgesDelegate::~EdgesDelegate () // .. nothing yet .. } +void EdgesDelegate::set_base_verbosity (int vb) +{ + m_base_verbosity = vb; +} + void EdgesDelegate::enable_progress (const std::string &progress_desc) { m_report_progress = true; diff --git a/src/db/db/dbEdgesDelegate.h b/src/db/db/dbEdgesDelegate.h index a647062be..9410451f8 100644 --- a/src/db/db/dbEdgesDelegate.h +++ b/src/db/db/dbEdgesDelegate.h @@ -83,6 +83,12 @@ public: virtual EdgesDelegate *clone () const = 0; + void set_base_verbosity (int vb); + int base_verbosity () const + { + return m_base_verbosity; + } + void enable_progress (const std::string &progress_desc); void disable_progress (); @@ -176,6 +182,7 @@ private: bool m_strict_handling; bool m_report_progress; std::string m_progress_desc; + int m_base_verbosity; }; } diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc index 452d160fc..eb6a2bf44 100644 --- a/src/db/db/dbHierNetworkProcessor.cc +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -198,6 +198,20 @@ interaction_test (const db::PolygonRef &a, const db::PolygonRef &b, const db::un } } +template +static bool +interaction_test (const db::Edge &a, const db::Edge &b, const Trans &trans) +{ + return a.intersect (b.transformed (trans)); +} + +template +static bool +interaction_test (const db::Edge &a, const db::Edge &b, const db::unit_trans &) +{ + return a.intersect (b); +} + template bool Connectivity::interacts (const T &a, unsigned int la, const T &b, unsigned int lb, const Trans &trans) const { @@ -212,6 +226,8 @@ bool Connectivity::interacts (const T &a, unsigned int la, const T &b, unsigned // explicit instantiations template DB_PUBLIC bool Connectivity::interacts (const db::PolygonRef &a, unsigned int la, const db::PolygonRef &b, unsigned int lb, const db::UnitTrans &trans) const; template DB_PUBLIC bool Connectivity::interacts (const db::PolygonRef &a, unsigned int la, const db::PolygonRef &b, unsigned int lb, const db::ICplxTrans &trans) const; +template DB_PUBLIC bool Connectivity::interacts (const db::Edge &a, unsigned int la, const db::Edge &b, unsigned int lb, const db::UnitTrans &trans) const; +template DB_PUBLIC bool Connectivity::interacts (const db::Edge &a, unsigned int la, const db::Edge &b, unsigned int lb, const db::ICplxTrans &trans) const; // ------------------------------------------------------------------------------ // local_cluster implementation @@ -560,7 +576,9 @@ size_t local_cluster::split (double max_area_ratio, Iter &output) const // explicit instantiations template class DB_PUBLIC local_cluster; +template class DB_PUBLIC local_cluster; template DB_PUBLIC size_t local_cluster::split > > > (double, std::back_insert_iterator > > &) const; +template DB_PUBLIC size_t local_cluster::split > > > (double, std::back_insert_iterator > > &) const; // ------------------------------------------------------------------------------ // local_clusters implementation @@ -891,6 +909,7 @@ local_clusters::apply_attr_equivalences (const tl::equivalence_clusters; +template class DB_PUBLIC local_clusters; // ------------------------------------------------------------------------------ // connected_clusters_iterator implementation @@ -912,6 +931,7 @@ connected_clusters_iterator::connected_clusters_iterator (const connected_clu // explicit instantiations template class DB_PUBLIC connected_clusters_iterator; +template class DB_PUBLIC connected_clusters_iterator; // ------------------------------------------------------------------------------ // connected_clusters implementation @@ -975,6 +995,7 @@ connected_clusters::find_cluster_with_connection (const ClusterInstance &inst // explicit instantiations template class DB_PUBLIC connected_clusters; +template class DB_PUBLIC connected_clusters; // ------------------------------------------------------------------------------ // connected_clusters implementation @@ -1909,7 +1930,7 @@ hier_clusters::build_hier_connections (cell_clusters_box_converter &cbc, c // handle local to instance connections { - std::list > heap; + std::list > heap; double area_ratio = 10.0; static std::string desc = tl::to_string (tr ("Local to instance treatment")); @@ -1922,12 +1943,12 @@ hier_clusters::build_hier_connections (cell_clusters_box_converter &cbc, c // we do not actually need the original clusters. For a better performance we optimize the // area ratio and split, but we keep the ID the same. - std::back_insert_iterator > > iout = std::back_inserter (heap); + std::back_insert_iterator > > iout = std::back_inserter (heap); size_t n = c->split (area_ratio, iout); if (n == 0) { bs2.insert1 (c.operator-> (), 0); } else { - std::list >::iterator h = heap.end (); + typename std::list >::iterator h = heap.end (); while (n-- > 0) { bs2.insert1 ((--h).operator-> (), 0); } @@ -2053,6 +2074,11 @@ template void insert_transformed (db::Layout &layout, db::Shapes & shapes.insert (db::PolygonRef (poly, layout.shape_repository ())); } +template void insert_transformed (db::Layout & /*layout*/, db::Shapes &shapes, const db::Edge &s, const Trans &t) +{ + shapes.insert (s.transformed (t)); +} + template void hier_clusters::return_to_hierarchy (db::Layout &layout, const std::map &lm) const @@ -2085,6 +2111,7 @@ hier_clusters::return_to_hierarchy (db::Layout &layout, const std::map; +template class DB_PUBLIC hier_clusters; // ------------------------------------------------------------------------------ // recursive_cluster_shape_iterator implementation @@ -2199,6 +2226,7 @@ void recursive_cluster_shape_iterator::down (db::cell_index_type ci, typename // explicit instantiations template class DB_PUBLIC recursive_cluster_shape_iterator; +template class DB_PUBLIC recursive_cluster_shape_iterator; // ------------------------------------------------------------------------------ // recursive_cluster_iterator implementation @@ -2271,6 +2299,7 @@ void recursive_cluster_iterator::down (db::cell_index_type ci, typename db::l // explicit instantiations template class DB_PUBLIC recursive_cluster_iterator; +template class DB_PUBLIC recursive_cluster_iterator; // ------------------------------------------------------------------------------ // incoming_cluster_connections implementation @@ -2351,5 +2380,6 @@ incoming_cluster_connections::ensure_computed_parent (db::cell_index_type ci) // explicit instantiations template class DB_PUBLIC incoming_cluster_connections; +template class DB_PUBLIC incoming_cluster_connections; } diff --git a/src/db/db/dbHierarchyBuilder.cc b/src/db/db/dbHierarchyBuilder.cc index d7a04f581..4a435c85c 100644 --- a/src/db/db/dbHierarchyBuilder.cc +++ b/src/db/db/dbHierarchyBuilder.cc @@ -598,4 +598,38 @@ void PolygonReferenceHierarchyBuilderShapeReceiver::push (const db::Polygon &sha target->insert (db::PolygonRef (shape, mp_layout->shape_repository ())); } +// --------------------------------------------------------------------------------------------- + +void EdgeBuildingHierarchyBuilderShapeReceiver::push (const db::Shape &shape, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) +{ + if (shape.is_polygon () || shape.is_simple_polygon () || shape.is_path ()) { + db::Polygon poly; + shape.polygon (poly); + push (poly, region, complex_region, target); + } else if (shape.is_box ()) { + push (shape.box (), region, complex_region, target); + } else if (shape.is_edge ()) { + target->insert (shape.edge ()); + } +} + +void EdgeBuildingHierarchyBuilderShapeReceiver::push (const db::Box &box, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target) +{ + if (! box.empty ()) { + target->insert (db::Edge (box.p1 (), box.upper_left ())); + target->insert (db::Edge (box.upper_left (), box.p2 ())); + target->insert (db::Edge (box.p2 (), box.lower_right ())); + target->insert (db::Edge (box.lower_right (), box.p1 ())); + } +} + +void EdgeBuildingHierarchyBuilderShapeReceiver::push (const db::Polygon &poly, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target) +{ + for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) { + target->insert (*e); + } +} + +// --------------------------------------------------------------------------------------------- + } diff --git a/src/db/db/dbHierarchyBuilder.h b/src/db/db/dbHierarchyBuilder.h index b9fd1b995..cad11c32f 100644 --- a/src/db/db/dbHierarchyBuilder.h +++ b/src/db/db/dbHierarchyBuilder.h @@ -148,6 +148,18 @@ private: db::property_names_id_type m_text_prop_id; }; +/** + * @brief An edge-generating shape receiver that feeds a shapes array after turning the shapes into edges + */ +class DB_PUBLIC EdgeBuildingHierarchyBuilderShapeReceiver + : public HierarchyBuilderShapeReceiver +{ +public: + virtual void push (const db::Shape &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); + virtual void push (const db::Box &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); + virtual void push (const db::Polygon &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target); +}; + /** * @brief A class building a hierarchy from a recursive shape iterator in push mode *