diff --git a/src/db/db/db.pro b/src/db/db/db.pro index 295976015..390e18425 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -58,6 +58,7 @@ SOURCES = \ dbLog.cc \ dbManager.cc \ dbMatrix.cc \ + dbMeasureEval.cc \ dbMemStatistics.cc \ dbMutableEdgePairs.cc \ dbMutableEdges.cc \ @@ -139,6 +140,7 @@ SOURCES = \ gsiDeclDbLog.cc \ gsiDeclDbManager.cc \ gsiDeclDbMatrix.cc \ + gsiDeclDbMeasureHelpers.cc \ gsiDeclDbMetaInfo.cc \ gsiDeclDbPath.cc \ gsiDeclDbPoint.cc \ @@ -295,6 +297,7 @@ HEADERS = \ dbLog.h \ dbManager.h \ dbMatrix.h \ + dbMeasureEval.h \ dbMemStatistics.h \ dbMetaInfo.h \ dbMutableEdgePairs.h \ @@ -431,6 +434,7 @@ HEADERS = \ dbNetShape.h \ dbShapeCollection.h \ dbShapeCollectionUtils.h \ + gsiDeclDbMeasureHelpers.h \ gsiDeclDbPropertiesSupport.h RESOURCES = \ diff --git a/src/db/db/dbAsIfFlatEdgePairs.cc b/src/db/db/dbAsIfFlatEdgePairs.cc index 29dc42390..1eb18c432 100644 --- a/src/db/db/dbAsIfFlatEdgePairs.cc +++ b/src/db/db/dbAsIfFlatEdgePairs.cc @@ -160,13 +160,17 @@ AsIfFlatEdgePairs::processed (const EdgePairProcessorBase &filter) const { std::unique_ptr edge_pairs (new FlatEdgePairs ()); - std::vector res_edge_pairs; + std::vector res_edge_pairs; for (EdgePairsIterator e = begin (); ! e.at_end (); ++e) { res_edge_pairs.clear (); - filter.process (*e, res_edge_pairs); - for (std::vector::const_iterator er = res_edge_pairs.begin (); er != res_edge_pairs.end (); ++er) { - edge_pairs->insert (*er); + filter.process (e.wp (), res_edge_pairs); + for (auto er = res_edge_pairs.begin (); er != res_edge_pairs.end (); ++er) { + if (er->properties_id () != 0) { + edge_pairs->insert (*er); + } else { + edge_pairs->insert (er->base ()); + } } } @@ -182,17 +186,16 @@ AsIfFlatEdgePairs::processed_to_polygons (const EdgePairToPolygonProcessorBase & region->set_merged_semantics (false); } - std::vector res_polygons; + std::vector res_polygons; for (EdgePairsIterator e (begin ()); ! e.at_end (); ++e) { res_polygons.clear (); - filter.process (*e, res_polygons); - for (std::vector::const_iterator pr = res_polygons.begin (); pr != res_polygons.end (); ++pr) { - db::properties_id_type prop_id = e.prop_id (); - if (prop_id != 0) { - region->insert (db::PolygonWithProperties (*pr, prop_id)); - } else { + filter.process (e.wp (), res_polygons); + for (auto pr = res_polygons.begin (); pr != res_polygons.end (); ++pr) { + if (pr->properties_id () != 0) { region->insert (*pr); + } else { + region->insert (pr->base ()); } } } @@ -209,17 +212,16 @@ AsIfFlatEdgePairs::processed_to_edges (const EdgePairToEdgeProcessorBase &filter edges->set_merged_semantics (false); } - std::vector res_edges; + std::vector res_edges; for (EdgePairsIterator e (begin ()); ! e.at_end (); ++e) { res_edges.clear (); - filter.process (*e, res_edges); - for (std::vector::const_iterator pr = res_edges.begin (); pr != res_edges.end (); ++pr) { - db::properties_id_type prop_id = e.prop_id (); - if (prop_id != 0) { - edges->insert (db::EdgeWithProperties (*pr, prop_id)); - } else { + filter.process (e.wp (), res_edges); + for (auto pr = res_edges.begin (); pr != res_edges.end (); ++pr) { + if (pr->properties_id () != 0) { edges->insert (*pr); + } else { + edges->insert (pr->base ()); } } } diff --git a/src/db/db/dbAsIfFlatEdges.cc b/src/db/db/dbAsIfFlatEdges.cc index 6ab1eac43..0f09068b5 100644 --- a/src/db/db/dbAsIfFlatEdges.cc +++ b/src/db/db/dbAsIfFlatEdges.cc @@ -648,13 +648,17 @@ AsIfFlatEdges::processed (const EdgeProcessorBase &filter) const edges->set_merged_semantics (false); } - std::vector res_edges; + 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); + filter.process (e.wp (), res_edges); + for (auto er = res_edges.begin (); er != res_edges.end (); ++er) { + if (er->properties_id () != 0) { + edges->insert (*er); + } else { + edges->insert (er->base ()); + } } } @@ -670,13 +674,17 @@ AsIfFlatEdges::processed_to_edge_pairs (const EdgeToEdgePairProcessorBase &filte edge_pairs->set_merged_semantics (false); } - std::vector res_edge_pairs; + std::vector res_edge_pairs; for (EdgesIterator e (filter.requires_raw_input () ? begin () : begin_merged ()); ! e.at_end (); ++e) { res_edge_pairs.clear (); - filter.process (*e, res_edge_pairs); - for (std::vector::const_iterator epr = res_edge_pairs.begin (); epr != res_edge_pairs.end (); ++epr) { - edge_pairs->insert (*epr); + filter.process (e.wp (), res_edge_pairs); + for (auto epr = res_edge_pairs.begin (); epr != res_edge_pairs.end (); ++epr) { + if (epr->properties_id () != 0) { + edge_pairs->insert (*epr); + } else { + edge_pairs->insert (epr->base ()); + } } } @@ -692,13 +700,17 @@ AsIfFlatEdges::processed_to_polygons (const EdgeToPolygonProcessorBase &filter) region->set_merged_semantics (false); } - std::vector res_polygons; + std::vector res_polygons; for (EdgesIterator e (filter.requires_raw_input () ? begin () : begin_merged ()); ! e.at_end (); ++e) { res_polygons.clear (); - filter.process (*e, res_polygons); - for (std::vector::const_iterator pr = res_polygons.begin (); pr != res_polygons.end (); ++pr) { - region->insert (*pr); + filter.process (e.wp (), res_polygons); + for (auto pr = res_polygons.begin (); pr != res_polygons.end (); ++pr) { + if (pr->properties_id () != 0) { + region->insert (*pr); + } else { + region->insert (pr->base ()); + } } } @@ -731,9 +743,17 @@ AsIfFlatEdges::filtered_pair (const EdgeFilterBase &filter) const for (EdgesIterator p (begin_merged ()); ! p.at_end (); ++p) { if (filter.selected (*p, p.prop_id ())) { - new_region_true->insert (*p); + if (p.prop_id () != 0) { + new_region_true->insert (db::EdgeWithProperties (*p, p.prop_id ())); + } else { + new_region_true->insert (*p); + } } else { - new_region_false->insert (*p); + if (p.prop_id () != 0) { + new_region_false->insert (db::EdgeWithProperties (*p, p.prop_id ())); + } else { + new_region_false->insert (*p); + } } } diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index 1ea27bb98..56e5d608b 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -155,29 +155,29 @@ AsIfFlatRegion::edges (const EdgeFilterBase *filter, const PolygonToEdgeProcesso } result->reserve (n); - std::vector heap; + std::vector heap; for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { - db::properties_id_type prop_id = p.prop_id (); - if (proc) { heap.clear (); - proc->process (*p, heap); + proc->process (p.wp (), heap); for (auto e = heap.begin (); e != heap.end (); ++e) { - if (! filter || filter->selected (*e, prop_id)) { - if (prop_id != 0) { - result->insert (db::EdgeWithProperties (*e, prop_id)); - } else { + if (! filter || filter->selected (*e, e->properties_id ())) { + if (e->properties_id () != 0) { result->insert (*e); + } else { + result->insert (e->base ()); } } } } else { + auto prop_id = p.prop_id (); + for (db::Polygon::polygon_edge_iterator e = p->begin_edge (); ! e.at_end (); ++e) { if (! filter || filter->selected (*e, prop_id)) { if (prop_id != 0) { @@ -325,7 +325,7 @@ struct ComparePolygonsWithProperties } -void AsIfFlatRegion::merge_polygons_to (db::Shapes &output, bool min_coherence, unsigned int min_wc) const +void AsIfFlatRegion::merge_polygons_to (db::Shapes &output, bool min_coherence, unsigned int min_wc, bool join_properties_on_merge) const { db::EdgeProcessor ep (report_progress (), progress_desc ()); ep.set_base_verbosity (base_verbosity ()); @@ -333,16 +333,101 @@ void AsIfFlatRegion::merge_polygons_to (db::Shapes &output, bool min_coherence, // count edges and reserve memory size_t n = 0; db::properties_id_type prop_id = 0; - bool need_split_props = false; + bool multiple_properties = false; for (RegionIterator s (begin ()); ! s.at_end (); ++s, ++n) { if (n == 0) { prop_id = s.prop_id (); - } else if (! need_split_props && prop_id != s.prop_id ()) { - need_split_props = true; + } else if (! multiple_properties && prop_id != s.prop_id ()) { + multiple_properties = true; } } - if (need_split_props) { + if (multiple_properties && join_properties_on_merge) { + + // this merge variant requires a two-step approach: we first and then join original properties IDs + // in a separate interaction step + + std::vector org_prop_ids; + org_prop_ids.reserve (n); + + n = 0; + for (RegionIterator p (begin ()); ! p.at_end (); ++p) { + n += p->vertices (); + } + ep.reserve (n); + + size_t org_poly_id = 0; + for (RegionIterator p (begin ()); ! p.at_end (); ++p, ++org_poly_id) { + org_prop_ids.push_back (p.prop_id ()); + ep.insert (*p, org_poly_id); + } + + // and run the merge step + db::MergeOp op (min_wc); + db::PolygonContainer pc; + db::PolygonGenerator pg (pc, false /*don't resolve holes*/, min_coherence); + ep.process (pg, op); + + // reserve space for new (merged) polygons + for (auto p = pc.polygons ().begin (); p != pc.polygons ().end (); ++p) { + n += p->vertices (); + } + ep.reserve (n); + + size_t merged_poly_id = org_poly_id; + for (auto p = pc.polygons ().begin (); p != pc.polygons ().end (); ++p, ++merged_poly_id) { + ep.insert (*p, merged_poly_id); + } + + // compute interactions between merged and original polygons + + db::InteractionDetector id; + id.set_include_touching (false); + db::EdgeSink es; + ep.process (es, id); + id.finish (); + + // collect original property IDs per merged polygon + + std::vector > prop_ids_per_merged_polygon; + prop_ids_per_merged_polygon.resize (merged_poly_id - org_poly_id); + + for (auto ii = id.begin (); ii != id.end (); ++ii) { + auto first = std::min (ii->first, ii->second); + auto second = std::max (ii->first, ii->second); + if (first < org_poly_id && second >= org_poly_id) { + prop_ids_per_merged_polygon [second - org_poly_id].insert (org_prop_ids [first]); + } + } + + // Form new polygons with joined properties + + for (auto p = pc.polygons ().begin (); p != pc.polygons ().end (); ++p) { + + const std::set &prop_ids = prop_ids_per_merged_polygon [p - pc.polygons ().begin ()]; + + db::properties_id_type prop_id = 0; + if (prop_ids.size () == 1) { + prop_id = *prop_ids.begin (); + } else if (prop_ids.size () > 1) { + db::PropertiesSet ps; + for (auto p = prop_ids.begin (); p != prop_ids.end (); ++p) { + // merge in "larger one wins" mode - the advantage of this mode is that + // it is independent on the order of the attribute sets (which in fact are pointers) + ps.join_max (db::properties (*p)); + } + prop_id = db::properties_id (ps); + } + + if (prop_id != 0) { + output.insert (db::PolygonWithProperties (*p, prop_id)); + } else { + output.insert (*p); + } + + } + + } else if (multiple_properties) { db::Shapes result (output.is_editable ()); @@ -441,9 +526,17 @@ AsIfFlatRegion::filtered_pair (const PolygonFilterBase &filter) const for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { if (filter.selected (*p, p.prop_id ())) { - new_region_true->insert (*p); + if (p.prop_id () != 0) { + new_region_true->insert (db::PolygonWithProperties (*p, p.prop_id ())); + } else { + new_region_true->insert (*p); + } } else { - new_region_false->insert (*p); + if (p.prop_id () != 0) { + new_region_false->insert (db::PolygonWithProperties (*p, p.prop_id ())); + } else { + new_region_false->insert (*p); + } } } @@ -460,17 +553,17 @@ AsIfFlatRegion::processed (const PolygonProcessorBase &filter) const new_region->set_merged_semantics (false); } - std::vector poly_res; + std::vector poly_res; for (RegionIterator p (filter.requires_raw_input () ? begin () : begin_merged ()); ! p.at_end (); ++p) { poly_res.clear (); - filter.process (*p, poly_res); - for (std::vector::const_iterator pr = poly_res.begin (); pr != poly_res.end (); ++pr) { - if (p.prop_id () != 0) { - new_region->insert (db::PolygonWithProperties (*pr, p.prop_id ())); - } else { + filter.process (p.wp (), poly_res); + for (auto pr = poly_res.begin (); pr != poly_res.end (); ++pr) { + if (pr->properties_id () != 0) { new_region->insert (*pr); + } else { + new_region->insert (pr->base ()); } } @@ -487,17 +580,17 @@ AsIfFlatRegion::processed_to_edges (const PolygonToEdgeProcessorBase &filter) co new_edges->set_merged_semantics (false); } - std::vector edge_res; + std::vector edge_res; for (RegionIterator 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 er = edge_res.begin (); er != edge_res.end (); ++er) { - if (p.prop_id () != 0) { - new_edges->insert (db::EdgeWithProperties (*er, p.prop_id ())); - } else { + filter.process (p.wp (), edge_res); + for (auto er = edge_res.begin (); er != edge_res.end (); ++er) { + if (er->properties_id () != 0) { new_edges->insert (*er); + } else { + new_edges->insert (er->base ()); } } @@ -514,17 +607,17 @@ AsIfFlatRegion::processed_to_edge_pairs (const PolygonToEdgePairProcessorBase &f new_edge_pairs->set_merged_semantics (false); } - std::vector edge_pair_res; + std::vector edge_pair_res; for (RegionIterator p (filter.requires_raw_input () ? begin () : begin_merged ()); ! p.at_end (); ++p) { edge_pair_res.clear (); - filter.process (*p, edge_pair_res); - for (std::vector::const_iterator epr = edge_pair_res.begin (); epr != edge_pair_res.end (); ++epr) { - if (p.prop_id () != 0) { - new_edge_pairs->insert (db::EdgePairWithProperties (*epr, p.prop_id ())); - } else { + filter.process (p.wp (), edge_pair_res); + for (auto epr = edge_pair_res.begin (); epr != edge_pair_res.end (); ++epr) { + if (epr->properties_id () != 0) { new_edge_pairs->insert (*epr); + } else { + new_edge_pairs->insert (epr->base ()); } } @@ -1241,7 +1334,7 @@ AsIfFlatRegion::run_single_polygon_check (db::edge_relation_type rel, db::Coord } RegionDelegate * -AsIfFlatRegion::merged (bool min_coherence, unsigned int min_wc) const +AsIfFlatRegion::merged (bool min_coherence, unsigned int min_wc, bool join_properties_on_merge) const { if (empty ()) { @@ -1259,7 +1352,7 @@ AsIfFlatRegion::merged (bool min_coherence, unsigned int min_wc) const } else { std::unique_ptr new_region (new FlatRegion (true)); - merge_polygons_to (new_region->raw_polygons (), min_coherence, min_wc); + merge_polygons_to (new_region->raw_polygons (), min_coherence, min_wc, join_properties_on_merge); return new_region.release (); diff --git a/src/db/db/dbAsIfFlatRegion.h b/src/db/db/dbAsIfFlatRegion.h index cddf88d5e..8a86d998a 100644 --- a/src/db/db/dbAsIfFlatRegion.h +++ b/src/db/db/dbAsIfFlatRegion.h @@ -108,17 +108,17 @@ class DB_PUBLIC AsIfFlatRegion return merged (); } - virtual RegionDelegate *merged_in_place (bool min_coherence, unsigned int min_wc) + virtual RegionDelegate *merged_in_place (bool min_coherence, unsigned int min_wc, bool join_properties_on_merge) { - return merged (min_coherence, min_wc); + return merged (min_coherence, min_wc, join_properties_on_merge); } virtual RegionDelegate *merged () const { - return merged (min_coherence (), 0); + return merged (min_coherence (), 0, join_properties_on_merge ()); } - virtual RegionDelegate *merged (bool min_coherence, unsigned int min_wc) const; + virtual RegionDelegate *merged (bool min_coherence, unsigned int min_wc, bool join_properties_on_merge) const; virtual RegionDelegate *sized (coord_type d, unsigned int mode) const; virtual RegionDelegate *sized (coord_type dx, coord_type dy, unsigned int mode) const; @@ -288,7 +288,7 @@ class DB_PUBLIC AsIfFlatRegion protected: void update_bbox (const db::Box &box); void invalidate_bbox (); - void merge_polygons_to (db::Shapes &output, bool min_coherence, unsigned int min_wc) const; + void merge_polygons_to (db::Shapes &output, bool min_coherence, unsigned int min_wc, bool join_properties_on_merge) const; RegionDelegate *and_or_not_with (bool is_and, const Region &other, PropertyConstraint property_constraint) const; virtual EdgePairsDelegate *run_check (db::edge_relation_type rel, bool different_polygons, const Region *other, db::Coord d, const RegionCheckOptions &options) const; diff --git a/src/db/db/dbAsIfFlatTexts.cc b/src/db/db/dbAsIfFlatTexts.cc index a9e8c0e91..f8dd3e086 100644 --- a/src/db/db/dbAsIfFlatTexts.cc +++ b/src/db/db/dbAsIfFlatTexts.cc @@ -179,9 +179,17 @@ AsIfFlatTexts::filtered_pair (const TextFilterBase &filter) const for (TextsIterator p (begin ()); ! p.at_end (); ++p) { if (filter.selected (*p, p.prop_id ())) { - new_texts_true->insert (*p); + if (p.prop_id () != 0) { + new_texts_true->insert (db::TextWithProperties (*p, p.prop_id ())); + } else { + new_texts_true->insert (*p); + } } else { - new_texts_false->insert (*p); + if (p.prop_id () != 0) { + new_texts_false->insert (db::TextWithProperties (*p, p.prop_id ())); + } else { + new_texts_false->insert (*p); + } } } @@ -193,13 +201,17 @@ AsIfFlatTexts::processed (const TextProcessorBase &filter) const { std::unique_ptr texts (new FlatTexts ()); - std::vector res_texts; + std::vector res_texts; for (TextsIterator e = begin (); ! e.at_end (); ++e) { res_texts.clear (); - filter.process (*e, res_texts); - for (std::vector::const_iterator er = res_texts.begin (); er != res_texts.end (); ++er) { - texts->insert (*er); + filter.process (e.wp (), res_texts); + for (auto er = res_texts.begin (); er != res_texts.end (); ++er) { + if (er->properties_id () != 0) { + texts->insert (*er); + } else { + texts->insert (er->base ()); + } } } @@ -215,16 +227,16 @@ AsIfFlatTexts::processed_to_polygons (const TextToPolygonProcessorBase &filter) region->set_merged_semantics (false); } - std::vector res_polygons; + std::vector res_polygons; for (TextsIterator e (begin ()); ! e.at_end (); ++e) { res_polygons.clear (); - filter.process (*e, res_polygons); - for (std::vector::const_iterator pr = res_polygons.begin (); pr != res_polygons.end (); ++pr) { - if (e.prop_id () != 0) { - region->insert (db::PolygonWithProperties (*pr, e.prop_id ())); - } else { + filter.process (e.wp (), res_polygons); + for (auto pr = res_polygons.begin (); pr != res_polygons.end (); ++pr) { + if (pr->properties_id () != 0) { region->insert (*pr); + } else { + region->insert (pr->base ()); } } } diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index aaa6e5fb3..8791b7ded 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -231,6 +231,11 @@ void DeepRegion::min_coherence_changed () set_is_merged (false); } +void DeepRegion::join_properties_on_merge_changed () +{ + set_is_merged (false); +} + void DeepRegion::do_insert (const db::Polygon &polygon, db::properties_id_type prop_id) { db::Layout &layout = deep_layer ().layout (); @@ -520,7 +525,7 @@ class ClusterMerger { public: ClusterMerger (unsigned int layer, db::Layout &layout, const db::hier_clusters &hc, bool min_coherence, bool report_progress, const std::string &progress_desc) - : m_layer (layer), mp_layout (&layout), mp_hc (&hc), m_min_coherence (min_coherence), m_ep (report_progress, progress_desc) + : m_layer (layer), mp_layout (&layout), mp_hc (&hc), m_min_coherence (min_coherence), m_text_name_id (0), m_ep (report_progress, progress_desc) { // .. nothing yet .. } @@ -530,6 +535,19 @@ class ClusterMerger m_ep.set_base_verbosity (vb); } + /** + * @brief Specifies the label property name ID for pseudo-label polygons + * If set to 0, the merge does not skip pseudo-labels. + */ + void set_text_name (const tl::Variant &n) + { + if (n.is_nil ()) { + m_text_name_id = 0; + } else { + m_text_name_id = db::property_names_id (n); + } + } + db::Shapes &merged (size_t cid, db::cell_index_type ci, unsigned int min_wc = 0) { return compute_merged (cid, ci, true, min_wc); @@ -548,8 +566,19 @@ class ClusterMerger db::Layout *mp_layout; const db::hier_clusters *mp_hc; bool m_min_coherence; + db::property_names_id_type m_text_name_id; db::EdgeProcessor m_ep; + bool skip_pseudo_label (db::properties_id_type prop_id) + { + if (prop_id == 0 || m_text_name_id == 0) { + return false; + } else { + const db::PropertiesSet &ps = db::properties (prop_id); + return (ps.size () == 1 && ps.begin ()->first == m_text_name_id); + } + } + db::properties_id_type property_id (size_t cid, db::cell_index_type ci, bool initial) { std::map, db::properties_id_type>::iterator s = m_property_id_per_cluster.find (std::make_pair (cid, ci)); @@ -563,22 +592,41 @@ class ClusterMerger return s->second; } - s = m_property_id_per_cluster.insert (std::make_pair (std::make_pair (cid, ci), db::properties_id_type (0))).first; - const db::connected_clusters &cc = mp_hc->clusters_per_cell (ci); const db::local_cluster &c = cc.cluster_by_id (cid); - if (c.begin_attr () != c.end_attr ()) { + // collect attributes (aka properties) of the root and the child clusters and join them - s->second = *c.begin_attr (); + s = m_property_id_per_cluster.insert (std::make_pair (std::make_pair (cid, ci), db::properties_id_type (0))).first; - } else { + std::set attrs (c.begin_attr (), c.end_attr ()); - 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 () && s->second == db::properties_id_type (0); ++i) { - s->second = property_id (i->id (), i->inst_cell_index (), false); + 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) { + auto prop_id = property_id (i->id (), i->inst_cell_index (), false); + if (prop_id != 0) { + attrs.insert (prop_id); + } + } + + if (attrs.size () > 1) { + + // join the properties + db::PropertiesSet ps; + for (auto a = attrs.begin (); a != attrs.end (); ++a) { + if (! skip_pseudo_label (*a)) { + // merge in "larger one wins" mode - the advantage of this mode is that + // it is independent on the order of the attribute sets (which in fact are pointers) + ps.join_max (db::properties (*a)); + } } + s->second = db::properties_id (ps); + + } else if (! attrs.empty () && ! skip_pseudo_label (*attrs.begin ())) { + + s->second = *attrs.begin (); + } return s->second; @@ -702,7 +750,7 @@ DeepRegion::ensure_merged_polygons_valid () const db::Connectivity conn; conn.connect (deep_layer ()); hc.set_base_verbosity (base_verbosity () + 10); - hc.build (layout, deep_layer ().initial_cell (), conn, 0, deep_layer ().breakout_cells (), true /*separate_attributes*/); + hc.build (layout, deep_layer ().initial_cell (), conn, 0, deep_layer ().breakout_cells (), ! join_properties_on_merge ()); // collect the clusters and merge them into big polygons // NOTE: using the ClusterMerger we merge bottom-up forming bigger and bigger polygons. This is @@ -711,6 +759,14 @@ DeepRegion::ensure_merged_polygons_valid () const ClusterMerger cm (deep_layer ().layer (), layout, hc, min_coherence (), report_progress (), progress_desc ()); cm.set_base_verbosity (base_verbosity () + 10); + // Specify the property name ID for the pseudo-labels, so we can filter out those properties + // (for backward compatibility only if join_properties_on_merge is true - if we don't with + // join_properties_on_merge, the pseudo-label properties may get attached to other shapes which + // will be taken as texts then) + if (join_properties_on_merge ()) { + cm.set_text_name (deep_layer ().store ()->text_property_name ()); + } + // 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 ()); @@ -1505,12 +1561,13 @@ DeepRegion::edges (const EdgeFilterBase *filter, const PolygonToEdgeProcessorBas const db::Shapes &s = c->shapes (polygons.layer ()); db::Shapes &st = c->shapes (res->deep_layer ().layer ()); - std::vector heap; + std::vector heap; for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) { - db::Polygon poly; + db::PolygonWithProperties poly; si->polygon (poly); + poly.properties_id (si->prop_id ()); if (proc) { @@ -1518,16 +1575,16 @@ DeepRegion::edges (const EdgeFilterBase *filter, const PolygonToEdgeProcessorBas proc->process (poly, heap); for (auto e = heap.begin (); e != heap.end (); ++e) { - if (! filter || filter->selected ((*e).transformed (tr), si->prop_id ())) { - st.insert (db::EdgeWithProperties (*e, si->prop_id ())); + if (! filter || filter->selected ((*e).transformed (tr), e->properties_id ())) { + st.insert (*e); } } } else { for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) { - if (! filter || filter->selected ((*e).transformed (tr), si->prop_id ())) { - st.insert (db::EdgeWithProperties (*e, si->prop_id ())); + if (! filter || filter->selected ((*e).transformed (tr), poly.properties_id ())) { + st.insert (db::EdgeWithProperties (*e, poly.properties_id ())); } } @@ -1741,10 +1798,10 @@ DeepRegion::merged_in_place () } RegionDelegate * -DeepRegion::merged_in_place (bool min_coherence, unsigned int min_wc) +DeepRegion::merged_in_place (bool min_coherence, unsigned int min_wc, bool join_properties_on_merge) { // TODO: implement to be really in-place - return merged (min_coherence, min_wc); + return merged (min_coherence, min_wc, join_properties_on_merge); } RegionDelegate * @@ -1770,7 +1827,7 @@ DeepRegion::merged () const } RegionDelegate * -DeepRegion::merged (bool min_coherence, unsigned int min_wc) const +DeepRegion::merged (bool min_coherence, unsigned int min_wc, bool join_properties_on_merge) const { if (empty ()) { return clone (); @@ -1784,7 +1841,7 @@ DeepRegion::merged (bool min_coherence, unsigned int min_wc) const db::Connectivity conn; conn.connect (deep_layer ()); hc.set_base_verbosity (base_verbosity () + 10); - hc.build (layout, deep_layer ().initial_cell (), conn); + hc.build (layout, deep_layer ().initial_cell (), conn, 0, 0, ! join_properties_on_merge); // collect the clusters and merge them into big polygons // NOTE: using the ClusterMerger we merge bottom-up forming bigger and bigger polygons. This is @@ -1795,6 +1852,14 @@ DeepRegion::merged (bool min_coherence, unsigned int min_wc) const ClusterMerger cm (deep_layer ().layer (), layout, hc, min_coherence, report_progress (), progress_desc ()); cm.set_base_verbosity (base_verbosity () + 10); + // Specify the property name ID for the pseudo-labels, so we can filter out those properties + // (for backward compatibility only if join_properties_on_merge is true - if we don't with + // join_properties_on_merge, the pseudo-label properties may get attached to other shapes which + // will be taken as texts then) + if (join_properties_on_merge) { + cm.set_text_name (deep_layer ().store ()->text_property_name ()); + } + 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) { diff --git a/src/db/db/dbDeepRegion.h b/src/db/db/dbDeepRegion.h index 178a21f02..293063665 100644 --- a/src/db/db/dbDeepRegion.h +++ b/src/db/db/dbDeepRegion.h @@ -128,10 +128,10 @@ class DB_PUBLIC DeepRegion virtual std::pair filtered_pair (const PolygonFilterBase &filter) const; virtual RegionDelegate *merged_in_place (); - virtual RegionDelegate *merged_in_place (bool min_coherence, unsigned int min_wc); + virtual RegionDelegate *merged_in_place (bool min_coherence, unsigned int min_wc, bool join_properties_on_merge); virtual RegionDelegate *merged () const; - virtual RegionDelegate *merged (bool min_coherence, unsigned int min_wc) const; + virtual RegionDelegate *merged (bool min_coherence, unsigned int min_wc, bool join_properties_on_merge) const; virtual RegionDelegate *sized (coord_type d, unsigned int mode) const; virtual RegionDelegate *sized (coord_type dx, coord_type dy, unsigned int mode) const; @@ -155,6 +155,7 @@ class DB_PUBLIC DeepRegion protected: virtual void merged_semantics_changed (); virtual void min_coherence_changed (); + virtual void join_properties_on_merge_changed (); virtual EdgePairsDelegate *run_check (db::edge_relation_type rel, bool different_polygons, const Region *other, db::Coord d, const RegionCheckOptions &options) const; virtual EdgePairsDelegate *run_single_polygon_check (db::edge_relation_type rel, db::Coord d, const RegionCheckOptions &options) const; diff --git a/src/db/db/dbEdgePairs.h b/src/db/db/dbEdgePairs.h index 0cffe8960..e72376d4d 100644 --- a/src/db/db/dbEdgePairs.h +++ b/src/db/db/dbEdgePairs.h @@ -55,6 +55,8 @@ class EdgePairs; class DB_PUBLIC EdgePairFilterBase { public: + typedef db::EdgePair shape_type; + EdgePairFilterBase () { } virtual ~EdgePairFilterBase () { } diff --git a/src/db/db/dbEdgePairsDelegate.h b/src/db/db/dbEdgePairsDelegate.h index d4a1efd97..d000911c3 100644 --- a/src/db/db/dbEdgePairsDelegate.h +++ b/src/db/db/dbEdgePairsDelegate.h @@ -52,14 +52,6 @@ EdgePairToPolygonProcessor : m_e (e) { } - void process(const EdgePair &ep, std::vector &res) const - { - db::Polygon poly = ep.normalized ().to_polygon (m_e); - if (poly.vertices () >= 3) { - res.push_back (poly); - } - } - void process(const EdgePairWithProperties &ep, std::vector &res) const { db::Polygon poly = ep.normalized ().to_polygon (m_e); @@ -80,12 +72,6 @@ EdgePairToEdgesProcessor EdgePairToEdgesProcessor () { } - void process(const EdgePair &ep, std::vector &res) const - { - res.push_back (ep.first ()); - res.push_back (ep.second ()); - } - void process(const EdgePairWithProperties &ep, std::vector &res) const { res.push_back (db::EdgeWithProperties (ep.first (), ep.properties_id ())); @@ -101,14 +87,6 @@ EdgePairToFirstEdgesProcessor EdgePairToFirstEdgesProcessor () { } - void process(const EdgePair &ep, std::vector &res) const - { - res.push_back (ep.first ()); - if (ep.is_symmetric ()) { - res.push_back (ep.second ()); - } - } - void process(const EdgePairWithProperties &ep, std::vector &res) const { res.push_back (db::EdgeWithProperties (ep.first (), ep.properties_id ())); @@ -126,13 +104,6 @@ EdgePairToSecondEdgesProcessor EdgePairToSecondEdgesProcessor () { } - void process(const EdgePair &ep, std::vector &res) const - { - if (! ep.is_symmetric ()) { - res.push_back (ep.second ()); - } - } - void process(const EdgePairWithProperties &ep, std::vector &res) const { if (! ep.is_symmetric ()) { @@ -149,11 +120,6 @@ EdgePairToLesserEdgesProcessor EdgePairToLesserEdgesProcessor () { } - void process(const EdgePair &ep, std::vector &res) const - { - res.push_back (ep.lesser ()); - } - void process(const EdgePairWithProperties &ep, std::vector &res) const { res.push_back (db::EdgeWithProperties (ep.lesser (), ep.properties_id ())); @@ -168,11 +134,6 @@ EdgePairToGreaterEdgesProcessor EdgePairToGreaterEdgesProcessor () { } - void process(const EdgePair &ep, std::vector &res) const - { - res.push_back (ep.greater ()); - } - void process(const EdgePairWithProperties &ep, std::vector &res) const { res.push_back (db::EdgeWithProperties (ep.greater (), ep.properties_id ())); diff --git a/src/db/db/dbEdgesDelegate.h b/src/db/db/dbEdgesDelegate.h index 91aea92ee..a1f39d671 100644 --- a/src/db/db/dbEdgesDelegate.h +++ b/src/db/db/dbEdgesDelegate.h @@ -45,6 +45,8 @@ namespace db { class DB_PUBLIC EdgeFilterBase { public: + typedef db::Edge shape_type; + /** * @brief Constructor */ diff --git a/src/db/db/dbEdgesUtils.cc b/src/db/db/dbEdgesUtils.cc index 68db12206..2a3118d39 100644 --- a/src/db/db/dbEdgesUtils.cc +++ b/src/db/db/dbEdgesUtils.cc @@ -184,34 +184,6 @@ EdgeSegmentSelector::EdgeSegmentSelector (int mode, Edge::distance_type length, EdgeSegmentSelector::~EdgeSegmentSelector () { } -void -EdgeSegmentSelector::process (const db::Edge &edge, std::vector &res) const -{ - double l = std::max (edge.double_length () * m_fraction, double (m_length)); - - db::DVector ds; - if (! edge.is_degenerate ()) { - ds = db::DVector (edge.d ()) * (l / edge.double_length ()); - } - - if (m_mode < 0) { - - res.push_back (db::Edge (edge.p1 (), db::Point (db::DPoint (edge.p1 ()) + ds))); - - } else if (m_mode > 0) { - - res.push_back (db::Edge (db::Point (db::DPoint (edge.p2 ()) - ds), edge.p2 ())); - - } else { - - db::DVector dl = ds * 0.5; - 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))); - - } -} - void EdgeSegmentSelector::process (const db::EdgeWithProperties &edge, std::vector &res) const { diff --git a/src/db/db/dbEdgesUtils.h b/src/db/db/dbEdgesUtils.h index 769687b01..563f897f2 100644 --- a/src/db/db/dbEdgesUtils.h +++ b/src/db/db/dbEdgesUtils.h @@ -644,11 +644,6 @@ class DB_PUBLIC ExtendedEdgeProcessor : m_ext_b (ext_b), m_ext_e (ext_e), m_ext_o (ext_o), m_ext_i (ext_i) { } - virtual void process (const Edge &edge, std::vector &res) const - { - res.push_back (extended_edge (edge, m_ext_b, m_ext_e, m_ext_o, m_ext_i)); - } - virtual void process (const EdgeWithProperties &edge, std::vector &res) const { res.push_back (db::PolygonWithProperties (extended_edge (edge, m_ext_b, m_ext_e, m_ext_o, m_ext_i), edge.properties_id ())); @@ -668,7 +663,6 @@ class DB_PUBLIC EdgeSegmentSelector EdgeSegmentSelector (int mode, Edge::distance_type length, double fraction); ~EdgeSegmentSelector (); - virtual void process (const db::Edge &edge, std::vector &res) const; virtual void process (const db::EdgeWithProperties &edge, std::vector &res) const; virtual const TransformationReducer *vars () const { return &m_vars; } diff --git a/src/db/db/dbEmptyRegion.h b/src/db/db/dbEmptyRegion.h index bceabdc06..8b41c9244 100644 --- a/src/db/db/dbEmptyRegion.h +++ b/src/db/db/dbEmptyRegion.h @@ -92,9 +92,9 @@ class DB_PUBLIC EmptyRegion virtual EdgePairsDelegate *processed_to_edge_pairs (const PolygonToEdgePairProcessorBase &) const; virtual RegionDelegate *merged_in_place () { return this; } - virtual RegionDelegate *merged_in_place (bool, unsigned int) { return this; } + virtual RegionDelegate *merged_in_place (bool, unsigned int, bool) { return this; } virtual RegionDelegate *merged () const { return new EmptyRegion (); } - virtual RegionDelegate *merged (bool, unsigned int) const { return new EmptyRegion (); } + virtual RegionDelegate *merged (bool, unsigned int, bool) const { return new EmptyRegion (); } virtual RegionDelegate *sized (coord_type, unsigned int) const { return new EmptyRegion (); } virtual RegionDelegate *sized (coord_type, coord_type, unsigned int) const { return new EmptyRegion (); } diff --git a/src/db/db/dbFlatEdges.cc b/src/db/db/dbFlatEdges.cc index 27e323cae..825ff7fae 100644 --- a/src/db/db/dbFlatEdges.cc +++ b/src/db/db/dbFlatEdges.cc @@ -226,7 +226,7 @@ Box FlatEdges::compute_bbox () const EdgesDelegate * FlatEdges::processed_in_place (const EdgeProcessorBase &filter) { - std::vector edge_res; + std::vector edge_res; db::Shapes &e = *mp_edges; @@ -236,22 +236,22 @@ FlatEdges::processed_in_place (const EdgeProcessorBase &filter) for (EdgesIterator p (filter.requires_raw_input () ? begin () : begin_merged ()); ! p.at_end (); ++p) { edge_res.clear (); - filter.process (*p, edge_res); + filter.process (p.wp (), edge_res); - for (std::vector::const_iterator pr = edge_res.begin (); pr != edge_res.end (); ++pr) { - if (p.prop_id () != 0) { + for (auto pr = edge_res.begin (); pr != edge_res.end (); ++pr) { + if (pr->properties_id () != 0) { if (pw_wp == e.get_layer ().end ()) { - e.get_layer ().insert (db::EdgeWithProperties (*pr, p.prop_id ())); + e.get_layer ().insert (*pr); pw_wp = e.get_layer ().end (); } else { - e.get_layer ().replace (pw_wp++, db::EdgeWithProperties (*pr, p.prop_id ())); + e.get_layer ().replace (pw_wp++, *pr); } } else { if (pw == e.get_layer ().end ()) { - e.get_layer ().insert (*pr); + e.get_layer ().insert (pr->base ()); pw = e.get_layer ().end (); } else { - e.get_layer ().replace (pw++, *pr); + e.get_layer ().replace (pw++, pr->base ()); } } } diff --git a/src/db/db/dbFlatRegion.cc b/src/db/db/dbFlatRegion.cc index f6abd1696..04b3a2bd9 100644 --- a/src/db/db/dbFlatRegion.cc +++ b/src/db/db/dbFlatRegion.cc @@ -99,6 +99,12 @@ void FlatRegion::merged_semantics_changed () m_merged_polygons_valid = false; } +void FlatRegion::join_properties_on_merge_changed () +{ + mp_merged_polygons->clear (); + m_merged_polygons_valid = false; +} + void FlatRegion::min_coherence_changed () { m_is_merged = false; @@ -115,7 +121,7 @@ void FlatRegion::ensure_merged_polygons_valid () const { if (! m_merged_polygons_valid) { - merge_polygons_to (*mp_merged_polygons, min_coherence (), 0); + merge_polygons_to (*mp_merged_polygons, min_coherence (), 0, join_properties_on_merge ()); m_merged_polygons_valid = true; } } @@ -220,16 +226,16 @@ RegionDelegate *FlatRegion::process_in_place (const PolygonProcessorBase &filter db::layer &poly_layer_wp = mp_polygons->get_layer (); db::layer out_wp; - std::vector poly_res; + std::vector poly_res; for (RegionIterator p (filter.requires_raw_input () ? begin () : begin_merged ()); ! p.at_end (); ++p) { poly_res.clear (); - filter.process (*p, poly_res); - if (p.prop_id () != 0) { - for (auto r = poly_res.begin (); r != poly_res.end (); ++r) { - out_wp.insert (db::PolygonWithProperties (*r, p.prop_id ())); + filter.process (p.wp (), poly_res); + for (auto r = poly_res.begin (); r != poly_res.end (); ++r) { + if (r->properties_id () != 0) { + out_wp.insert (*r); + } else { + out_wp.insert (r->base ()); } - } else { - out.insert (poly_res.begin (), poly_res.end ()); } } @@ -260,7 +266,7 @@ RegionDelegate *FlatRegion::merged_in_place () return this; } else { - return merged_in_place (min_coherence (), 0); + return merged_in_place (min_coherence (), 0, join_properties_on_merge ()); } } else { @@ -268,7 +274,7 @@ RegionDelegate *FlatRegion::merged_in_place () } } -RegionDelegate *FlatRegion::merged_in_place (bool min_coherence, unsigned int min_wc) +RegionDelegate *FlatRegion::merged_in_place (bool min_coherence, unsigned int min_wc, bool join_properties_on_merge) { if (empty ()) { @@ -285,7 +291,7 @@ RegionDelegate *FlatRegion::merged_in_place (bool min_coherence, unsigned int mi } else { invalidate_cache (); - merge_polygons_to (*mp_polygons, min_coherence, min_wc); + merge_polygons_to (*mp_polygons, min_coherence, min_wc, join_properties_on_merge); m_is_merged = true; @@ -301,7 +307,7 @@ RegionDelegate *FlatRegion::merged () const if (m_merged_polygons_valid) { return new FlatRegion (*mp_merged_polygons, true); } else { - return AsIfFlatRegion::merged (min_coherence (), 0); + return AsIfFlatRegion::merged (min_coherence (), 0, join_properties_on_merge ()); } } else { diff --git a/src/db/db/dbFlatRegion.h b/src/db/db/dbFlatRegion.h index 02f207d91..7e9adf8ae 100644 --- a/src/db/db/dbFlatRegion.h +++ b/src/db/db/dbFlatRegion.h @@ -81,11 +81,11 @@ class DB_PUBLIC FlatRegion virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const; virtual RegionDelegate *merged_in_place (); - virtual RegionDelegate *merged_in_place (bool min_coherence, unsigned int min_wc); + virtual RegionDelegate *merged_in_place (bool min_coherence, unsigned int min_wc, bool join_properties_on_merge); virtual RegionDelegate *merged () const; - virtual RegionDelegate *merged (bool min_coherence, unsigned int min_wc) const + virtual RegionDelegate *merged (bool min_coherence, unsigned int min_wc, bool join_properties_on_merge) const { - return db::AsIfFlatRegion::merged (min_coherence, min_wc); + return db::AsIfFlatRegion::merged (min_coherence, min_wc, join_properties_on_merge); } virtual RegionDelegate *process_in_place (const PolygonProcessorBase &filter); @@ -131,6 +131,7 @@ class DB_PUBLIC FlatRegion protected: virtual void merged_semantics_changed (); + virtual void join_properties_on_merge_changed (); virtual void min_coherence_changed (); virtual Box compute_bbox () const; void invalidate_cache (); diff --git a/src/db/db/dbGenericShapeIterator.h b/src/db/db/dbGenericShapeIterator.h index 4e44681b6..7125cddc0 100644 --- a/src/db/db/dbGenericShapeIterator.h +++ b/src/db/db/dbGenericShapeIterator.h @@ -284,6 +284,7 @@ class DB_PUBLIC generic_shape_iterator public: typedef T value_type; typedef const value_type &reference; + typedef const db::object_with_properties with_properties_type; typedef const value_type *pointer; typedef std::forward_iterator_tag iterator_category; typedef void difference_type; @@ -373,6 +374,11 @@ class DB_PUBLIC generic_shape_iterator return mp_delegate->get (); } + with_properties_type wp () const + { + return with_properties_type (*mp_delegate->get (), mp_delegate->prop_id ()); + } + generic_shape_iterator &operator++ () { mp_delegate->increment (); diff --git a/src/db/db/dbHierNetworkProcessor.h b/src/db/db/dbHierNetworkProcessor.h index d6333c1fc..d625a78d3 100644 --- a/src/db/db/dbHierNetworkProcessor.h +++ b/src/db/db/dbHierNetworkProcessor.h @@ -403,6 +403,14 @@ class DB_PUBLIC_TEMPLATE local_cluster return m_attrs == other.m_attrs; } + /** + * @brief Gets the number of attributes + */ + size_t attr_count () const + { + return m_attrs.size (); + } + /** * @brief Gets the attribute iterator (begin) */ diff --git a/src/db/db/dbInstances.cc b/src/db/db/dbInstances.cc index 697e42c33..02ca1e743 100644 --- a/src/db/db/dbInstances.cc +++ b/src/db/db/dbInstances.cc @@ -1611,10 +1611,8 @@ Instances::replace_prop_id (const instance_type &ref, db::properties_id_type pro throw tl::Exception (tl::to_string (tr ("Trying to replace an object in a list that it does not belong to"))); } - if (! ref.is_null ()) { - if (ref.prop_id () != prop_id) { - invalidate_prop_ids (); - } + if (! ref.is_null () && (!ref.has_prop_id () || ref.prop_id () != prop_id)) { + invalidate_prop_ids (); cell_inst_wp_array_type new_inst (ref.cell_inst (), prop_id); return replace (ref, new_inst); } else { @@ -1622,7 +1620,29 @@ Instances::replace_prop_id (const instance_type &ref, db::properties_id_type pro } } -void +Instances::instance_type +Instances::clear_properties (const instance_type &ref) +{ + if (ref.instances () != this) { + throw tl::Exception (tl::to_string (tr ("Trying to replace an object in a list that it does not belong to"))); + } + + if (! ref.is_null () && ref.has_prop_id ()) { + + invalidate_prop_ids (); + + cell_inst_array_type new_inst (ref.cell_inst ()); + erase (ref); + return insert (new_inst); + + } else { + + return ref; + + } +} + +void Instances::do_clear_insts () { if (m_generic.any) { diff --git a/src/db/db/dbInstances.h b/src/db/db/dbInstances.h index b472604bc..17d71ab28 100644 --- a/src/db/db/dbInstances.h +++ b/src/db/db/dbInstances.h @@ -1497,6 +1497,13 @@ class DB_PUBLIC Instances */ instance_type replace_prop_id (const instance_type &ref, db::properties_id_type prop_id); + /** + * @brief Clears the properties + * + * @return The reference to the new instance + */ + instance_type clear_properties (const instance_type &ref); + /** * @brief Replace the instance pointed to by the iterator with the given instance * diff --git a/src/db/db/dbLayoutQuery.cc b/src/db/db/dbLayoutQuery.cc index 40835f186..f96560210 100644 --- a/src/db/db/dbLayoutQuery.cc +++ b/src/db/db/dbLayoutQuery.cc @@ -1212,12 +1212,12 @@ class DB_PUBLIC ChildCellFilterState return true; } else { - v = tl::Variant::make_variant (db::ICplxTrans ()); + v = tl::Variant::make_variant (db::DCplxTrans ()); return true; } } else { - v = tl::Variant::make_variant (db::ICplxTrans ()); + v = tl::Variant::make_variant (db::DCplxTrans ()); return true; } diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index ecc43f376..043f1629c 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -34,6 +34,7 @@ #include "dbLayoutToNetlistSoftConnections.h" #include "dbShapeProcessor.h" #include "dbNetlistDeviceClasses.h" +#include "dbMeasureEval.h" #include "dbLog.h" #include "tlGlobPattern.h" @@ -1772,20 +1773,20 @@ class PolygonAreaAndPerimeterCollector } -static void -compute_area_and_perimeter_of_net_shapes (const db::hier_clusters &clusters, db::cell_index_type ci, size_t cid, unsigned int layer_id, db::Polygon::area_type &area, db::Polygon::perimeter_type &perimeter) +void +LayoutToNetlist::compute_area_and_perimeter_of_net_shapes (db::cell_index_type ci, size_t cid, unsigned int layer_id, db::Polygon::area_type &area, db::Polygon::perimeter_type &perimeter) const { db::EdgeProcessor ep; // count vertices and reserve space size_t n = 0; - for (db::recursive_cluster_shape_iterator rci (clusters, layer_id, ci, cid); !rci.at_end (); ++rci) { + for (db::recursive_cluster_shape_iterator rci (m_net_clusters, layer_id, ci, cid); !rci.at_end (); ++rci) { n += rci->polygon_ref ().vertices (); } ep.reserve (n); size_t p = 0; - for (db::recursive_cluster_shape_iterator rci (clusters, layer_id, ci, cid); !rci.at_end (); ++rci) { + for (db::recursive_cluster_shape_iterator rci (m_net_clusters, layer_id, ci, cid); !rci.at_end (); ++rci) { ep.insert_with_trans (rci->polygon_ref (), rci.trans (), ++p); } @@ -1798,49 +1799,24 @@ compute_area_and_perimeter_of_net_shapes (const db::hier_clusters perimeter = ap_collector.perimeter (); } -namespace { - -class AntennaShapeGenerator - : public PolygonSink +db::Point +LayoutToNetlist::get_merged_shapes_of_net (db::cell_index_type ci, size_t cid, unsigned int layer_id, db::Shapes &shapes, db::properties_id_type prop_id) const { -public: - AntennaShapeGenerator (db::Layout *layout, db::Shapes &shapes, db::properties_id_type prop_id) - : PolygonSink (), mp_layout (layout), mp_shapes (&shapes), m_prop_id (prop_id) - { } - - virtual void put (const db::Polygon &polygon) - { - if (m_prop_id != 0) { - mp_shapes->insert (db::PolygonRefWithProperties (db::PolygonRef (polygon, mp_layout->shape_repository ()), m_prop_id)); - } else { - mp_shapes->insert (db::PolygonRef (polygon, mp_layout->shape_repository ())); - } - } - -private: - db::Layout *mp_layout; - db::Shapes *mp_shapes; - db::properties_id_type m_prop_id; -}; - -} + const db::Layout *layout = &dss ().const_layout (m_layout_index); -static db::Point -get_merged_shapes_of_net (const db::hier_clusters &clusters, db::cell_index_type ci, size_t cid, unsigned int layer_id, db::Layout *layout, db::Shapes &shapes, db::properties_id_type prop_id) -{ db::Point ref; bool any_ref = false; db::EdgeProcessor ep; // count vertices and reserve space size_t n = 0; - for (db::recursive_cluster_shape_iterator rci (clusters, layer_id, ci, cid); !rci.at_end (); ++rci) { + for (db::recursive_cluster_shape_iterator rci (m_net_clusters, layer_id, ci, cid); !rci.at_end (); ++rci) { n += rci->polygon_ref ().vertices (); } ep.reserve (n); size_t p = 0; - for (db::recursive_cluster_shape_iterator rci (clusters, layer_id, ci, cid); !rci.at_end (); ++rci) { + for (db::recursive_cluster_shape_iterator rci (m_net_clusters, layer_id, ci, cid); !rci.at_end (); ++rci) { db::PolygonRef pr = rci->polygon_ref (); db::PolygonRef::polygon_edge_iterator e = pr.begin_edge (); if (! e.at_end ()) { @@ -1854,7 +1830,7 @@ get_merged_shapes_of_net (const db::hier_clusters &clusters, db::c } } - db::AntennaShapeGenerator sg (layout, shapes, prop_id); + db::PolygonRefToShapesGenerator sg (const_cast (layout), &shapes, prop_id); db::PolygonGenerator pg (sg, false); db::SimpleMerge op; ep.process (pg, op); @@ -1968,7 +1944,7 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_a db::Polygon::area_type adiode_int = 0; db::Polygon::perimeter_type pdiode_int = 0; - compute_area_and_perimeter_of_net_shapes (m_net_clusters, *cid, *c, layer_of (*d->first), adiode_int, pdiode_int); + compute_area_and_perimeter_of_net_shapes (*cid, *c, layer_of (*d->first), adiode_int, pdiode_int); adiodes_int.push_back (adiode_int); @@ -1987,7 +1963,7 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_a db::Polygon::area_type agate_int = 0; db::Polygon::perimeter_type pgate_int = 0; - compute_area_and_perimeter_of_net_shapes (m_net_clusters, *cid, *c, layer_of (gate), agate_int, pgate_int); + compute_area_and_perimeter_of_net_shapes (*cid, *c, layer_of (gate), agate_int, pgate_int); double agate = 0.0; if (fabs (gate_area_factor) > 1e-6) { @@ -2002,7 +1978,7 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_a db::Polygon::area_type ametal_int = 0; db::Polygon::perimeter_type pmetal_int = 0; - compute_area_and_perimeter_of_net_shapes (m_net_clusters, *cid, *c, layer_of (metal), ametal_int, pmetal_int); + compute_area_and_perimeter_of_net_shapes (*cid, *c, layer_of (metal), ametal_int, pmetal_int); double ametal = 0.0; if (fabs (metal_area_factor) > 1e-6) { @@ -2041,7 +2017,7 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_a prop_id = db::properties_id (ps); } - db::Point ref = get_merged_shapes_of_net (m_net_clusters, *cid, *c, layer_of (metal), &ly, shapes, prop_id); + db::Point ref = get_merged_shapes_of_net (*cid, *c, layer_of (metal), shapes, prop_id); if (values) { @@ -2078,6 +2054,80 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_a return db::Region (new db::DeepRegion (dl)); } +db::Region +LayoutToNetlist::measure_net (const db::Region &primary, const std::map &secondary, const std::string &expression, const std::map &variables, double dbu) +{ + // TODO: that's basically too much .. we only need the clusters + if (! m_netlist_extracted) { + throw tl::Exception (tl::to_string (tr ("The netlist has not been extracted yet"))); + } + + db::Layout &ly = dss ().layout (m_layout_index); + + if (dbu < 0.0) { + dbu = ly.dbu (); + } + + db::MeasureNetEval eval (this, dbu); + + for (auto v = variables.begin (); v != variables.end (); ++v) { + eval.set_var (v->first, v->second); + } + + eval.set_primary_layer (layer_of (primary)); + for (auto s = secondary.begin (); s != secondary.end (); ++s) { + if (s->second) { + eval.set_secondary_layer (s->first, layer_of (*s->second)); + } + } + + eval.init (); + + tl::Extractor ex (expression.c_str ()); + tl::Expression compiled_expr; + eval.parse (compiled_expr, ex); + + db::DeepLayer dl (&dss (), m_layout_index, ly.insert_layer ()); + unsigned int primary_layer = layer_of (primary); + + for (db::Layout::bottom_up_const_iterator cid = ly.begin_bottom_up (); cid != ly.end_bottom_up (); ++cid) { + + const connected_clusters &clusters = m_net_clusters.clusters_per_cell (*cid); + if (clusters.empty ()) { + continue; + } + + for (connected_clusters::all_iterator c = clusters.begin_all (); ! c.at_end (); ++c) { + + if (! clusters.is_root (*c)) { + continue; + } + + // skip nets without shapes on primary layer + if (db::recursive_cluster_shape_iterator (m_net_clusters, primary_layer, *cid, *c).at_end ()) { + continue; + } + + try { + + eval.reset (*cid, *c); + compiled_expr.execute (); + + if (! eval.skip ()) { + db::Shapes &shapes = ly.cell (*cid).shapes (dl.layer ()); + get_merged_shapes_of_net (*cid, *c, primary_layer, shapes, db::properties_id (eval.prop_set_out ())); + } + + } catch (tl::Exception &ex) { + tl::warn << ex.msg (); + } + + } + + } + + return db::Region (new db::DeepRegion (dl)); +} void LayoutToNetlist::save (const std::string &path, bool short_format) { diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index 4b35c7914..ed88030de 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -1126,6 +1126,30 @@ class DB_PUBLIC LayoutToNetlist */ db::Region antenna_check (const db::Region &gate, double gate_area_factor, double gate_perimeter_factor, const db::Region &metal, double metal_area_factor, double metal_perimeter_factor, double ratio, const std::vector > &diodes = std::vector > (), Texts *values = 0); + /** + * @brief Runs a generic net measurement function + * + * This method accepts some primary layer, a number of secondary layers with names and an expression. + * + * It will look at nets connecting to shapes on the primary layer and execute the expression for each + * of those nets. After that it will copy the primary shapes of the net to the output with the properties + * placed by "put" attached to them. + * + * It is possible to skip primary shapes of a specific net by calling the "skip" function with a "true" + * value. + * + * The formulas may use the following functions: + * + * * "area": the area of all primary-layer shapes on the net in square um + * * "area(name)": the area of all secondary-layer shapes. 'name' is a symbol with the name given in the secondary-layer map + * * "perimeter": the perimeter of the primary-layer shapes on the net in um + * * "perimeter(name)": the perimeter of the secondary-layer shapes. 'name' is a symbol with the name given in the secondary-layer map + * * "put(name, value)": places the value as property 'name' on the output shapes + * * "skip(flag)": will skip the primary shapes of that net when called with a true value + * * "net": the Net object of the current net + */ + db::Region measure_net (const db::Region &primary, const std::map &secondary, const std::string &expression, const std::map &variables, double dbu = -1.0); + /** * @brief Saves the database to the given path * @@ -1170,6 +1194,16 @@ class DB_PUBLIC LayoutToNetlist m_make_soft_connection_diodes = f; } + /** + * @brief Utility: computes the area and perimeter of a net's shapes + */ + void compute_area_and_perimeter_of_net_shapes (db::cell_index_type ci, size_t cid, unsigned int layer_id, db::Polygon::area_type &area, db::Polygon::perimeter_type &perimeter) const; + + /** + * @brief Utility: computes the merged shapes of a net + */ + db::Point get_merged_shapes_of_net (db::cell_index_type ci, size_t cid, unsigned int layer_id, db::Shapes &shapes, db::properties_id_type prop_id) const; + private: // no copying LayoutToNetlist (const db::LayoutToNetlist &other); diff --git a/src/db/db/dbLayoutToNetlistFormatDefs.h b/src/db/db/dbLayoutToNetlistFormatDefs.h index 6c7f4f3fe..bea7dbd60 100644 --- a/src/db/db/dbLayoutToNetlistFormatDefs.h +++ b/src/db/db/dbLayoutToNetlistFormatDefs.h @@ -79,7 +79,10 @@ namespace db * circuit( [circuit-def]) - circuit (cell) [short key: X] * * [class]: - * class(