From a21957629610ee261e9d737c26fafe5944808661 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 16 Feb 2025 00:08:35 +0100 Subject: [PATCH] WIP: Region, Edges, EdgePairs and Texts filters can filter by property now, first implementation of Region property filter. --- src/db/db/dbAsIfFlatEdgePairs.cc | 2 +- src/db/db/dbAsIfFlatEdges.cc | 8 +- src/db/db/dbAsIfFlatRegion.cc | 12 +- src/db/db/dbAsIfFlatTexts.cc | 8 +- src/db/db/dbCompoundOperation.cc | 8 +- src/db/db/dbCompoundOperation.h | 13 +- src/db/db/dbDeepEdgePairs.cc | 4 +- src/db/db/dbDeepEdges.cc | 4 +- src/db/db/dbDeepRegion.cc | 8 +- src/db/db/dbDeepTexts.cc | 4 +- src/db/db/dbEdgePairFilters.cc | 12 +- src/db/db/dbEdgePairFilters.h | 8 +- src/db/db/dbEdgePairs.h | 2 +- src/db/db/dbEdgesDelegate.h | 4 +- src/db/db/dbEdgesUtils.cc | 4 +- src/db/db/dbEdgesUtils.h | 22 +-- src/db/db/dbFlatEdgePairs.cc | 2 +- src/db/db/dbFlatEdges.cc | 2 +- src/db/db/dbFlatRegion.cc | 2 +- src/db/db/dbFlatTexts.cc | 2 +- src/db/db/dbRegionDelegate.h | 8 +- src/db/db/dbRegionUtils.cc | 44 ++--- src/db/db/dbRegionUtils.h | 48 ++--- src/db/db/dbTexts.h | 2 +- src/db/db/dbTextsUtils.h | 4 +- src/db/db/gsiDeclDbEdgePairs.cc | 10 +- src/db/db/gsiDeclDbEdges.cc | 26 ++- src/db/db/gsiDeclDbNetlistDeviceExtractor.cc | 40 +++++ src/db/db/gsiDeclDbRegion.cc | 180 +++++++++++++++++-- src/db/db/gsiDeclDbTexts.cc | 10 +- src/db/unit_tests/dbEdgePairsTests.cc | 68 +++---- testdata/ruby/dbRegionTest.rb | 46 +++++ 32 files changed, 446 insertions(+), 171 deletions(-) diff --git a/src/db/db/dbAsIfFlatEdgePairs.cc b/src/db/db/dbAsIfFlatEdgePairs.cc index f442979c4..575353c66 100644 --- a/src/db/db/dbAsIfFlatEdgePairs.cc +++ b/src/db/db/dbAsIfFlatEdgePairs.cc @@ -233,7 +233,7 @@ AsIfFlatEdgePairs::filtered (const EdgePairFilterBase &filter) const std::unique_ptr new_edge_pairs (new FlatEdgePairs ()); for (EdgePairsIterator p (begin ()); ! p.at_end (); ++p) { - if (filter.selected (*p)) { + if (filter.selected (*p, p.prop_id ())) { db::properties_id_type prop_id = p.prop_id (); if (prop_id != 0) { new_edge_pairs->insert (db::EdgePairWithProperties (*p, prop_id)); diff --git a/src/db/db/dbAsIfFlatEdges.cc b/src/db/db/dbAsIfFlatEdges.cc index 13ee3b066..2ac09819a 100644 --- a/src/db/db/dbAsIfFlatEdges.cc +++ b/src/db/db/dbAsIfFlatEdges.cc @@ -711,8 +711,12 @@ AsIfFlatEdges::filtered (const EdgeFilterBase &filter) const std::unique_ptr new_region (new FlatEdges ()); for (EdgesIterator p (begin_merged ()); ! p.at_end (); ++p) { - if (filter.selected (*p)) { - new_region->insert (*p); + if (filter.selected (*p, p.prop_id ())) { + if (p.prop_id () != 0) { + new_region->insert (db::EdgeWithProperties (*p, p.prop_id ())); + } else { + new_region->insert (*p); + } } } diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index d69f280e3..b4de3b83f 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -167,7 +167,7 @@ AsIfFlatRegion::edges (const EdgeFilterBase *filter, const PolygonToEdgeProcesso proc->process (*p, heap); for (auto e = heap.begin (); e != heap.end (); ++e) { - if (! filter || filter->selected (*e)) { + if (! filter || filter->selected (*e, prop_id)) { if (prop_id != 0) { result->insert (db::EdgeWithProperties (*e, prop_id)); } else { @@ -179,7 +179,7 @@ AsIfFlatRegion::edges (const EdgeFilterBase *filter, const PolygonToEdgeProcesso } else { for (db::Polygon::polygon_edge_iterator e = p->begin_edge (); ! e.at_end (); ++e) { - if (! filter || filter->selected (*e)) { + if (! filter || filter->selected (*e, prop_id)) { if (prop_id != 0) { result->insert (db::EdgeWithProperties (*e, prop_id)); } else { @@ -420,8 +420,12 @@ AsIfFlatRegion::filtered (const PolygonFilterBase &filter) const std::unique_ptr new_region (new FlatRegion ()); for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p) { - if (filter.selected (*p)) { - new_region->insert (*p); + if (filter.selected (*p, p.prop_id ())) { + if (p.prop_id () != 0) { + new_region->insert (db::PolygonWithProperties (*p, p.prop_id ())); + } else { + new_region->insert (*p); + } } } diff --git a/src/db/db/dbAsIfFlatTexts.cc b/src/db/db/dbAsIfFlatTexts.cc index de06092f0..e13c4ad8d 100644 --- a/src/db/db/dbAsIfFlatTexts.cc +++ b/src/db/db/dbAsIfFlatTexts.cc @@ -159,8 +159,12 @@ AsIfFlatTexts::filtered (const TextFilterBase &filter) const std::unique_ptr new_texts (new FlatTexts ()); for (TextsIterator p (begin ()); ! p.at_end (); ++p) { - if (filter.selected (*p)) { - new_texts->insert (*p); + if (filter.selected (*p, p.prop_id ())) { + if (p.prop_id () != 0) { + new_texts->insert (db::TextWithProperties (*p, p.prop_id ())); + } else { + new_texts->insert (*p); + } } } diff --git a/src/db/db/dbCompoundOperation.cc b/src/db/db/dbCompoundOperation.cc index 6cb08a68f..cd9f8dcad 100644 --- a/src/db/db/dbCompoundOperation.cc +++ b/src/db/db/dbCompoundOperation.cc @@ -1260,7 +1260,13 @@ CompoundRegionEdgePairFilterOperationNode::do_compute_local (CompoundRegionOpera bool CompoundRegionEdgePairFilterOperationNode::is_selected (const db::EdgePair &p) const { - return mp_filter->selected (p); + return mp_filter->selected (p, db::properties_id_type (0)); +} + +bool +CompoundRegionEdgePairFilterOperationNode::is_selected (const db::EdgePairWithProperties &p) const +{ + return mp_filter->selected (p, p.properties_id ()); } // --------------------------------------------------------------------------------------------- diff --git a/src/db/db/dbCompoundOperation.h b/src/db/db/dbCompoundOperation.h index 23f74b33e..ca42cf77e 100644 --- a/src/db/db/dbCompoundOperation.h +++ b/src/db/db/dbCompoundOperation.h @@ -1015,14 +1015,12 @@ private: child (0)->compute_local (cache, layout, cell, interactions, one, proc); if (m_sum_of_set) { - std::unordered_set wo_props; - wo_props.insert (one.front ().begin (), one.front ().end ()); - if (mp_filter->selected_set (wo_props)) { + if (mp_filter->selected_set (one.front ())) { results.front ().insert (one.front ().begin (), one.front ().end ()); } } else { for (typename std::unordered_set >::const_iterator p = one.front ().begin (); p != one.front ().end (); ++p) { - if (mp_filter->selected (*p)) { + if (mp_filter->selected (*p, p->properties_id ())) { results.front ().insert (*p); } } @@ -1066,14 +1064,12 @@ private: child (0)->compute_local (cache, layout, cell, interactions, one, proc); if (m_sum_of) { - std::unordered_set wo_props; - wo_props.insert (one.front ().begin (), one.front ().end ()); - if (mp_filter->selected (wo_props)) { + if (mp_filter->selected (one.front ())) { results.front ().insert (one.front ().begin (), one.front ().end ()); } } else { for (typename std::unordered_set::const_iterator p = one.front ().begin (); p != one.front ().end (); ++p) { - if (mp_filter->selected (*p)) { + if (mp_filter->selected (*p, p->properties_id ())) { results.front ().insert (*p); } } @@ -1108,6 +1104,7 @@ private: bool m_owns_filter; bool is_selected (const db::EdgePair &p) const; + bool is_selected (const db::EdgePairWithProperties &p) const; template void implement_compute_local (db::CompoundRegionOperationCache *cache, db::Layout *layout, db::Cell *cell, const shape_interactions &interactions, std::vector > &results, const db::LocalProcessorBase *proc) const diff --git a/src/db/db/dbDeepEdgePairs.cc b/src/db/db/dbDeepEdgePairs.cc index f973dc4eb..56907fe0d 100644 --- a/src/db/db/dbDeepEdgePairs.cc +++ b/src/db/db/dbDeepEdgePairs.cc @@ -423,7 +423,7 @@ DeepEdgePairs::apply_filter (const EdgePairFilterBase &filter) const const db::ICplxTrans &tr = *v; for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::EdgePairs); ! si.at_end (); ++si) { - if (filter.selected (si->edge_pair ().transformed (tr))) { + if (filter.selected (si->edge_pair ().transformed (tr), si->prop_id ())) { st->insert (*si); } } @@ -435,7 +435,7 @@ DeepEdgePairs::apply_filter (const EdgePairFilterBase &filter) const db::Shapes &st = c->shapes (res->deep_layer ().layer ()); for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::EdgePairs); ! si.at_end (); ++si) { - if (filter.selected (si->edge_pair ())) { + if (filter.selected (si->edge_pair (), si->prop_id ())) { st.insert (*si); } } diff --git a/src/db/db/dbDeepEdges.cc b/src/db/db/dbDeepEdges.cc index 98a73b2eb..6ef0aaf54 100644 --- a/src/db/db/dbDeepEdges.cc +++ b/src/db/db/dbDeepEdges.cc @@ -848,7 +848,7 @@ DeepEdges::apply_filter (const EdgeFilterBase &filter) const } for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Edges); ! si.at_end (); ++si) { - if (filter.selected (si->edge ().transformed (*v))) { + if (filter.selected (si->edge ().transformed (*v), si->prop_id ())) { st->insert (*si); } } @@ -860,7 +860,7 @@ DeepEdges::apply_filter (const EdgeFilterBase &filter) const db::Shapes &st = c->shapes (res->deep_layer ().layer ()); for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Edges); ! si.at_end (); ++si) { - if (filter.selected (si->edge ())) { + if (filter.selected (si->edge (), si->prop_id ())) { st.insert (*si); } } diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index f9b985944..458cb8a3d 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -1511,7 +1511,7 @@ 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))) { + if (! filter || filter->selected ((*e).transformed (tr), si->prop_id ())) { st.insert (db::EdgeWithProperties (*e, si->prop_id ())); } } @@ -1519,7 +1519,7 @@ DeepRegion::edges (const EdgeFilterBase *filter, const PolygonToEdgeProcessorBas } else { for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); ! e.at_end (); ++e) { - if (! filter || filter->selected ((*e).transformed (tr))) { + if (! filter || filter->selected ((*e).transformed (tr), si->prop_id ())) { st.insert (db::EdgeWithProperties (*e, si->prop_id ())); } } @@ -1641,7 +1641,7 @@ DeepRegion::apply_filter (const PolygonFilterBase &filter) const for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) { db::Polygon poly; si->polygon (poly); - if (filter.selected (poly.transformed (*v))) { + if (filter.selected (poly.transformed (*v), si->prop_id ())) { st->insert (*si); } } @@ -1655,7 +1655,7 @@ DeepRegion::apply_filter (const PolygonFilterBase &filter) const for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::All); ! si.at_end (); ++si) { db::Polygon poly; si->polygon (poly); - if (filter.selected (poly)) { + if (filter.selected (poly, si->prop_id ())) { st.insert (*si); } } diff --git a/src/db/db/dbDeepTexts.cc b/src/db/db/dbDeepTexts.cc index 5efd7f080..92afeae82 100644 --- a/src/db/db/dbDeepTexts.cc +++ b/src/db/db/dbDeepTexts.cc @@ -442,7 +442,7 @@ DeepTexts *DeepTexts::apply_filter (const TextFilterBase &filter) const for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Texts); ! si.at_end (); ++si) { db::Text text; si->text (text); - if (filter.selected (text.transformed (*v))) { + if (filter.selected (text.transformed (*v), si->prop_id ())) { st->insert (*si); } } @@ -456,7 +456,7 @@ DeepTexts *DeepTexts::apply_filter (const TextFilterBase &filter) const for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Texts); ! si.at_end (); ++si) { db::Text text; si->text (text); - if (filter.selected (text)) { + if (filter.selected (text, si->prop_id ())) { st.insert (*si); } } diff --git a/src/db/db/dbEdgePairFilters.cc b/src/db/db/dbEdgePairFilters.cc index f4abbf7e4..d876afc2a 100644 --- a/src/db/db/dbEdgePairFilters.cc +++ b/src/db/db/dbEdgePairFilters.cc @@ -43,12 +43,12 @@ EdgeFilterBasedEdgePairFilter::~EdgeFilterBasedEdgePairFilter () // .. nothing yet .. } -bool EdgeFilterBasedEdgePairFilter::selected (const db::EdgePair &edge_pair) const +bool EdgeFilterBasedEdgePairFilter::selected (const db::EdgePair &edge_pair, db::properties_id_type prop_id) const { if (m_one_must_match) { - return mp_edge_filter->selected (edge_pair.first ()) || mp_edge_filter->selected (edge_pair.second ()); + return mp_edge_filter->selected (edge_pair.first (), prop_id) || mp_edge_filter->selected (edge_pair.second (), prop_id); } else { - return mp_edge_filter->selected (edge_pair.first ()) && mp_edge_filter->selected (edge_pair.second ()); + return mp_edge_filter->selected (edge_pair.first (), prop_id) && mp_edge_filter->selected (edge_pair.second (), prop_id); } } @@ -71,7 +71,7 @@ EdgePairFilterByDistance::EdgePairFilterByDistance (distance_type min_distance, // .. nothing yet .. } -bool EdgePairFilterByDistance::selected (const db::EdgePair &edge_pair) const +bool EdgePairFilterByDistance::selected (const db::EdgePair &edge_pair, db::properties_id_type) const { distance_type dist = edge_pair.distance (); bool sel = (dist >= m_min_distance && dist < m_max_distance); @@ -87,7 +87,7 @@ EdgePairFilterByArea::EdgePairFilterByArea (area_type min_area, area_type max_ar // .. nothing yet .. } -bool EdgePairFilterByArea::selected (const db::EdgePair &edge_pair) const +bool EdgePairFilterByArea::selected (const db::EdgePair &edge_pair, db::properties_id_type) const { area_type dist = edge_pair.to_simple_polygon (0).area (); bool sel = (dist >= m_min_area && dist < m_max_area); @@ -110,7 +110,7 @@ InternalAngleEdgePairFilter::InternalAngleEdgePairFilter (double amin, bool incl } bool -InternalAngleEdgePairFilter::selected (const db::EdgePair &edge_pair) const +InternalAngleEdgePairFilter::selected (const db::EdgePair &edge_pair, db::properties_id_type) const { db::Vector d1 = edge_pair.first ().d (); db::Vector d2 = edge_pair.second ().d (); diff --git a/src/db/db/dbEdgePairFilters.h b/src/db/db/dbEdgePairFilters.h index 60737fd1a..d721f618a 100644 --- a/src/db/db/dbEdgePairFilters.h +++ b/src/db/db/dbEdgePairFilters.h @@ -47,7 +47,7 @@ public: EdgeFilterBasedEdgePairFilter (EdgeFilterBase *edge_filter, bool one_must_match); virtual ~EdgeFilterBasedEdgePairFilter (); - virtual bool selected (const db::EdgePair &edge_pair) const; + virtual bool selected (const db::EdgePair &edge_pair, properties_id_type prop_id) const; virtual const TransformationReducer *vars () const; virtual bool wants_variants () const; @@ -69,7 +69,7 @@ public: EdgePairFilterByDistance (distance_type min_distance, distance_type max_distance, bool inverted); - virtual bool selected (const db::EdgePair &edge_pair) const; + virtual bool selected (const db::EdgePair &edge_pair, properties_id_type) const; virtual const TransformationReducer *vars () const { return &m_vars; } virtual bool wants_variants () const { return true; } @@ -92,7 +92,7 @@ public: EdgePairFilterByArea (area_type min_area, area_type max_area, bool inverted); - virtual bool selected (const db::EdgePair &edge_pair) const; + virtual bool selected (const db::EdgePair &edge_pair, properties_id_type) const; virtual const TransformationReducer *vars () const { return &m_vars; } virtual bool wants_variants () const { return true; } @@ -114,7 +114,7 @@ public: InternalAngleEdgePairFilter (double a, bool inverted); InternalAngleEdgePairFilter (double amin, bool include_amin, double amax, bool include_amax, bool inverted); - virtual bool selected (const db::EdgePair &edge_pair) const; + virtual bool selected (const db::EdgePair &edge_pair, properties_id_type) const; virtual const TransformationReducer *vars () const { return 0; } virtual bool wants_variants () const { return false; } diff --git a/src/db/db/dbEdgePairs.h b/src/db/db/dbEdgePairs.h index 0917813aa..aedf2c36d 100644 --- a/src/db/db/dbEdgePairs.h +++ b/src/db/db/dbEdgePairs.h @@ -58,7 +58,7 @@ public: EdgePairFilterBase () { } virtual ~EdgePairFilterBase () { } - virtual bool selected (const db::EdgePair &edge_pair) const = 0; + virtual bool selected (const db::EdgePair &edge_pair, db::properties_id_type prop_id) const = 0; virtual const TransformationReducer *vars () const = 0; virtual bool wants_variants () const = 0; }; diff --git a/src/db/db/dbEdgesDelegate.h b/src/db/db/dbEdgesDelegate.h index 0c4b0c387..f3e8cab77 100644 --- a/src/db/db/dbEdgesDelegate.h +++ b/src/db/db/dbEdgesDelegate.h @@ -56,13 +56,13 @@ public: * @brief Filters the edge * If this method returns true, the edge is kept. Otherwise it's discarded. */ - virtual bool selected (const db::Edge &edge) const = 0; + virtual bool selected (const db::Edge &edge, db::properties_id_type prop_id) const = 0; /** * @brief Filters the edge set * If this method returns true, the edges are kept. Otherwise they are discarded. */ - virtual bool selected (const std::unordered_set &edge) const = 0; + virtual bool selected (const std::unordered_set &edge) const = 0; /** * @brief Returns the transformation reducer for building cell variants diff --git a/src/db/db/dbEdgesUtils.cc b/src/db/db/dbEdgesUtils.cc index 6d60b4d77..15dcb5a1b 100644 --- a/src/db/db/dbEdgesUtils.cc +++ b/src/db/db/dbEdgesUtils.cc @@ -304,7 +304,7 @@ EdgeOrientationFilter::EdgeOrientationFilter (double a, bool inverse, bool absol } bool -EdgeOrientationFilter::selected (const db::Edge &edge) const +EdgeOrientationFilter::selected (const db::Edge &edge, db::properties_id_type) const { // NOTE: this edge normalization confines the angle to a range between (-90 .. 90] (-90 excluded). // A horizontal edge has 0 degree, a vertical one has 90 degree. @@ -342,7 +342,7 @@ static EdgeAngleChecker s_orthodiagonal_checkers [] = { }; bool -SpecialEdgeOrientationFilter::selected (const db::Edge &edge) const +SpecialEdgeOrientationFilter::selected (const db::Edge &edge, properties_id_type) const { const EdgeAngleChecker *eb, *ee; diff --git a/src/db/db/dbEdgesUtils.h b/src/db/db/dbEdgesUtils.h index c2f987278..8daa404e8 100644 --- a/src/db/db/dbEdgesUtils.h +++ b/src/db/db/dbEdgesUtils.h @@ -71,7 +71,7 @@ struct DB_PUBLIC EdgeLengthFilter /** * @brief Returns true if the edge length matches the criterion */ - virtual bool selected (const db::Edge &edge) const + virtual bool selected (const db::Edge &edge, db::properties_id_type) const { return check (edge.length ()); } @@ -79,10 +79,10 @@ struct DB_PUBLIC EdgeLengthFilter /** * @brief Returns true if the total edge length matches the criterion */ - bool selected (const std::unordered_set &edges) const + bool selected (const std::unordered_set &edges) const { length_type l = 0; - for (std::unordered_set::const_iterator e = edges.begin (); e != edges.end (); ++e) { + for (std::unordered_set::const_iterator e = edges.begin (); e != edges.end (); ++e) { l += e->length (); } return check (l); @@ -204,15 +204,15 @@ struct DB_PUBLIC EdgeOrientationFilter /** * @brief Returns true if the edge orientation matches the criterion */ - virtual bool selected (const db::Edge &edge) const; + virtual bool selected (const db::Edge &edge, properties_id_type) const; /** * @brief Returns true if all edge orientations match the criterion */ - virtual bool selected (const std::unordered_set &edges) const + virtual bool selected (const std::unordered_set &edges) const { - for (std::unordered_set::const_iterator e = edges.begin (); e != edges.end (); ++e) { - if (! selected (*e)) { + for (std::unordered_set::const_iterator e = edges.begin (); e != edges.end (); ++e) { + if (! selected (*e, e->properties_id ())) { return false; } } @@ -274,15 +274,15 @@ struct DB_PUBLIC SpecialEdgeOrientationFilter /** * @brief Returns true if the edge orientation matches the criterion */ - virtual bool selected (const db::Edge &edge) const; + virtual bool selected (const db::Edge &edge, db::properties_id_type) const; /** * @brief Returns true if all edge orientations match the criterion */ - virtual bool selected (const std::unordered_set &edges) const + virtual bool selected (const std::unordered_set &edges) const { - for (std::unordered_set::const_iterator e = edges.begin (); e != edges.end (); ++e) { - if (! selected (*e)) { + for (std::unordered_set::const_iterator e = edges.begin (); e != edges.end (); ++e) { + if (! selected (*e, e->properties_id ())) { return false; } } diff --git a/src/db/db/dbFlatEdgePairs.cc b/src/db/db/dbFlatEdgePairs.cc index e6b9808ac..cb554a3ea 100644 --- a/src/db/db/dbFlatEdgePairs.cc +++ b/src/db/db/dbFlatEdgePairs.cc @@ -103,7 +103,7 @@ FlatEdgePairs::filter_in_place (const EdgePairFilterBase &filter) edge_pair_iterator_type pw = ep.get_layer ().begin (); for (EdgePairsIterator p (begin ()); ! p.at_end (); ++p) { - if (filter.selected (*p)) { + if (filter.selected (*p, p.prop_id ())) { if (pw == ep.get_layer ().end ()) { ep.get_layer ().insert (*p); pw = ep.get_layer ().end (); diff --git a/src/db/db/dbFlatEdges.cc b/src/db/db/dbFlatEdges.cc index fb0e6c507..44299bc8c 100644 --- a/src/db/db/dbFlatEdges.cc +++ b/src/db/db/dbFlatEdges.cc @@ -276,7 +276,7 @@ FlatEdges::filter_in_place (const EdgeFilterBase &filter) edge_iterator_wp_type pw_wp = e.get_layer ().begin (); for (EdgesIterator p (begin_merged ()); ! p.at_end (); ++p) { - if (filter.selected (*p)) { + if (filter.selected (*p, p.prop_id ())) { if (p.prop_id () != 0) { if (pw_wp == e.get_layer ().end ()) { e.get_layer ().insert (db::EdgeWithProperties (*p, p.prop_id ())); diff --git a/src/db/db/dbFlatRegion.cc b/src/db/db/dbFlatRegion.cc index ae4cf1b8b..f6abd1696 100644 --- a/src/db/db/dbFlatRegion.cc +++ b/src/db/db/dbFlatRegion.cc @@ -184,7 +184,7 @@ RegionDelegate *FlatRegion::filter_in_place (const PolygonFilterBase &filter) polygon_iterator_wp_type pw_wp = poly_layer_wp.begin (); for (RegionIterator p (filter.requires_raw_input () ? begin () : begin_merged ()); ! p.at_end (); ++p) { - if (filter.selected (*p)) { + if (filter.selected (*p, p.prop_id ())) { if (p.prop_id () != 0) { if (pw_wp == poly_layer_wp.end ()) { poly_layer_wp.insert (db::PolygonWithProperties (*p, p.prop_id ())); diff --git a/src/db/db/dbFlatTexts.cc b/src/db/db/dbFlatTexts.cc index 8f05ae5db..e2e0e54a2 100644 --- a/src/db/db/dbFlatTexts.cc +++ b/src/db/db/dbFlatTexts.cc @@ -101,7 +101,7 @@ FlatTexts::filter_in_place (const TextFilterBase &filter) text_iterator_type pw = texts.get_layer ().begin (); for (TextsIterator p (begin ()); ! p.at_end (); ++p) { - if (filter.selected (*p)) { + if (filter.selected (*p, p.prop_id ())) { if (pw == texts.get_layer ().end ()) { texts.get_layer ().insert (*p); pw = texts.get_layer ().end (); diff --git a/src/db/db/dbRegionDelegate.h b/src/db/db/dbRegionDelegate.h index 252d2df9b..44aa918f8 100644 --- a/src/db/db/dbRegionDelegate.h +++ b/src/db/db/dbRegionDelegate.h @@ -68,25 +68,25 @@ public: * @brief Filters the polygon * If this method returns true, the polygon is kept. Otherwise it's discarded. */ - virtual bool selected (const db::Polygon &polygon) const = 0; + virtual bool selected (const db::Polygon &polygon, db::properties_id_type prop_id) const = 0; /** * @brief Filters the polygon reference * If this method returns true, the polygon is kept. Otherwise it's discarded. */ - virtual bool selected (const db::PolygonRef &polygon) const = 0; + virtual bool selected (const db::PolygonRef &polygon, db::properties_id_type prop_id) const = 0; /** * @brief Filters the set of polygons (taking the overall properties) * If this method returns true, the polygon is kept. Otherwise it's discarded. */ - virtual bool selected_set (const std::unordered_set &polygons) const = 0; + virtual bool selected_set (const std::unordered_set &polygons) const = 0; /** * @brief Filters the set of polygon references (taking the overall properties) * If this method returns true, the polygon is kept. Otherwise it's discarded. */ - virtual bool selected_set (const std::unordered_set &polygons) const = 0; + virtual bool selected_set (const std::unordered_set &polygons) const = 0; /** * @brief Returns the transformation reducer for building cell variants diff --git a/src/db/db/dbRegionUtils.cc b/src/db/db/dbRegionUtils.cc index ec6b6b7a5..925bd314f 100644 --- a/src/db/db/dbRegionUtils.cc +++ b/src/db/db/dbRegionUtils.cc @@ -48,29 +48,29 @@ bool RegionPerimeterFilter::check (perimeter_type p) const } } -bool RegionPerimeterFilter::selected (const db::Polygon &poly) const +bool RegionPerimeterFilter::selected (const db::Polygon &poly, db::properties_id_type) const { return check (poly.perimeter ()); } -bool RegionPerimeterFilter::selected (const db::PolygonRef &poly) const +bool RegionPerimeterFilter::selected (const db::PolygonRef &poly, db::properties_id_type) const { return check (poly.perimeter ()); } -bool RegionPerimeterFilter::selected_set (const std::unordered_set &poly) const +bool RegionPerimeterFilter::selected_set (const std::unordered_set &poly) const { perimeter_type ps = 0; - for (std::unordered_set::const_iterator p = poly.begin (); p != poly.end (); ++p) { + for (std::unordered_set::const_iterator p = poly.begin (); p != poly.end (); ++p) { ps += p->perimeter (); } return check (ps); } -bool RegionPerimeterFilter::selected_set (const std::unordered_set &poly) const +bool RegionPerimeterFilter::selected_set (const std::unordered_set &poly) const { perimeter_type ps = 0; - for (std::unordered_set::const_iterator p = poly.begin (); p != poly.end (); ++p) { + for (std::unordered_set::const_iterator p = poly.begin (); p != poly.end (); ++p) { ps += p->perimeter (); } return check (ps); @@ -99,29 +99,29 @@ bool RegionAreaFilter::check (area_type a) const } } -bool RegionAreaFilter::selected (const db::Polygon &poly) const +bool RegionAreaFilter::selected (const db::Polygon &poly, db::properties_id_type) const { return check (poly.area ()); } -bool RegionAreaFilter::selected (const db::PolygonRef &poly) const +bool RegionAreaFilter::selected (const db::PolygonRef &poly, properties_id_type) const { return check (poly.area ()); } -bool RegionAreaFilter::selected_set (const std::unordered_set &poly) const +bool RegionAreaFilter::selected_set (const std::unordered_set &poly) const { area_type as = 0; - for (std::unordered_set::const_iterator p = poly.begin (); p != poly.end (); ++p) { + for (std::unordered_set::const_iterator p = poly.begin (); p != poly.end (); ++p) { as += p->area (); } return check (as); } -bool RegionAreaFilter::selected_set (const std::unordered_set &poly) const +bool RegionAreaFilter::selected_set (const std::unordered_set &poly) const { area_type as = 0; - for (std::unordered_set::const_iterator p = poly.begin (); p != poly.end (); ++p) { + for (std::unordered_set::const_iterator p = poly.begin (); p != poly.end (); ++p) { as += p->area (); } return check (as); @@ -143,13 +143,13 @@ RectilinearFilter::RectilinearFilter (bool inverse) } bool -RectilinearFilter::selected (const db::Polygon &poly) const +RectilinearFilter::selected (const db::Polygon &poly, db::properties_id_type) const { return poly.is_rectilinear () != m_inverse; } bool -RectilinearFilter::selected (const db::PolygonRef &poly) const +RectilinearFilter::selected (const db::PolygonRef &poly, db::properties_id_type) const { return poly.is_rectilinear () != m_inverse; } @@ -170,14 +170,14 @@ HoleCountFilter::HoleCountFilter (size_t min_count, size_t max_count, bool inver } bool -HoleCountFilter::selected (const db::Polygon &poly) const +HoleCountFilter::selected (const db::Polygon &poly, db::properties_id_type) const { bool ok = poly.holes () < m_max_count && poly.holes () >= m_min_count; return ok != m_inverse; } bool -HoleCountFilter::selected (const db::PolygonRef &poly) const +HoleCountFilter::selected (const db::PolygonRef &poly, properties_id_type) const { bool ok = poly.obj ().holes () < m_max_count && poly.obj ().holes () >= m_min_count; return ok != m_inverse; @@ -198,7 +198,7 @@ RectangleFilter::RectangleFilter (bool is_square, bool inverse) } bool -RectangleFilter::selected (const db::Polygon &poly) const +RectangleFilter::selected (const db::Polygon &poly, properties_id_type) const { bool ok = poly.is_box (); if (ok && m_is_square) { @@ -209,7 +209,7 @@ RectangleFilter::selected (const db::Polygon &poly) const } bool -RectangleFilter::selected (const db::PolygonRef &poly) const +RectangleFilter::selected (const db::PolygonRef &poly, properties_id_type) const { bool ok = poly.is_box (); if (ok && m_is_square) { @@ -256,13 +256,13 @@ RegionBBoxFilter::check (const db::Box &box) const } bool -RegionBBoxFilter::selected (const db::Polygon &poly) const +RegionBBoxFilter::selected (const db::Polygon &poly, properties_id_type) const { return check (poly.box ()); } bool -RegionBBoxFilter::selected (const db::PolygonRef &poly) const +RegionBBoxFilter::selected (const db::PolygonRef &poly, properties_id_type) const { return check (poly.box ()); } @@ -322,7 +322,7 @@ static double compute_ratio_parameter (const P &poly, RegionRatioFilter::paramet return v; } -bool RegionRatioFilter::selected (const db::Polygon &poly) const +bool RegionRatioFilter::selected (const db::Polygon &poly, properties_id_type) const { double v = compute_ratio_parameter (poly, m_parameter); @@ -330,7 +330,7 @@ bool RegionRatioFilter::selected (const db::Polygon &poly) const return ok != m_inverse; } -bool RegionRatioFilter::selected (const db::PolygonRef &poly) const +bool RegionRatioFilter::selected (const db::PolygonRef &poly, properties_id_type) const { double v = compute_ratio_parameter (poly, m_parameter); diff --git a/src/db/db/dbRegionUtils.h b/src/db/db/dbRegionUtils.h index f637dcbde..49a0ac003 100644 --- a/src/db/db/dbRegionUtils.h +++ b/src/db/db/dbRegionUtils.h @@ -57,22 +57,22 @@ struct DB_PUBLIC RegionPerimeterFilter /** * @brief Returns true if the polygon's perimeter matches the criterion */ - virtual bool selected (const db::Polygon &poly) const; + virtual bool selected (const db::Polygon &poly, properties_id_type) const; /** * @brief Returns true if the polygon's perimeter matches the criterion */ - virtual bool selected (const db::PolygonRef &poly) const; + virtual bool selected (const db::PolygonRef &poly, properties_id_type) const; /** * @brief Returns true if the polygon's perimeter sum matches the criterion */ - virtual bool selected_set (const std::unordered_set &polygons) const; + virtual bool selected_set (const std::unordered_set &polygons) const; /** * @brief Returns true if the polygon's perimeter sum matches the criterion */ - virtual bool selected_set (const std::unordered_set &polygons) const; + virtual bool selected_set (const std::unordered_set &polygons) const; /** * @brief This filter is isotropic @@ -123,22 +123,22 @@ struct DB_PUBLIC RegionAreaFilter /** * @brief Returns true if the polygon's area matches the criterion */ - virtual bool selected (const db::Polygon &poly) const; + virtual bool selected (const db::Polygon &poly, properties_id_type) const; /** * @brief Returns true if the polygon's area matches the criterion */ - virtual bool selected (const db::PolygonRef &poly) const; + virtual bool selected (const db::PolygonRef &poly, properties_id_type) const; /** * @brief Returns true if the polygon's area sum matches the criterion */ - virtual bool selected_set (const std::unordered_set &polygons) const; + virtual bool selected_set (const std::unordered_set &polygons) const; /** * @brief Returns true if the polygon's area sum matches the criterion */ - virtual bool selected_set (const std::unordered_set &polygons) const; + virtual bool selected_set (const std::unordered_set &polygons) const; /** * @brief This filter is isotropic @@ -175,20 +175,20 @@ struct DB_PUBLIC AllMustMatchFilter */ AllMustMatchFilter () { } - virtual bool selected_set (const std::unordered_set &polygons) const + virtual bool selected_set (const std::unordered_set &polygons) const { - for (std::unordered_set::const_iterator p = polygons.begin (); p != polygons.end (); ++p) { - if (! selected (*p)) { + for (std::unordered_set::const_iterator p = polygons.begin (); p != polygons.end (); ++p) { + if (! selected (*p, p->properties_id ())) { return false; } } return true; } - virtual bool selected_set (const std::unordered_set &polygons) const + virtual bool selected_set (const std::unordered_set &polygons) const { - for (std::unordered_set::const_iterator p = polygons.begin (); p != polygons.end (); ++p) { - if (! selected (*p)) { + for (std::unordered_set::const_iterator p = polygons.begin (); p != polygons.end (); ++p) { + if (! selected (*p, p->properties_id ())) { return false; } } @@ -215,12 +215,12 @@ struct DB_PUBLIC RectilinearFilter /** * @brief Returns true if the polygon is rectilinear */ - virtual bool selected (const db::Polygon &poly) const; + virtual bool selected (const db::Polygon &poly, properties_id_type) const; /** * @brief Returns true if the polygon is rectilinear */ - virtual bool selected (const db::PolygonRef &poly) const; + virtual bool selected (const db::PolygonRef &poly, properties_id_type) const; /** * @brief This filter does not need variants @@ -259,12 +259,12 @@ struct DB_PUBLIC RectangleFilter /** * @brief Returns true if the polygon is a rectangle */ - virtual bool selected (const db::Polygon &poly) const; + virtual bool selected (const db::Polygon &poly, properties_id_type) const; /** * @brief Returns true if the polygon is a rectangle */ - virtual bool selected (const db::PolygonRef &poly) const; + virtual bool selected (const db::PolygonRef &poly, properties_id_type) const; /** * @brief This filter does not need variants @@ -304,12 +304,12 @@ struct DB_PUBLIC HoleCountFilter /** * @brief Returns true if the polygon is a rectangle */ - virtual bool selected (const db::Polygon &poly) const; + virtual bool selected (const db::Polygon &poly, properties_id_type) const; /** * @brief Returns true if the polygon is a rectangle */ - virtual bool selected (const db::PolygonRef &poly) const; + virtual bool selected (const db::PolygonRef &poly, properties_id_type) const; /** * @brief This filter does not need variants @@ -375,12 +375,12 @@ struct DB_PUBLIC RegionBBoxFilter /** * @brief Returns true if the polygon's bounding box matches the criterion */ - virtual bool selected (const db::Polygon &poly) const; + virtual bool selected (const db::Polygon &poly, properties_id_type) const; /** * @brief Returns true if the polygon's bounding box matches the criterion */ - virtual bool selected (const db::PolygonRef &poly) const; + virtual bool selected (const db::PolygonRef &poly, properties_id_type) const; /** * @brief This filter is isotropic unless the parameter is width or height @@ -444,12 +444,12 @@ struct DB_PUBLIC RegionRatioFilter /** * @brief Returns true if the polygon's area matches the criterion */ - virtual bool selected (const db::Polygon &poly) const; + virtual bool selected (const db::Polygon &poly, properties_id_type) const; /** * @brief Returns true if the polygon's area matches the criterion */ - virtual bool selected (const db::PolygonRef &poly) const; + virtual bool selected (const db::PolygonRef &poly, properties_id_type) const; /** * @brief This filter is isotropic unless the parameter is width or height diff --git a/src/db/db/dbTexts.h b/src/db/db/dbTexts.h index c16f30e36..e714377df 100644 --- a/src/db/db/dbTexts.h +++ b/src/db/db/dbTexts.h @@ -57,7 +57,7 @@ public: TextFilterBase () { } virtual ~TextFilterBase () { } - virtual bool selected (const db::Text &text) const = 0; + virtual bool selected (const db::Text &text, db::properties_id_type prop_id) const = 0; virtual const TransformationReducer *vars () const = 0; virtual bool wants_variants () const = 0; }; diff --git a/src/db/db/dbTextsUtils.h b/src/db/db/dbTextsUtils.h index a07fc1f52..f35d237a0 100644 --- a/src/db/db/dbTextsUtils.h +++ b/src/db/db/dbTextsUtils.h @@ -58,7 +58,7 @@ struct DB_PUBLIC TextStringFilter /** * @brief Returns true if the text matches the criterion */ - virtual bool selected (const db::Text &text) const + virtual bool selected (const db::Text &text, db::properties_id_type) const { return (text.string () == m_text) != m_inverse; } @@ -118,7 +118,7 @@ struct DB_PUBLIC TextPatternFilter /** * @brief Returns true if the text matches the criterion */ - virtual bool selected (const db::Text &text) const + virtual bool selected (const db::Text &text, db::properties_id_type) const { return m_pattern.match (text.string ()) != m_inverse; } diff --git a/src/db/db/gsiDeclDbEdgePairs.cc b/src/db/db/gsiDeclDbEdgePairs.cc index 3ac118dd5..aec39b3eb 100644 --- a/src/db/db/gsiDeclDbEdgePairs.cc +++ b/src/db/db/gsiDeclDbEdgePairs.cc @@ -45,17 +45,17 @@ class EdgePairFilterImpl public: EdgePairFilterImpl () { } - bool issue_selected (const db::EdgePair &) const + bool issue_selected (const db::EdgePairWithProperties &) const { return false; } - virtual bool selected (const db::EdgePair &edge_pair) const + virtual bool selected (const db::EdgePair &edge_pair, db::properties_id_type prop_id) const { if (f_selected.can_issue ()) { - return f_selected.issue (&EdgePairFilterImpl::issue_selected, edge_pair); + return f_selected.issue (&EdgePairFilterImpl::issue_selected, db::EdgePairWithProperties (edge_pair, prop_id)); } else { - return issue_selected (edge_pair); + return issue_selected (db::EdgePairWithProperties (edge_pair, prop_id)); } } @@ -73,6 +73,8 @@ Class decl_EdgePairFilterImpl ("db", "EdgePairFilter", "@brief Selects an edge pair\n" "This method is the actual payload. It needs to be reimplemented in a derived class.\n" "It needs to analyze the edge pair and return 'true' if it should be kept and 'false' if it should be discarded." + "\n" + "Since version 0.30, the edge pair carries properties." ), "@brief A generic edge pair filter adaptor\n" "\n" diff --git a/src/db/db/gsiDeclDbEdges.cc b/src/db/db/gsiDeclDbEdges.cc index 0d8f307ad..8339805b4 100644 --- a/src/db/db/gsiDeclDbEdges.cc +++ b/src/db/db/gsiDeclDbEdges.cc @@ -46,26 +46,34 @@ class EdgeFilterImpl public: EdgeFilterImpl () { } - bool issue_selected (const db::Edge &) const + bool issue_selected (const db::EdgeWithProperties &) const { return false; } - virtual bool selected (const db::Edge &edge) const + virtual bool selected (const db::Edge &edge, db::properties_id_type prop_id) const { if (f_selected.can_issue ()) { - return f_selected.issue (&EdgeFilterImpl::issue_selected, edge); + return f_selected.issue (&EdgeFilterImpl::issue_selected, db::EdgeWithProperties (edge, prop_id)); } else { - return issue_selected (edge); + return issue_selected (db::EdgeWithProperties (edge, prop_id)); } } // Returns true if all edges match the criterion - virtual bool selected (const std::unordered_set &edges) const + virtual bool selected (const std::unordered_set &edges) const { - for (std::unordered_set::const_iterator e = edges.begin (); e != edges.end (); ++e) { - if (! selected (*e)) { - return false; + if (f_selected.can_issue ()) { + for (std::unordered_set::const_iterator e = edges.begin (); e != edges.end (); ++e) { + if (! f_selected.issue (&EdgeFilterImpl::issue_selected, *e)) { + return false; + } + } + } else { + for (std::unordered_set::const_iterator e = edges.begin (); e != edges.end (); ++e) { + if (! issue_selected (*e)) { + return false; + } } } return true; @@ -85,6 +93,8 @@ Class decl_EdgeFilterImpl ("db", "EdgeFilter", "@brief Selects an edge\n" "This method is the actual payload. It needs to be reimplemented in a derived class.\n" "It needs to analyze the edge and return 'true' if it should be kept and 'false' if it should be discarded." + "\n" + "Since version 0.30, the edge carries properties." ), "@brief A generic edge filter adaptor\n" "\n" diff --git a/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc b/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc index 47087b104..454d1aaa5 100644 --- a/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc +++ b/src/db/db/gsiDeclDbNetlistDeviceExtractor.cc @@ -263,6 +263,26 @@ define_terminal_by_names (GenericDeviceExtractor *extractor, db::Device *device, extractor->define_terminal (device, terminal_id, layer_id, shape); } +static void error1 (GenericDeviceExtractor *ext, const std::string &message, const db::DPolygonWithProperties &poly) +{ + ext->error (message, poly); +} + +static void error2 (GenericDeviceExtractor *ext, const std::string &message, const db::PolygonWithProperties &poly) +{ + ext->error (message, poly); +} + +static void warn1 (GenericDeviceExtractor *ext, const std::string &message, const db::DPolygonWithProperties &poly) +{ + ext->warn (message, poly); +} + +static void warn2 (GenericDeviceExtractor *ext, const std::string &message, const db::PolygonWithProperties &poly) +{ + ext->warn (message, poly); +} + Class decl_GenericDeviceExtractor (decl_dbNetlistDeviceExtractor, "db", "GenericDeviceExtractor", gsi::callback ("setup", &GenericDeviceExtractor::setup, &GenericDeviceExtractor::cb_setup, "@brief Sets up the extractor.\n" @@ -397,10 +417,20 @@ Class decl_GenericDeviceExtractor (decl_dbNetlistDeviceE gsi::arg ("message"), gsi::arg ("geometry"), "@brief Issues an error with the given message and micrometer-units polygon geometry\n" ) + + gsi::method_ext ("error", &error1, + gsi::arg ("message"), gsi::arg ("geometry"), + "@brief Issues an error with the given message and micrometer-units polygon geometry with properties\n" + "This flavor has been introduced in version 0.30." + ) + gsi::method ("error", (void (GenericDeviceExtractor::*) (const std::string &, const db::Polygon &)) &GenericDeviceExtractor::error, gsi::arg ("message"), gsi::arg ("geometry"), "@brief Issues an error with the given message and database-unit polygon geometry\n" ) + + gsi::method_ext ("error", &error2, + gsi::arg ("message"), gsi::arg ("geometry"), + "@brief Issues an error with the given message and database-units polygon geometry with properties\n" + "This flavor has been introduced in version 0.30." + ) + gsi::method ("error", (void (GenericDeviceExtractor::*) (const std::string &, const std::string &, const std::string &)) &GenericDeviceExtractor::error, gsi::arg ("category_name"), gsi::arg ("category_description"), gsi::arg ("message"), "@brief Issues an error with the given category name and description, message\n" @@ -423,11 +453,21 @@ Class decl_GenericDeviceExtractor (decl_dbNetlistDeviceE "@brief Issues a warning with the given message and micrometer-units polygon geometry\n" "Warnings have been introduced in version 0.28.13." ) + + gsi::method_ext ("warn", &warn1, + gsi::arg ("message"), gsi::arg ("geometry"), + "@brief Issues a warning with the given message and micrometer-units polygon geometry with properties\n" + "This flavor has been introduced in version 0.30." + ) + gsi::method ("warn", (void (GenericDeviceExtractor::*) (const std::string &, const db::Polygon &)) &GenericDeviceExtractor::warn, gsi::arg ("message"), gsi::arg ("geometry"), "@brief Issues a warning with the given message and database-unit polygon geometry\n" "Warnings have been introduced in version 0.28.13." ) + + gsi::method_ext ("warn", &warn2, + gsi::arg ("message"), gsi::arg ("geometry"), + "@brief Issues a warning with the given message and database-unit polygon geometry\n" + "This flavor has been introduced in version 0.30." + ) + gsi::method ("warn", (void (GenericDeviceExtractor::*) (const std::string &, const std::string &, const std::string &)) &GenericDeviceExtractor::warn, gsi::arg ("category_name"), gsi::arg ("category_description"), gsi::arg ("message"), "@brief Issues a warning with the given category name and description, message\n" diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index b3cb7bcff..b01ffd261 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -36,6 +36,7 @@ #include "dbRegionProcessors.h" #include "dbCompoundOperation.h" #include "dbLayoutToNetlist.h" +#include "dbPropertiesRepository.h" #include "tlGlobPattern.h" #include "gsiDeclDbContainerHelpers.h" @@ -50,31 +51,38 @@ namespace gsi // --------------------------------------------------------------------------------- // PolygonFilter binding -class PolygonFilterImpl +class PolygonFilterBase : public shape_filter_impl { +public: + PolygonFilterBase () { } +}; + +class PolygonFilterImpl + : public PolygonFilterBase +{ public: PolygonFilterImpl () { } - bool issue_selected (const db::Polygon &) const + bool issue_selected (const db::PolygonWithProperties &) const { return false; } - virtual bool selected (const db::Polygon &polygon) const + virtual bool selected (const db::Polygon &polygon, db::properties_id_type prop_id) const { if (f_selected.can_issue ()) { - return f_selected.issue (&PolygonFilterImpl::issue_selected, polygon); + return f_selected.issue (&PolygonFilterImpl::issue_selected, db::PolygonWithProperties (polygon, prop_id)); } else { return issue_selected (polygon); } } - virtual bool selected (const db::PolygonRef &polygon) const + virtual bool selected (const db::PolygonRef &polygon, db::properties_id_type prop_id) const { db::Polygon p; polygon.instantiate (p); - return selected (p); + return selected (p, prop_id); } gsi::Callback f_selected; @@ -85,12 +93,164 @@ private: PolygonFilterImpl (const PolygonFilterImpl &); }; -Class decl_PolygonFilterImpl ("db", "PolygonFilter", +/** + * @brief A properties filter + */ +class PropertiesFilter +{ +public: + PropertiesFilter (const tl::Variant &name, const tl::Variant &value, bool inverse) + : m_name_id (db::property_names_id (name)), m_value_from (value), m_exact (true), m_glob (false), m_inverse (inverse) + { + // .. nothing yet .. + } + + PropertiesFilter (const tl::Variant &name, const tl::Variant &from, const tl::Variant &to, bool inverse) + : m_name_id (db::property_names_id (name)), m_value_from (from), m_value_to (to), m_exact (false), m_glob (false), m_inverse (inverse) + { + // .. nothing yet .. + } + + PropertiesFilter (const tl::Variant &name, const std::string &pattern, bool inverse) + : m_name_id (db::property_names_id (name)), m_pattern (pattern), m_exact (true), m_glob (true), m_inverse (inverse) + { + // .. nothing yet .. + } + + bool prop_selected (db::properties_id_type prop_id) const + { + auto c = m_cache.find (prop_id); + if (c != m_cache.end ()) { + return c->second; + } + + bool res = prop_selected_impl (prop_id); + m_cache.insert (std::make_pair (prop_id, res)); + return res; + } + +private: + bool prop_selected_impl (db::properties_id_type prop_id) const + { + const db::PropertiesSet &ps = db::properties (prop_id); + if (ps.has_value (m_name_id)) { + + const tl::Variant &value = ps.value (m_name_id); + + if (m_glob) { + return m_pattern.match (value.to_string ()) != m_inverse; + } else if (m_exact) { + return (value == m_value_from) != m_inverse; + } else { + return ((m_value_from.is_nil () || ! (value < m_value_from)) && (m_value_to.is_nil () || value < m_value_to)) != m_inverse; + } + + } else { + return m_inverse; + } + } + + mutable std::map m_cache; + db::property_names_id_type m_name_id; + tl::Variant m_value_from, m_value_to; + tl::GlobPattern m_pattern; + bool m_exact; + bool m_glob; + bool m_inverse; +}; + +class PolygonPropertiesFilter + : public PolygonFilterBase, public PropertiesFilter +{ +public: + PolygonPropertiesFilter (const tl::Variant &name, const std::string &pattern, bool inverse) + : PropertiesFilter (name, pattern, inverse) + { + // .. nothing yet .. + } + + PolygonPropertiesFilter (const tl::Variant &name, const tl::Variant &value, bool inverse) + : PropertiesFilter (name, value, inverse) + { + // .. nothing yet .. + } + + PolygonPropertiesFilter (const tl::Variant &name, const tl::Variant &from, const tl::Variant &to, bool inverse) + : PropertiesFilter (name, from, to, inverse) + { + // .. nothing yet .. + } + + bool selected (const db::Polygon &, db::properties_id_type prop_id) const + { + return PropertiesFilter::prop_selected (prop_id); + } + + bool selected (const db::PolygonRef &, db::properties_id_type prop_id) const + { + return PropertiesFilter::prop_selected (prop_id); + } +}; + +static PolygonFilterBase *make_ppf1 (const tl::Variant &name, const tl::Variant &value, bool inverse) +{ + return new PolygonPropertiesFilter (name, value, inverse); +} + +static PolygonFilterBase *make_ppf2 (const tl::Variant &name, const tl::Variant &from, const tl::Variant &to, bool inverse) +{ + return new PolygonPropertiesFilter (name, from, to, inverse); +} + +static PolygonFilterBase *make_pg (const tl::Variant &name, const std::string &glob, bool inverse) +{ + return new PolygonPropertiesFilter (name, glob, inverse); +} + +Class decl_PolygonFilterBase ("db", "PolygonFilterBase", + gsi::constructor ("property_glob", &make_pg, gsi::arg ("name"), gsi::arg ("pattern"), gsi::arg ("inverse", false), + "@brief Creates a single-valued property filter\n" + "@param name The name of the property to use.\n" + "@param value The glob pattern to match the property value against.\n" + "@param inverse If true, inverts the selection - i.e. all polygons without a matching property are selected.\n" + "\n" + "Apply this filter with \\Region#filtered.\n" + "\n" + "This feature has been introduced in version 0.30." + ) + + gsi::constructor ("property_filter", &make_ppf1, gsi::arg ("name"), gsi::arg ("value"), gsi::arg ("inverse", false), + "@brief Creates a single-valued property filter\n" + "@param name The name of the property to use.\n" + "@param value The value against which the property is checked (exact match).\n" + "@param inverse If true, inverts the selection - i.e. all polygons without a property with the given name and value are selected.\n" + "\n" + "Apply this filter with \\Region#filtered.\n" + "\n" + "This feature has been introduced in version 0.30." + ) + + gsi::constructor ("property_filter_bounded", &make_ppf2, gsi::arg ("name"), gsi::arg ("from"), gsi::arg ("to"), gsi::arg ("inverse", false), + "@brief Creates a single-valued property filter\n" + "@param name The name of the property to use.\n" + "@param from The lower value against which the property is checked or 'nil' if no lower bound shall be used.\n" + "@param to The upper value against which the property is checked or 'nil' if no upper bound shall be used.\n" + "@param inverse If true, inverts the selection - i.e. all polygons without a property with the given name and value range are selected.\n" + "\n" + "This version does a bounded match. The value of the propery needs to be larger or equal to 'from' and less than 'to'.\n" + "Apply this filter with \\Region#filtered.\n" + "\n" + "This feature has been introduced in version 0.30." + ), + "@hide" +); + +Class decl_PolygonFilterImpl (decl_PolygonFilterBase, "db", "PolygonFilter", PolygonFilterImpl::method_decls (true) + callback ("selected", &PolygonFilterImpl::issue_selected, &PolygonFilterImpl::f_selected, gsi::arg ("polygon"), "@brief Selects a polygon\n" "This method is the actual payload. It needs to be reimplemented in a derived class.\n" - "It needs to analyze the polygon and return 'true' if it should be kept and 'false' if it should be discarded." + "It needs to analyze the polygon and return 'true' if it should be kept and 'false' if it should be discarded.\n" + "\n" + "Since version 0.30, the polygon carries properties." ), "@brief A generic polygon filter adaptor\n" "\n" @@ -544,12 +704,12 @@ static db::Edges extent_refs_edges (const db::Region *r, double fx1, double fy1, return r->processed (db::RelativeExtentsAsEdges (fx1, fy1, fx2, fy2)); } -static db::Region filtered (const db::Region *r, const PolygonFilterImpl *f) +static db::Region filtered (const db::Region *r, const PolygonFilterBase *f) { return r->filtered (*f); } -static void filter (db::Region *r, const PolygonFilterImpl *f) +static void filter (db::Region *r, const PolygonFilterBase *f) { r->filter (*f); } diff --git a/src/db/db/gsiDeclDbTexts.cc b/src/db/db/gsiDeclDbTexts.cc index 0de49ade6..46c516123 100644 --- a/src/db/db/gsiDeclDbTexts.cc +++ b/src/db/db/gsiDeclDbTexts.cc @@ -42,17 +42,17 @@ class TextFilterImpl public: TextFilterImpl () { } - bool issue_selected (const db::Text &) const + bool issue_selected (const db::TextWithProperties &) const { return false; } - virtual bool selected (const db::Text &text) const + virtual bool selected (const db::Text &text, db::properties_id_type prop_id) const { if (f_selected.can_issue ()) { - return f_selected.issue (&TextFilterImpl::issue_selected, text); + return f_selected.issue (&TextFilterImpl::issue_selected, db::TextWithProperties (text, prop_id)); } else { - return issue_selected (text); + return issue_selected (db::TextWithProperties (text, prop_id)); } } @@ -70,6 +70,8 @@ Class decl_TextFilterImpl ("db", "TextFilter", "@brief Selects a text\n" "This method is the actual payload. It needs to be reimplemented in a derived class.\n" "It needs to analyze the text and return 'true' if it should be kept and 'false' if it should be discarded." + "\n" + "Since version 0.30, the text carries properties." ), "@brief A generic text filter adaptor\n" "\n" diff --git a/src/db/unit_tests/dbEdgePairsTests.cc b/src/db/unit_tests/dbEdgePairsTests.cc index 0974f24cd..1f6153c3d 100644 --- a/src/db/unit_tests/dbEdgePairsTests.cc +++ b/src/db/unit_tests/dbEdgePairsTests.cc @@ -115,7 +115,7 @@ TEST(2) struct EPTestFilter : public db::EdgePairFilterBase { - bool selected (const db::EdgePair &ep) const + bool selected (const db::EdgePair &ep, db::properties_id_type) const { return ep.first ().double_length () < 50; } @@ -171,44 +171,44 @@ TEST(5_InternalAngleFilter) db::EdgePair ep90 (db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 0), db::Point (0, 100))); db::EdgePair epm90 (db::Edge (db::Point (0, 0), db::Point (100, 0)), db::Edge (db::Point (0, 100), db::Point (0, 0))); - EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, false).selected (ep0), true); - EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, false).selected (ep180), true); - EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, false).selected (ep90), false); - EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, false).selected (epm90), false); - EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, false).selected (ep45), false); + EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, false).selected (ep0, 0), true); + EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, false).selected (ep180, 0), true); + EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, false).selected (ep90, 0), false); + EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, false).selected (epm90, 0), false); + EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, false).selected (ep45, 0), false); - EXPECT_EQ (db::InternalAngleEdgePairFilter (90.0, false).selected (ep0), false); - EXPECT_EQ (db::InternalAngleEdgePairFilter (90.0, false).selected (ep180), false); - EXPECT_EQ (db::InternalAngleEdgePairFilter (90.0, false).selected (ep90), true); - EXPECT_EQ (db::InternalAngleEdgePairFilter (90.0, false).selected (epm90), true); - EXPECT_EQ (db::InternalAngleEdgePairFilter (90.0, false).selected (ep45), false); + EXPECT_EQ (db::InternalAngleEdgePairFilter (90.0, false).selected (ep0, 0), false); + EXPECT_EQ (db::InternalAngleEdgePairFilter (90.0, false).selected (ep180, 0), false); + EXPECT_EQ (db::InternalAngleEdgePairFilter (90.0, false).selected (ep90, 0), true); + EXPECT_EQ (db::InternalAngleEdgePairFilter (90.0, false).selected (epm90, 0), true); + EXPECT_EQ (db::InternalAngleEdgePairFilter (90.0, false).selected (ep45, 0), false); - EXPECT_EQ (db::InternalAngleEdgePairFilter (45.0, false).selected (ep0), false); - EXPECT_EQ (db::InternalAngleEdgePairFilter (45.0, false).selected (ep180), false); - EXPECT_EQ (db::InternalAngleEdgePairFilter (45.0, false).selected (ep90), false); - EXPECT_EQ (db::InternalAngleEdgePairFilter (45.0, false).selected (epm90), false); - EXPECT_EQ (db::InternalAngleEdgePairFilter (45.0, false).selected (ep45), true); - EXPECT_EQ (db::InternalAngleEdgePairFilter (45.0, false).selected (ep45inv), true); + EXPECT_EQ (db::InternalAngleEdgePairFilter (45.0, false).selected (ep0, 0), false); + EXPECT_EQ (db::InternalAngleEdgePairFilter (45.0, false).selected (ep180, 0), false); + EXPECT_EQ (db::InternalAngleEdgePairFilter (45.0, false).selected (ep90, 0), false); + EXPECT_EQ (db::InternalAngleEdgePairFilter (45.0, false).selected (epm90, 0), false); + EXPECT_EQ (db::InternalAngleEdgePairFilter (45.0, false).selected (ep45, 0), true); + EXPECT_EQ (db::InternalAngleEdgePairFilter (45.0, false).selected (ep45inv, 0), true); - EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true).selected (ep0), false); - EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true).selected (ep180), false); - EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true).selected (ep90), true); - EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true).selected (epm90), true); - EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true).selected (ep45), true); + EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true).selected (ep0, 0), false); + EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true).selected (ep180, 0), false); + EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true).selected (ep90, 0), true); + EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true).selected (epm90, 0), true); + EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true).selected (ep45, 0), true); - EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, false).selected (ep0), true); - EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, false).selected (ep180), true); - EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, false).selected (ep90), false); - EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, false).selected (epm90), false); - EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, false).selected (ep45), true); - EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, false).selected (ep45inv), true); + EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, false).selected (ep0, 0), true); + EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, false).selected (ep180, 0), true); + EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, false).selected (ep90, 0), false); + EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, false).selected (epm90, 0), false); + EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, false).selected (ep45, 0), true); + EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, false).selected (ep45inv, 0), true); - EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, true).selected (ep0), false); - EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, true).selected (ep180), false); - EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, true).selected (ep90), true); - EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, true).selected (epm90), true); - EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, true).selected (ep45), false); - EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, true).selected (ep45inv), false); + EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, true).selected (ep0, 0), false); + EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, true).selected (ep180, 0), false); + EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, true).selected (ep90, 0), true); + EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, true).selected (epm90, 0), true); + EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, true).selected (ep45, 0), false); + EXPECT_EQ (db::InternalAngleEdgePairFilter (0.0, true, 45.0, true, true).selected (ep45inv, 0), false); } TEST(6_add_with_properties) diff --git a/testdata/ruby/dbRegionTest.rb b/testdata/ruby/dbRegionTest.rb index 9cb46a1dd..e60250ee8 100644 --- a/testdata/ruby/dbRegionTest.rb +++ b/testdata/ruby/dbRegionTest.rb @@ -1583,6 +1583,52 @@ class DBRegion_TestClass < TestBase end + # properties + def test_prop_filters + + r = RBA::Region::new + r.insert(RBA::PolygonWithProperties::new(RBA::Box::new(0, 0, 100, 200), { "one" => -1 })) + r.insert(RBA::PolygonWithProperties::new(RBA::Box::new(1, 1, 101, 201), { "one" => 17 })) + r.insert(RBA::PolygonWithProperties::new(RBA::Box::new(2, 2, 102, 202), { "one" => 42 })) + + assert_equal(r.filtered(RBA::PolygonFilter::property_filter("one", 11)).to_s, "") + assert_equal(r.filtered(RBA::PolygonFilter::property_filter("two", 17)).to_s, "") + assert_equal(r.filtered(RBA::PolygonFilter::property_filter("one", 17)).to_s, "(1,1;1,201;101,201;101,1){one=>17}") + assert_equal(r.filtered(RBA::PolygonFilter::property_filter("one", 17, true)).to_s, "(2,2;2,202;102,202;102,2){one=>42};(0,0;0,200;100,200;100,0){one=>-1}") + assert_equal(r.filtered(RBA::PolygonFilter::property_filter_bounded("one", 17, nil)).to_s, "(1,1;1,201;101,201;101,1){one=>17};(2,2;2,202;102,202;102,2){one=>42}") + assert_equal(r.filtered(RBA::PolygonFilter::property_filter_bounded("one", 17, 18)).to_s, "(1,1;1,201;101,201;101,1){one=>17}") + assert_equal(r.filtered(RBA::PolygonFilter::property_filter_bounded("one", 17, 18, true)).to_s, "(2,2;2,202;102,202;102,2){one=>42};(0,0;0,200;100,200;100,0){one=>-1}") + assert_equal(r.filtered(RBA::PolygonFilter::property_filter_bounded("one", nil, 18)).to_s, "(1,1;1,201;101,201;101,1){one=>17};(0,0;0,200;100,200;100,0){one=>-1}") + assert_equal(r.filtered(RBA::PolygonFilter::property_glob("one", "1*")).to_s, "(1,1;1,201;101,201;101,1){one=>17}") + assert_equal(r.filtered(RBA::PolygonFilter::property_glob("one", "1*", true)).to_s, "(2,2;2,202;102,202;102,2){one=>42};(0,0;0,200;100,200;100,0){one=>-1}") + + ly = RBA::Layout::new + top = ly.create_cell("TOP") + l1 = ly.layer(1, 0) + + s = top.shapes(l1) + s.insert(RBA::PolygonWithProperties::new(RBA::Box::new(0, 0, 100, 200), { "one" => -1 })) + s.insert(RBA::PolygonWithProperties::new(RBA::Box::new(1, 1, 101, 201), { "one" => 17 })) + s.insert(RBA::PolygonWithProperties::new(RBA::Box::new(2, 2, 102, 202), { "one" => 42 })) + + dss = RBA::DeepShapeStore::new + iter = top.begin_shapes_rec(l1) + iter.enable_properties() + r = RBA::Region::new(iter, dss) + + assert_equal(r.filtered(RBA::PolygonFilter::property_filter("one", 11)).to_s, "") + assert_equal(r.filtered(RBA::PolygonFilter::property_filter("two", 17)).to_s, "") + assert_equal(r.filtered(RBA::PolygonFilter::property_filter("one", 17)).to_s, "(1,1;1,201;101,201;101,1){one=>17}") + assert_equal(r.filtered(RBA::PolygonFilter::property_filter("one", 17, true)).to_s, "(0,0;0,200;100,200;100,0){one=>-1};(2,2;2,202;102,202;102,2){one=>42}") + assert_equal(r.filtered(RBA::PolygonFilter::property_filter_bounded("one", 17, nil)).to_s, "(1,1;1,201;101,201;101,1){one=>17};(2,2;2,202;102,202;102,2){one=>42}") + assert_equal(r.filtered(RBA::PolygonFilter::property_filter_bounded("one", 17, 18)).to_s, "(1,1;1,201;101,201;101,1){one=>17}") + assert_equal(r.filtered(RBA::PolygonFilter::property_filter_bounded("one", 17, 18, true)).to_s, "(0,0;0,200;100,200;100,0){one=>-1};(2,2;2,202;102,202;102,2){one=>42}") + assert_equal(r.filtered(RBA::PolygonFilter::property_filter_bounded("one", nil, 18)).to_s, "(0,0;0,200;100,200;100,0){one=>-1};(1,1;1,201;101,201;101,1){one=>17}") + assert_equal(r.filtered(RBA::PolygonFilter::property_glob("one", "1*")).to_s, "(1,1;1,201;101,201;101,1){one=>17}") + assert_equal(r.filtered(RBA::PolygonFilter::property_glob("one", "1*", true)).to_s, "(0,0;0,200;100,200;100,0){one=>-1};(2,2;2,202;102,202;102,2){one=>42}") + + end + end load("test_epilogue.rb")