diff --git a/src/db/db/dbAsIfFlatRegion.cc b/src/db/db/dbAsIfFlatRegion.cc index 9547a71cf..f2fa65d1b 100644 --- a/src/db/db/dbAsIfFlatRegion.cc +++ b/src/db/db/dbAsIfFlatRegion.cc @@ -378,28 +378,77 @@ AsIfFlatRegion::processed_to_edge_pairs (const PolygonToEdgePairProcessorBase &f return new_edge_pairs.release (); } -RegionDelegate * -AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse, size_t min_count, size_t max_count) const +namespace { + +class OutputPairHolder { +public: + OutputPairHolder (InteractingOutputMode output_mode, bool merged_semantics) + { + if (output_mode == None) { + return; + } + + if (output_mode == Positive || output_mode == Negative || output_mode == PositiveAndNegative) { + m_positive.reset (new FlatRegion (merged_semantics)); + m_results.push_back (& m_positive->raw_polygons ()); + } else { + m_results.push_back ((db::Shapes *) 0); + } + + if (output_mode == PositiveAndNegative) { + m_negative.reset (new FlatRegion (merged_semantics)); + m_results.push_back (& m_negative->raw_polygons ()); + } + } + + std::pair region_pair () + { + return std::make_pair (m_positive.release (), m_negative.release ()); + } + + const std::vector &results () { return m_results; } + +private: + std::unique_ptr m_positive, m_negative; + std::vector m_results; +}; + +} + +std::pair +AsIfFlatRegion::selected_interacting_generic (const Edges &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const +{ + OutputPairHolder oph (output_mode, merged_semantics ()); + + if (output_mode == None) { + return oph.region_pair (); + } + min_count = std::max (size_t (1), min_count); - if (max_count < min_count || other.empty ()) { - if (! inverse) { - return new EmptyRegion (); + // shortcut + if (empty ()) { + if (output_mode == Positive || output_mode == Negative) { + return std::make_pair (clone (), (RegionDelegate *) 0); } else { - return clone (); + return std::make_pair (clone (), clone ()); + } + } else if (max_count < min_count || other.empty ()) { + if (output_mode == Positive) { + return std::make_pair (new EmptyRegion (), (RegionDelegate *) 0); + } else if (output_mode == Negative) { + return std::make_pair (clone (), (RegionDelegate *) 0); + } else { + return std::make_pair (new EmptyRegion (), clone ()); } - } else if (empty ()) { - return clone (); } bool counting = !(min_count == 1 && max_count == std::numeric_limits::max ()); -#if defined(USE_LOCAL_PROCESSOR) - db::RegionIterator polygons (begin_merged ()); - db::interacting_with_edge_local_operation op (inverse, min_count, max_count, true); + db::interacting_with_edge_local_operation op (output_mode, min_count, max_count, true); db::local_processor proc; proc.set_base_verbosity (base_verbosity ()); @@ -413,71 +462,42 @@ AsIfFlatRegion::selected_interacting_generic (const Edges &other, bool inverse, std::vector results; results.push_back (&output->raw_polygons ()); - proc.run_flat (polygons, others, std::vector (), &op, results); + proc.run_flat (polygons, others, std::vector (), &op, oph.results ()); - return output.release (); - -#else - std::unordered_map > counted_results; - ResultCountingInserter inserter (counted_results); - - db::box_scanner2 scanner (report_progress (), progress_desc ()); - scanner.reserve1 (count ()); - scanner.reserve2 (other.count ()); - - std::unique_ptr output (new FlatRegion (false)); - region_to_edge_interaction_filter filter (inserter, false, counting /*get all in counting mode*/); - - AddressablePolygonDelivery p (begin_merged ()); - - for ( ; ! p.at_end (); ++p) { - scanner.insert1 (p.operator-> (), 0); - if (inverse) { - inserter.init (p.operator-> ()); - } - } - - AddressableEdgeDelivery e (counting ? other.addressable_merged_edges () : other.addressable_edges ()); - - for ( ; ! e.at_end (); ++e) { - scanner.insert2 (e.operator-> (), 0); - } - - scanner.process (filter, 1, db::box_convert (), db::box_convert ()); - - // select hits based on their count - - for (std::unordered_map >::const_iterator r = counted_results.begin (); r != counted_results.end (); ++r) { - bool hit = r->second >= min_count && r->second <= max_count; - if (hit != inverse) { - output->insert (*r->first); - } - } - - return output.release (); -#endif + return oph.region_pair (); } -RegionDelegate * -AsIfFlatRegion::selected_interacting_generic (const Texts &other, bool inverse, size_t min_count, size_t max_count) const +std::pair +AsIfFlatRegion::selected_interacting_generic (const Texts &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const { - min_count = std::max (size_t (1), min_count); + OutputPairHolder oph (output_mode, merged_semantics ()); - if (max_count < min_count || other.empty ()) { - if (! inverse) { - return new EmptyRegion (); - } else { - return clone (); - } - } else if (empty ()) { - return clone (); + if (output_mode == None) { + return oph.region_pair (); } -#if defined(USE_LOCAL_PROCESSOR) + min_count = std::max (size_t (1), min_count); + + // shortcut + if (empty ()) { + if (output_mode == Positive || output_mode == Negative) { + return std::make_pair (clone (), (RegionDelegate *) 0); + } else { + return std::make_pair (clone (), clone ()); + } + } else if (max_count < min_count || other.empty ()) { + if (output_mode == Positive) { + return std::make_pair (new EmptyRegion (), (RegionDelegate *) 0); + } else if (output_mode == Negative) { + return std::make_pair (clone (), (RegionDelegate *) 0); + } else { + return std::make_pair (new EmptyRegion (), clone ()); + } + } db::RegionIterator polygons (begin_merged ()); - db::interacting_with_text_local_operation op (inverse, min_count, max_count); + db::interacting_with_text_local_operation op (output_mode, min_count, max_count); db::local_processor proc; proc.set_base_verbosity (base_verbosity ()); @@ -487,84 +507,58 @@ AsIfFlatRegion::selected_interacting_generic (const Texts &other, bool inverse, std::vector > others; others.push_back (other.begin ()); - std::unique_ptr output (new FlatRegion (merged_semantics ())); - std::vector results; - results.push_back (&output->raw_polygons ()); + proc.run_flat (polygons, others, std::vector (), &op, oph.results ()); - proc.run_flat (polygons, others, std::vector (), &op, results); - - return output.release (); - -#else - bool counting = !(min_count == 1 && max_count == std::numeric_limits::max ()); - - std::unordered_map > counted_results; - ResultCountingInserter inserter (counted_results); - - db::box_scanner2 scanner (report_progress (), progress_desc ()); - scanner.reserve1 (count ()); - scanner.reserve2 (other.count ()); - - region_to_text_interaction_filter filter (inserter, false, counting /*get all in counting mode*/); - - AddressablePolygonDelivery p (begin_merged ()); - - for ( ; ! p.at_end (); ++p) { - scanner.insert1 (p.operator-> (), 0); - if (inverse) { - inserter.init (p.operator-> ()); - } - } - - AddressableTextDelivery e (other.addressable_texts ()); - - for ( ; ! e.at_end (); ++e) { - scanner.insert2 (e.operator-> (), 0); - } - - scanner.process (filter, 1, db::box_convert (), db::box_convert ()); - - // select hits based on their count - - std::unique_ptr output (new FlatRegion (true)); - - for (std::unordered_map >::const_iterator r = counted_results.begin (); r != counted_results.end (); ++r) { - bool hit = r->second >= min_count && r->second <= max_count; - if (hit != inverse) { - output->insert (*r->first); - } - } - - return output.release (); -#endif + return oph.region_pair (); } -RegionDelegate * -AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse, size_t min_count, size_t max_count) const + +std::pair +AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, bool touching, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const { + OutputPairHolder oph (output_mode, merged_semantics ()); + + if (output_mode == None) { + return oph.region_pair (); + } + min_count = std::max (size_t (1), min_count); // shortcut if (empty ()) { - return clone (); + if (output_mode == Positive || output_mode == Negative) { + return std::make_pair (clone (), (RegionDelegate *) 0); + } else { + return std::make_pair (clone (), clone ()); + } } else if (max_count < min_count || other.empty ()) { // clear, if b is empty and // * mode is inside, enclosing or interacting and inverse is false ("inside" or "interacting") // * mode is outside and inverse is true ("not outside") - if ((mode <= 0) != inverse) { - return new EmptyRegion (); + if ((mode <= 0)) { + if (output_mode == Positive) { + return std::make_pair (new EmptyRegion (), (RegionDelegate *) 0); + } else if (output_mode == Negative) { + return std::make_pair (clone (), (RegionDelegate *) 0); + } else { + return std::make_pair (new EmptyRegion (), clone ()); + } } else { - return clone (); + if (output_mode == Positive) { + return std::make_pair (clone(), (RegionDelegate *) 0); + } else if (output_mode == Negative) { + return std::make_pair (new EmptyRegion (), (RegionDelegate *) 0); + } else { + return std::make_pair (clone (), new EmptyRegion ()); + } } } -#if defined(USE_LOCAL_PROCESSOR) - bool counting = !(min_count == 1 && max_count == std::numeric_limits::max ()); db::RegionIterator polygons (begin_merged ()); - db::interacting_local_operation op (mode, touching, inverse, min_count, max_count, true); + db::interacting_local_operation op (mode, touching, output_mode, min_count, max_count, true); db::local_processor proc; proc.set_base_verbosity (base_verbosity ()); @@ -574,121 +568,9 @@ AsIfFlatRegion::selected_interacting_generic (const Region &other, int mode, boo std::vector > others; others.push_back ((mode < 0 || counting) ? other.begin_merged () : other.begin ()); - std::unique_ptr output (new FlatRegion (merged_semantics ())); - std::vector results; - results.push_back (&output->raw_polygons ()); + proc.run_flat (polygons, others, std::vector (), &op, oph.results ()); - proc.run_flat (polygons, others, std::vector (), &op, results); - - return output.release (); - -#else - db::EdgeProcessor ep (report_progress (), progress_desc ()); - ep.set_base_verbosity (base_verbosity ()); - - size_t n = 0; - size_t nstart = 0; - - if (mode < -1) { - - // in enclosing mode self must be primary and other the secondary. For other - // modes it's the other way round - - for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p, ++n) { - if (mode > 0 || p->box ().touches (other.bbox ())) { - ep.insert (*p, n); - } - } - - nstart = n; - - } - - if (min_count == size_t (1) && max_count == std::numeric_limits::max ()) { - - if (mode < 0) { - - // NOTE: on "inside" or "enclosing", the other region must be merged - for (RegionIterator p = other.begin_merged (); ! p.at_end (); ++p) { - if (p->box ().touches (bbox ())) { - ep.insert (*p, n); - } - } - - } else { - - for (RegionIterator p = other.begin (); ! p.at_end (); ++p) { - if (p->box ().touches (bbox ())) { - ep.insert (*p, n); - } - } - - } - - ++n; - - } else { - - // with counting we need to separate the other polygons by different properties - - // cannot only have min_count/max_count in outside mode - tl_assert (mode <= 0); - - for (RegionIterator p = other.begin_merged (); ! p.at_end (); ++p) { - if (p->box ().touches (bbox ())) { - ep.insert (*p, n); - } - ++n; - } - - } - - if (mode >= -1) { - - nstart = n; - - for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p, ++n) { - if (mode > 0 || p->box ().touches (other.bbox ())) { - ep.insert (*p, n); - } - } - - } - - // there should be at least one element to look at for primary - tl_assert (nstart > 0); - - db::InteractionDetector id (mode, nstart - 1); - id.set_include_touching (touching); - db::EdgeSink es; - ep.process (es, id); - id.finish (); - - std::unique_ptr output (new FlatRegion (false)); - - std::map interaction_counts; - for (db::InteractionDetector::iterator i = id.begin (); i != id.end () ; ++i) { - if (i->first < nstart && i->second >= nstart) { - interaction_counts [mode < -1 ? i->first : i->second] += 1; - } - } - - output->reserve (n); - - n = (mode < -1 ? 0 : nstart); - for (RegionIterator p (begin_merged ()); ! p.at_end (); ++p, ++n) { - size_t count = 0; - std::map ::const_iterator c = interaction_counts.find (n); - if (c != interaction_counts.end ()) { - count = c->second; - } - if ((count >= min_count && count <= max_count) != inverse) { - output->insert (*p); - } - } - - return output.release (); -#endif + return oph.region_pair (); } EdgesDelegate * diff --git a/src/db/db/dbAsIfFlatRegion.h b/src/db/db/dbAsIfFlatRegion.h index eecec66d3..d2b8ff9e3 100644 --- a/src/db/db/dbAsIfFlatRegion.h +++ b/src/db/db/dbAsIfFlatRegion.h @@ -139,72 +139,107 @@ public: virtual RegionDelegate *selected_outside (const Region &other) const { - return selected_interacting_generic (other, 1, false, false); + return selected_interacting_generic (other, 1, false, Positive, size_t (0), std::numeric_limits::max ()).first; } virtual RegionDelegate *selected_not_outside (const Region &other) const { - return selected_interacting_generic (other, 1, false, true); + return selected_interacting_generic (other, 1, false, Negative, size_t (0), std::numeric_limits::max ()).first; + } + + virtual std::pair selected_outside_pair (const Region &other) const + { + return selected_interacting_generic (other, 1, false, PositiveAndNegative, size_t (0), std::numeric_limits::max ()); } virtual RegionDelegate *selected_inside (const Region &other) const { - return selected_interacting_generic (other, -1, true, false); + return selected_interacting_generic (other, -1, true, Positive, size_t (0), std::numeric_limits::max ()).first; } virtual RegionDelegate *selected_not_inside (const Region &other) const { - return selected_interacting_generic (other, -1, true, true); + return selected_interacting_generic (other, -1, true, Negative, size_t (0), std::numeric_limits::max ()).first; + } + + virtual std::pair selected_inside_pair (const Region &other) const + { + return selected_interacting_generic (other, -1, true, PositiveAndNegative, size_t (0), std::numeric_limits::max ()); } virtual RegionDelegate *selected_enclosing (const Region &other, size_t min_count, size_t max_count) const { - return selected_interacting_generic (other, -2, false, false, min_count, max_count); + return selected_interacting_generic (other, -2, false, Positive, min_count, max_count).first; } virtual RegionDelegate *selected_not_enclosing (const Region &other, size_t min_count, size_t max_count) const { - return selected_interacting_generic (other, -2, false, true, min_count, max_count); + return selected_interacting_generic (other, -2, false, Negative, min_count, max_count).first; + } + + virtual std::pair selected_enclosing_pair (const Region &other, size_t min_count, size_t max_count) const + { + return selected_interacting_generic (other, -2, false, PositiveAndNegative, min_count, max_count); } virtual RegionDelegate *selected_interacting (const Region &other, size_t min_count, size_t max_count) const { - return selected_interacting_generic (other, 0, true, false, min_count, max_count); + return selected_interacting_generic (other, 0, true, Positive, min_count, max_count).first; } virtual RegionDelegate *selected_not_interacting (const Region &other, size_t min_count, size_t max_count) const { - return selected_interacting_generic (other, 0, true, true, min_count, max_count); + return selected_interacting_generic (other, 0, true, Negative, min_count, max_count).first; + } + + virtual std::pair selected_interacting_pair (const Region &other, size_t min_count, size_t max_count) const + { + return selected_interacting_generic (other, 0, true, PositiveAndNegative, min_count, max_count); } virtual RegionDelegate *selected_interacting (const Edges &other, size_t min_count, size_t max_count) const { - return selected_interacting_generic (other, false, min_count, max_count); + return selected_interacting_generic (other, Positive, min_count, max_count).first; } virtual RegionDelegate *selected_not_interacting (const Edges &other, size_t min_count, size_t max_count) const { - return selected_interacting_generic (other, true, min_count, max_count); + return selected_interacting_generic (other, Negative, min_count, max_count).first; + } + + virtual std::pair selected_interacting_pair (const Edges &other, size_t min_count, size_t max_count) const + { + return selected_interacting_generic (other, PositiveAndNegative, min_count, max_count); } virtual RegionDelegate *selected_interacting (const Texts &other, size_t min_count, size_t max_count) const { - return selected_interacting_generic (other, false, min_count, max_count); + return selected_interacting_generic (other, Positive, min_count, max_count).first; } virtual RegionDelegate *selected_not_interacting (const Texts &other, size_t min_count, size_t max_count) const { - return selected_interacting_generic (other, true, min_count, max_count); + return selected_interacting_generic (other, Negative, min_count, max_count).first; + } + + virtual std::pair selected_interacting_pair (const Texts &other, size_t min_count, size_t max_count) const + { + return selected_interacting_generic (other, PositiveAndNegative, min_count, max_count); } virtual RegionDelegate *selected_overlapping (const Region &other, size_t min_count, size_t max_count) const { - return selected_interacting_generic (other, 0, false, false, min_count, max_count); + return selected_interacting_generic (other, 0, false, Positive, min_count, max_count).first; } virtual RegionDelegate *selected_not_overlapping (const Region &other, size_t min_count, size_t max_count) const { - return selected_interacting_generic (other, 0, false, true, min_count, max_count); + return selected_interacting_generic (other, 0, false, Negative, min_count, max_count).first; + } + + virtual std::pair selected_overlapping_pair (const Region &other, size_t min_count, size_t max_count) const + { + return selected_interacting_generic (other, 0, false, PositiveAndNegative, min_count, max_count); } virtual RegionDelegate *pull_inside (const Region &other) const @@ -245,9 +280,9 @@ protected: 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; - virtual RegionDelegate *selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse, size_t min_count = 1, size_t max_count = std::numeric_limits::max ()) const; - virtual RegionDelegate *selected_interacting_generic (const Edges &other, bool inverse, size_t min_count = 1, size_t max_count = std::numeric_limits::max ()) const; - virtual RegionDelegate *selected_interacting_generic (const Texts &other, bool inverse, size_t min_count = 1, size_t max_count = std::numeric_limits::max ()) const; + virtual std::pair selected_interacting_generic (const Region &other, int mode, bool touching, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const; + virtual std::pair selected_interacting_generic (const Edges &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const; + virtual std::pair selected_interacting_generic (const Texts &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const; virtual RegionDelegate *pull_generic (const Region &other, int mode, bool touching) const; virtual EdgesDelegate *pull_generic (const Edges &other) const; virtual TextsDelegate *pull_generic (const Texts &other) const; diff --git a/src/db/db/dbCompoundOperation.cc b/src/db/db/dbCompoundOperation.cc index d0d175149..db4aedd84 100644 --- a/src/db/db/dbCompoundOperation.cc +++ b/src/db/db/dbCompoundOperation.cc @@ -1060,13 +1060,13 @@ template void CompoundRegionLogicalCaseSelectOperationNode::implement_compute_lo // --------------------------------------------------------------------------------------------- CompoundRegionInteractOperationNode::CompoundRegionInteractOperationNode (CompoundRegionOperationNode *a, CompoundRegionOperationNode *b, int mode, bool touching, bool inverse, size_t min_count, size_t max_count) - : compound_region_generic_operation_node (&m_op, a, b), m_op (mode, touching, inverse, min_count, max_count, b->is_merged ()) + : compound_region_generic_operation_node (&m_op, a, b), m_op (mode, touching, inverse ? Negative : Positive, min_count, max_count, b->is_merged ()) { // .. nothing yet .. } CompoundRegionInteractOperationNode::CompoundRegionInteractOperationNode (db::Region *a, db::Region *b, int mode, bool touching, bool inverse, size_t min_count, size_t max_count) - : compound_region_generic_operation_node (&m_op, a, b), m_op (mode, touching, inverse, min_count, max_count, b->is_merged ()) + : compound_region_generic_operation_node (&m_op, a, b), m_op (mode, touching, inverse ? Negative : Positive, min_count, max_count, b->is_merged ()) { // .. nothing yet .. } @@ -1080,7 +1080,7 @@ CompoundRegionInteractOperationNode::generated_description () const // --------------------------------------------------------------------------------------------- CompoundRegionInteractWithEdgeOperationNode::CompoundRegionInteractWithEdgeOperationNode (CompoundRegionOperationNode *a, CompoundRegionOperationNode *b, bool inverse, size_t min_count, size_t max_count) - : compound_region_generic_operation_node (&m_op, a, b), m_op (inverse, min_count, max_count, b->is_merged ()) + : compound_region_generic_operation_node (&m_op, a, b), m_op (inverse ? Negative : Positive, min_count, max_count, b->is_merged ()) { // .. nothing yet .. } diff --git a/src/db/db/dbCompoundOperation.h b/src/db/db/dbCompoundOperation.h index 4f211a239..c7d285465 100644 --- a/src/db/db/dbCompoundOperation.h +++ b/src/db/db/dbCompoundOperation.h @@ -753,7 +753,8 @@ public: virtual void do_compute_local (db::Layout * /*layout*/, const shape_interactions & /*interactions*/, std::vector > & /*results*/, size_t /*max_vertex_count*/, double /*area_ratio*/) const { } private: - db::interacting_local_operation m_op; + typedef db::interacting_local_operation op_type; + op_type m_op; }; class DB_PUBLIC CompoundRegionInteractWithEdgeOperationNode diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index bc49410e9..db74b18ff 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -1519,9 +1519,67 @@ DeepRegion::run_single_polygon_check (db::edge_relation_type rel, db::Coord d, c return res.release (); } -RegionDelegate * -DeepRegion::selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse, size_t min_count, size_t max_count) const +namespace { + +class InteractingResultHolder +{ +public: + InteractingResultHolder (InteractingOutputMode output_mode, bool is_merged, const db::DeepLayer &polygons) + : m_output_mode (output_mode), m_is_merged (is_merged) + { + if (m_output_mode == Positive || m_output_mode == Negative) { + m_dl1 = db::DeepLayer (polygons.derived ()); + } else if (m_output_mode == PositiveAndNegative) { + m_dl1 = db::DeepLayer (polygons.derived ()); + m_dl2 = db::DeepLayer (polygons.derived ()); + } + } + + std::vector layers () const + { + std::vector l; + if (m_output_mode == Positive || m_output_mode == Negative) { + l.push_back (m_dl1.layer ()); + } else if (m_output_mode == PositiveAndNegative) { + l.push_back (m_dl1.layer ()); + l.push_back (m_dl2.layer ()); + } + return l; + } + + std::pair result_pair () + { + if (m_output_mode == Positive || m_output_mode == Negative) { + db::DeepRegion *res = new db::DeepRegion (m_dl1); + res->set_is_merged (m_is_merged); + return std::pair (res, 0); + } else if (m_output_mode == PositiveAndNegative) { + db::DeepRegion *res1 = new db::DeepRegion (m_dl1); + res1->set_is_merged (m_is_merged); + db::DeepRegion *res2 = new db::DeepRegion (m_dl2); + res2->set_is_merged (m_is_merged); + return std::pair (res1, res2); + } else { + return std::pair (0, 0); + } + } + +private: + InteractingOutputMode m_output_mode; + bool m_is_merged; + DeepLayer m_dl1, m_dl2; +}; + +} + +std::pair +DeepRegion::selected_interacting_generic (const Region &other, int mode, bool touching, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const +{ + if (output_mode == None) { + return std::pair (0, 0); + } + bool counting = !(min_count == 1 && max_count == std::numeric_limits::max ()); // with these flag set to true, the resulting polygons are broken again. @@ -1539,9 +1597,7 @@ DeepRegion::selected_interacting_generic (const Region &other, int mode, bool to // NOTE: on "inside" or with counting, the other polygons must be merged const db::DeepLayer &other_polygons = (mode < 0 || counting) ? other_deep->merged_deep_layer () : other_deep->deep_layer (); - DeepLayer dl_out (polygons.derived ()); - - db::InteractingLocalOperation op (mode, touching, inverse, min_count, max_count, true); + db::InteractingLocalOperation op (mode, touching, output_mode, min_count, max_count, true); db::local_processor proc (const_cast (&polygons.layout ()), const_cast (&polygons.initial_cell ()), &other_polygons.layout (), &other_polygons.initial_cell (), polygons.breakout_cells (), other_polygons.breakout_cells ()); proc.set_description (progress_desc ()); @@ -1553,17 +1609,16 @@ DeepRegion::selected_interacting_generic (const Region &other, int mode, bool to proc.set_max_vertex_count (polygons.store ()->max_vertex_count ()); } - proc.run (&op, polygons.layer (), other_polygons.layer (), dl_out.layer ()); + bool result_is_merged = (! split_after && ((mode < 0 && other.merged_semantics ()) || other.is_merged ()) && (merged_semantics () || is_merged ())); + InteractingResultHolder orh (output_mode, result_is_merged, polygons); - db::DeepRegion *res = new db::DeepRegion (dl_out); - if (! split_after && ((mode < 0 && other.merged_semantics ()) || other.is_merged ()) && (merged_semantics () || is_merged ())) { - res->set_is_merged (true); - } - return res; + proc.run (&op, polygons.layer (), other_polygons.layer (), orh.layers ()); + + return orh.result_pair (); } -RegionDelegate * -DeepRegion::selected_interacting_generic (const Edges &other, bool inverse, size_t min_count, size_t max_count) const +std::pair +DeepRegion::selected_interacting_generic (const Edges &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const { bool counting = !(min_count == 1 && max_count == std::numeric_limits::max ()); @@ -1580,9 +1635,7 @@ DeepRegion::selected_interacting_generic (const Edges &other, bool inverse, size const db::DeepLayer &polygons = merged_deep_layer (); - DeepLayer dl_out (polygons.derived ()); - - db::InteractingWithEdgeLocalOperation op (inverse, min_count, max_count, true); + db::InteractingWithEdgeLocalOperation op (output_mode, min_count, max_count, true); db::local_processor proc (const_cast (&polygons.layout ()), const_cast (&polygons.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), polygons.breakout_cells (), other_deep->deep_layer ().breakout_cells ()); proc.set_description (progress_desc ()); @@ -1594,13 +1647,12 @@ DeepRegion::selected_interacting_generic (const Edges &other, bool inverse, size proc.set_max_vertex_count (polygons.store ()->max_vertex_count ()); } - proc.run (&op, polygons.layer (), counting ? other_deep->merged_deep_layer ().layer () : other_deep->deep_layer ().layer (), dl_out.layer ()); + bool result_is_merged = (! split_after && other.is_merged () && (merged_semantics () || is_merged ())); + InteractingResultHolder orh (output_mode, result_is_merged, polygons); - db::DeepRegion *res = new db::DeepRegion (dl_out); - if (! split_after) { - res->set_is_merged (other.is_merged () && (merged_semantics () || is_merged ())); - } - return res; + proc.run (&op, polygons.layer (), counting ? other_deep->merged_deep_layer ().layer () : other_deep->deep_layer ().layer (), orh.layers ()); + + return orh.result_pair (); } RegionDelegate * @@ -1706,8 +1758,9 @@ DeepRegion::pull_generic (const Texts &other) const return res; } -RegionDelegate * -DeepRegion::selected_interacting_generic (const Texts &other, bool inverse, size_t min_count, size_t max_count) const + +std::pair +DeepRegion::selected_interacting_generic (const Texts &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const { // with these flag set to true, the resulting polygons are broken again. bool split_after = false; @@ -1722,9 +1775,7 @@ DeepRegion::selected_interacting_generic (const Texts &other, bool inverse, size const db::DeepLayer &polygons = merged_deep_layer (); - DeepLayer dl_out (polygons.derived ()); - - db::InteractingWithTextLocalOperation op (inverse, min_count, max_count); + db::InteractingWithTextLocalOperation op (output_mode, min_count, max_count); db::local_processor proc (const_cast (&polygons.layout ()), const_cast (&polygons.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), polygons.breakout_cells (), other_deep->deep_layer ().breakout_cells ()); proc.set_description (progress_desc ()); @@ -1736,13 +1787,12 @@ DeepRegion::selected_interacting_generic (const Texts &other, bool inverse, size proc.set_max_vertex_count (polygons.store ()->max_vertex_count ()); } - proc.run (&op, polygons.layer (), other_deep->deep_layer ().layer (), dl_out.layer ()); + bool result_is_merged = (! split_after && (merged_semantics () || is_merged ())); + InteractingResultHolder orh (output_mode, result_is_merged, polygons); - db::DeepRegion *res = new db::DeepRegion (dl_out); - if (! split_after) { - res->set_is_merged (merged_semantics () || is_merged ()); - } - return res; + proc.run (&op, polygons.layer (), other_deep->deep_layer ().layer (), orh.layers ()); + + return orh.result_pair (); } } diff --git a/src/db/db/dbDeepRegion.h b/src/db/db/dbDeepRegion.h index 138350c07..c15913f2c 100644 --- a/src/db/db/dbDeepRegion.h +++ b/src/db/db/dbDeepRegion.h @@ -140,9 +140,9 @@ protected: 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; - virtual RegionDelegate *selected_interacting_generic (const Region &other, int mode, bool touching, bool inverse, size_t min_count, size_t max_count) const; - virtual RegionDelegate *selected_interacting_generic (const Edges &other, bool inverse, size_t min_count, size_t max_count) const; - virtual RegionDelegate *selected_interacting_generic (const Texts &other, bool inverse, size_t min_count, size_t max_count) const; + virtual std::pair selected_interacting_generic (const Region &other, int mode, bool touching, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const; + virtual std::pair selected_interacting_generic (const Edges &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const; + virtual std::pair selected_interacting_generic (const Texts &other, InteractingOutputMode output_mode, size_t min_count, size_t max_count) const; virtual RegionDelegate *pull_generic (const Region &other, int mode, bool touching) const; virtual EdgesDelegate *pull_generic (const Edges &other) const; virtual TextsDelegate *pull_generic (const Texts &other) const; diff --git a/src/db/db/dbDeviceClass.h b/src/db/db/dbDeviceClass.h index 96bb0dc6e..d77048e2b 100644 --- a/src/db/db/dbDeviceClass.h +++ b/src/db/db/dbDeviceClass.h @@ -252,6 +252,7 @@ public: DeviceParameterCompareDelegate () { } virtual ~DeviceParameterCompareDelegate () { } + virtual DeviceParameterCompareDelegate *clone () const = 0; virtual bool less (const db::Device &a, const db::Device &b) const = 0; virtual bool equal (const db::Device &a, const db::Device &b) const = 0; }; @@ -273,6 +274,11 @@ public: virtual bool less (const db::Device &a, const db::Device &b) const; virtual bool equal (const db::Device &a, const db::Device &b) const; + virtual DeviceParameterCompareDelegate *clone () const + { + return new EqualDeviceParameters (*this); + } + EqualDeviceParameters &operator+= (const EqualDeviceParameters &other); EqualDeviceParameters operator+ (const EqualDeviceParameters &other) const @@ -298,6 +304,11 @@ public: virtual bool less (const db::Device &a, const db::Device &b) const; virtual bool equal (const db::Device &a, const db::Device &b) const; + virtual DeviceParameterCompareDelegate *clone () const + { + return new AllDeviceParametersAreEqual (*this); + } + private: double m_relative; }; @@ -574,6 +585,14 @@ public: /** * @brief Gets the parameter compare delegate or null if no such delegate is registered */ + const db::DeviceParameterCompareDelegate *parameter_compare_delegate () const + { + return mp_pc_delegate.get (); + } + + /** + * @brief Gets the parameter compare delegate or null if no such delegate is registered (non-const version) + */ db::DeviceParameterCompareDelegate *parameter_compare_delegate () { return mp_pc_delegate.get (); diff --git a/src/db/db/dbEmptyRegion.h b/src/db/db/dbEmptyRegion.h index 6e99c8938..89e82c68a 100644 --- a/src/db/db/dbEmptyRegion.h +++ b/src/db/db/dbEmptyRegion.h @@ -108,18 +108,25 @@ public: virtual RegionDelegate *selected_outside (const Region &) const { return new EmptyRegion (); } virtual RegionDelegate *selected_not_outside (const Region &) const { return new EmptyRegion (); } + virtual std::pair selected_outside_pair (const Region &) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); } virtual RegionDelegate *selected_inside (const Region &) const { return new EmptyRegion (); } virtual RegionDelegate *selected_not_inside (const Region &) const { return new EmptyRegion (); } + virtual std::pair selected_inside_pair (const Region &) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); } virtual RegionDelegate *selected_enclosing (const Region &, size_t, size_t) const { return new EmptyRegion (); } virtual RegionDelegate *selected_not_enclosing (const Region &, size_t, size_t) const { return new EmptyRegion (); } + virtual std::pair selected_enclosing_pair (const Region &, size_t, size_t) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); } virtual RegionDelegate *selected_interacting (const Region &, size_t, size_t) const { return new EmptyRegion (); } virtual RegionDelegate *selected_not_interacting (const Region &, size_t, size_t) const { return new EmptyRegion (); } + virtual std::pair selected_interacting_pair (const Region &, size_t, size_t) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); } virtual RegionDelegate *selected_interacting (const Edges &, size_t, size_t) const { return new EmptyRegion (); } virtual RegionDelegate *selected_not_interacting (const Edges &, size_t, size_t) const { return new EmptyRegion (); } + virtual std::pair selected_interacting_pair (const Edges &, size_t, size_t) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); } virtual RegionDelegate *selected_interacting (const Texts &, size_t, size_t) const { return new EmptyRegion (); } virtual RegionDelegate *selected_not_interacting (const Texts &, size_t, size_t) const { return new EmptyRegion (); } + virtual std::pair selected_interacting_pair (const Texts &, size_t, size_t) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); } virtual RegionDelegate *selected_overlapping (const Region &, size_t, size_t) const { return new EmptyRegion (); } virtual RegionDelegate *selected_not_overlapping (const Region &, size_t, size_t) const { return new EmptyRegion (); } + virtual std::pair selected_overlapping_pair (const Region &, size_t, size_t) const { return std::make_pair (new EmptyRegion (), new EmptyRegion ()); } virtual RegionDelegate *pull_inside (const Region &) const { return new EmptyRegion (); } virtual RegionDelegate *pull_interacting (const Region &) const { return new EmptyRegion (); } virtual EdgesDelegate *pull_interacting (const Edges &) const { return new EmptyEdges (); } diff --git a/src/db/db/dbHierProcessor.cc b/src/db/db/dbHierProcessor.cc index 6b534eabb..df90ff1ba 100644 --- a/src/db/db/dbHierProcessor.cc +++ b/src/db/db/dbHierProcessor.cc @@ -1280,6 +1280,14 @@ void local_processor::run (local_operation *op, unsigned run (op, subject_layer, il, ol); } +template +void local_processor::run (local_operation *op, unsigned int subject_layer, unsigned int intruder_layer, const std::vector &output_layers) +{ + std::vector ol, il; + il.push_back (intruder_layer); + run (op, subject_layer, il, output_layers); +} + template void local_processor::run (local_operation *op, unsigned int subject_layer, const std::vector &intruder_layers, unsigned int output_layer) { diff --git a/src/db/db/dbHierProcessor.h b/src/db/db/dbHierProcessor.h index 71ecdb311..c65da727f 100644 --- a/src/db/db/dbHierProcessor.h +++ b/src/db/db/dbHierProcessor.h @@ -419,6 +419,7 @@ public: local_processor (db::Layout *layout = 0, db::Cell *top = 0, const std::set *breakout_cells = 0); local_processor (db::Layout *subject_layout, db::Cell *subject_top, const db::Layout *intruder_layout, const db::Cell *intruder_cell, const std::set *subject_breakout_cells = 0, const std::set *intruder_breakout_cells = 0); void run (local_operation *op, unsigned int subject_layer, unsigned int intruder_layer, unsigned int output_layers); + void run (local_operation *op, unsigned int subject_layer, unsigned int intruder_layer, const std::vector &output_layers); void run (local_operation *op, unsigned int subject_layer, const std::vector &intruder_layers, const std::vector &output_layers); void run (local_operation *op, unsigned int subject_layer, const std::vector &intruder_layers, unsigned int output_layer); void compute_contexts (local_processor_contexts &contexts, const local_operation *op, unsigned int subject_layer, const std::vector &intruder_layers) const; diff --git a/src/db/db/dbLayout.cc b/src/db/db/dbLayout.cc index f08b0e6ce..fcc6b29ba 100644 --- a/src/db/db/dbLayout.cc +++ b/src/db/db/dbLayout.cc @@ -1671,7 +1671,9 @@ Layout::do_update () // HINT: because of some gcc bug, automatic destruction of the tl::Progress // object does not work. We overcome this problem by creating the object with new // and catching exceptions. - tl::RelativeProgress *pr = new tl::RelativeProgress (tl::to_string (tr ("Sorting layout")), m_cells_size, 1000); + // As this operation is critical we don't want to have it cancelled. Plus: do_update is called during ~LayoutLocker and + // if we throw exceptions then, we'll get a runtime assertion. + tl::RelativeProgress *pr = new tl::RelativeProgress (tl::to_string (tr ("Sorting layout")), m_cells_size, 0, false /*can't cancel*/); pr->set_desc (""); try { diff --git a/src/db/db/dbLayoutToNetlistReader.cc b/src/db/db/dbLayoutToNetlistReader.cc index 2ef9ed8fd..d809398d1 100644 --- a/src/db/db/dbLayoutToNetlistReader.cc +++ b/src/db/db/dbLayoutToNetlistReader.cc @@ -632,6 +632,9 @@ LayoutToNetlistStandardReader::read_pin (db::Netlist * /*netlist*/, db::LayoutTo } size_t pin_id = circuit->add_pin (pin).id (); + // NOTE: because we identify pins by their order and not by ID we need to ensure the pin IDs are + // generated sequentially. + tl_assert (circuit->pin_count () == pin_id + 1); if (net) { circuit->connect_pin (pin_id, net); } diff --git a/src/db/db/dbLayoutToNetlistWriter.cc b/src/db/db/dbLayoutToNetlistWriter.cc index bdeeebb91..4dc227ae4 100644 --- a/src/db/db/dbLayoutToNetlistWriter.cc +++ b/src/db/db/dbLayoutToNetlistWriter.cc @@ -561,7 +561,8 @@ void std_writer_impl::write (const db::SubCircuit &subcircuit, std::mapfirst.to_parsable_string () << " " << p->second.to_parsable_string () << ")" << endl; } - for (db::Circuit::const_pin_iterator p = subcircuit.circuit_ref ()->begin_pins (); p != subcircuit.circuit_ref ()->end_pins (); ++p) { + unsigned int pin_id = 0; + for (db::Circuit::const_pin_iterator p = subcircuit.circuit_ref ()->begin_pins (); p != subcircuit.circuit_ref ()->end_pins (); ++p, ++pin_id) { const db::Net *net = subcircuit.net_for_pin (p->id ()); if (net) { if (separate_lines) { @@ -569,7 +570,7 @@ void std_writer_impl::write (const db::SubCircuit &subcircuit, std::mapid ()) << " " << net2id [net] << ")"; + *mp_stream << Keys::pin_key << "(" << tl::to_string (pin_id) << " " << net2id [net] << ")"; if (separate_lines) { *mp_stream << endl; } diff --git a/src/db/db/dbLayoutVsSchematicFormatDefs.h b/src/db/db/dbLayoutVsSchematicFormatDefs.h index 8f1dd043b..8f7a25812 100644 --- a/src/db/db/dbLayoutVsSchematicFormatDefs.h +++ b/src/db/db/dbLayoutVsSchematicFormatDefs.h @@ -88,19 +88,19 @@ namespace db * * [xref-def]: * - * circuit([non] [non] [status]? [circuit-xrefs]) + * circuit([non] [non] [status]? [message]? [circuit-xrefs]) * - circuit pair [short key: X] * * [circuit-xrefs]: * - * xref([pair]*) + * xref([pair]*) - circuit cross-reference part [short key: Z] * * [pair] * - * pin([ion] [ion] [status]?) - a pin pair [short key: P] - * device([ion] [ion] [status]?) - a device pair [short key: D] - * circuit([ion] [ion] [status]?) - a subcircuit pair [short key: X] - * net([ion] [ion] [status]?) - a net pair [short key: N] + * pin([ion] [ion] [status]? [message]?) - a pin pair [short key: P] + * device([ion] [ion] [status]? [message]?) - a device pair [short key: D] + * circuit([ion] [ion] [status]? [message]?) - a subcircuit pair [short key: X] + * net([ion] [ion] [status]? [message]?) - a net pair [short key: N] * * [non] * @@ -110,6 +110,10 @@ namespace db * * | () * + * [message] + * + * description() - error description [short key: B] + * * [status] * * mismatch | - [short key: 0] diff --git a/src/db/db/dbLayoutVsSchematicReader.cc b/src/db/db/dbLayoutVsSchematicReader.cc index 576e42a66..1c514c8ca 100644 --- a/src/db/db/dbLayoutVsSchematicReader.cc +++ b/src/db/db/dbLayoutVsSchematicReader.cc @@ -112,6 +112,18 @@ void LayoutVsSchematicStandardReader::read_netlist (db::LayoutVsSchematic *lvs) } } +bool LayoutVsSchematicStandardReader::read_message (std::string &msg) +{ + if (test (skeys::description_key) || test (lkeys::description_key)) { + Brace br (this); + read_word_or_quoted (msg); + br.done (); + return true; + } else { + return false; + } +} + bool LayoutVsSchematicStandardReader::read_status (db::NetlistCrossReference::Status &status) { if (test (skeys::match_key) || test (lkeys::match_key)) { @@ -189,11 +201,14 @@ void LayoutVsSchematicStandardReader::read_xref (db::NetlistCrossReference *xref xref->gen_begin_circuit (circuit_a, circuit_b); db::NetlistCrossReference::Status status = db::NetlistCrossReference::None; + std::string msg; while (br) { if (read_status (status)) { // continue + } else if (read_message (msg)) { + // continue } else if (test (skeys::xref_key) || test (lkeys::xref_key)) { read_xrefs_for_circuits (xref, circuit_a, circuit_b); } else if (at_end ()) { @@ -204,7 +219,7 @@ void LayoutVsSchematicStandardReader::read_xref (db::NetlistCrossReference *xref } - xref->gen_end_circuit (circuit_a, circuit_b, status); + xref->gen_end_circuit (circuit_a, circuit_b, status, msg); br.done (); @@ -325,11 +340,13 @@ void LayoutVsSchematicStandardReader::read_net_pair (db::NetlistCrossReference * ion_b = read_ion (); db::NetlistCrossReference::Status status = db::NetlistCrossReference::None; + std::string msg; read_status (status); + read_message (msg); br.done (); - xref->gen_nets (net_by_numerical_id (circuit_a, ion_a, m_map_per_circuit_a), net_by_numerical_id (circuit_b, ion_b, m_map_per_circuit_b), status); + xref->gen_nets (net_by_numerical_id (circuit_a, ion_a, m_map_per_circuit_a), net_by_numerical_id (circuit_b, ion_b, m_map_per_circuit_b), status, msg); } void LayoutVsSchematicStandardReader::read_pin_pair (db::NetlistCrossReference *xref, const db::Circuit *circuit_a, const db::Circuit *circuit_b) @@ -341,11 +358,13 @@ void LayoutVsSchematicStandardReader::read_pin_pair (db::NetlistCrossReference * ion_b = read_ion (); db::NetlistCrossReference::Status status = db::NetlistCrossReference::None; + std::string msg; read_status (status); + read_message (msg); br.done (); - xref->gen_pins (pin_by_numerical_id (circuit_a, ion_a), pin_by_numerical_id (circuit_b, ion_b), status); + xref->gen_pins (pin_by_numerical_id (circuit_a, ion_a), pin_by_numerical_id (circuit_b, ion_b), status, msg); } void LayoutVsSchematicStandardReader::read_device_pair (db::NetlistCrossReference *xref, const db::Circuit *circuit_a, const db::Circuit *circuit_b) @@ -357,11 +376,13 @@ void LayoutVsSchematicStandardReader::read_device_pair (db::NetlistCrossReferenc ion_b = read_ion (); db::NetlistCrossReference::Status status = db::NetlistCrossReference::None; + std::string msg; read_status (status); + read_message (msg); br.done (); - xref->gen_devices (device_by_numerical_id (circuit_a, ion_a, m_map_per_circuit_a), device_by_numerical_id (circuit_b, ion_b, m_map_per_circuit_b), status); + xref->gen_devices (device_by_numerical_id (circuit_a, ion_a, m_map_per_circuit_a), device_by_numerical_id (circuit_b, ion_b, m_map_per_circuit_b), status, msg); } void LayoutVsSchematicStandardReader::read_subcircuit_pair (db::NetlistCrossReference *xref, const db::Circuit *circuit_a, const db::Circuit *circuit_b) @@ -373,11 +394,13 @@ void LayoutVsSchematicStandardReader::read_subcircuit_pair (db::NetlistCrossRefe ion_b = read_ion (); db::NetlistCrossReference::Status status = db::NetlistCrossReference::None; + std::string msg; read_status (status); + read_message (msg); br.done (); - xref->gen_subcircuits (subcircuit_by_numerical_id (circuit_a, ion_a, m_map_per_circuit_a), subcircuit_by_numerical_id (circuit_b, ion_b, m_map_per_circuit_b), status); + xref->gen_subcircuits (subcircuit_by_numerical_id (circuit_a, ion_a, m_map_per_circuit_a), subcircuit_by_numerical_id (circuit_b, ion_b, m_map_per_circuit_b), status, msg); } } diff --git a/src/db/db/dbLayoutVsSchematicReader.h b/src/db/db/dbLayoutVsSchematicReader.h index a28dca902..1cc900c75 100644 --- a/src/db/db/dbLayoutVsSchematicReader.h +++ b/src/db/db/dbLayoutVsSchematicReader.h @@ -78,6 +78,7 @@ private: void read_netlist (db::LayoutVsSchematic *lvs); bool read_status (db::NetlistCrossReference::Status &status); + bool read_message (std::string &msg); void read_xref (db::NetlistCrossReference *xref); void read_xrefs_for_circuits (db::NetlistCrossReference *xref, const db::Circuit *circuit_a, const db::Circuit *circuit_b); void read_net_pair (db::NetlistCrossReference *xref, const db::Circuit *circuit_a, const db::Circuit *circuit_b); diff --git a/src/db/db/dbLayoutVsSchematicWriter.cc b/src/db/db/dbLayoutVsSchematicWriter.cc index b9bec64ab..527429b74 100644 --- a/src/db/db/dbLayoutVsSchematicWriter.cc +++ b/src/db/db/dbLayoutVsSchematicWriter.cc @@ -70,6 +70,7 @@ private: } std::string status_to_s (const db::NetlistCrossReference::Status status); + std::string message_to_s (const std::string &msg); void write (const db::NetlistCrossReference *xref); std::map > m_net2id_per_circuit_a, m_net2id_per_circuit_b; @@ -145,7 +146,7 @@ std::string ion_to_s (const Obj *obj) } } -std::string net_id_to_s (const db::Net *net, const std::map &net2id) +static std::string net_id_to_s (const db::Net *net, const std::map &net2id) { if (net) { std::map::const_iterator i = net2id.find (net); @@ -156,6 +157,37 @@ std::string net_id_to_s (const db::Net *net, const std::map &pin2index) +{ + if (c) { + size_t pi = 0; + for (db::Circuit::const_pin_iterator p = c->begin_pins (); p != c->end_pins (); ++p, ++pi) { + pin2index.insert (std::make_pair (p.operator-> (), pi)); + } + } +} + +static std::string pin_id_to_s (const db::Pin *pin, const std::map &pin2index) +{ + if (pin) { + std::map::const_iterator i = pin2index.find (pin); + tl_assert (i != pin2index.end ()); + return tl::to_string (i->second); + } else { + return "()"; + } +} + +template +std::string std_writer_impl::message_to_s (const std::string &msg) +{ + if (msg.empty ()) { + return std::string (); + } else { + return " " + Keys::description_key + "(" + tl::to_word_or_quoted_string (msg) + ")"; + } +} + template std::string std_writer_impl::status_to_s (const db::NetlistCrossReference::Status status) { @@ -182,23 +214,27 @@ void std_writer_impl::write (const db::NetlistCrossReference *xref) const db::NetlistCrossReference::PerCircuitData *pcd = xref->per_circuit_data_for (*c); tl_assert (pcd != 0); - stream () << indent1 << Keys::circuit_key << "(" << name_to_s (c->first) << " " << name_to_s (c->second) << status_to_s (pcd->status) << endl; + stream () << indent1 << Keys::circuit_key << "(" << name_to_s (c->first) << " " << name_to_s (c->second) << status_to_s (pcd->status) << message_to_s (pcd->msg) << endl; stream () << indent2 << Keys::xref_key << "(" << endl; for (db::NetlistCrossReference::PerCircuitData::net_pairs_const_iterator n = pcd->nets.begin (); n != pcd->nets.end (); ++n) { - stream () << indent1 << indent2 << Keys::net_key << "(" << net_id_to_s (n->pair.first, m_net2id_per_circuit_a [c->first]) << " " << net_id_to_s (n->pair.second, m_net2id_per_circuit_b [c->second]) << status_to_s (n->status) << ")" << endl; + stream () << indent1 << indent2 << Keys::net_key << "(" << net_id_to_s (n->pair.first, m_net2id_per_circuit_a [c->first]) << " " << net_id_to_s (n->pair.second, m_net2id_per_circuit_b [c->second]) << status_to_s (n->status) << message_to_s (n->msg) << ")" << endl; } + std::map pin2index_a, pin2index_b; + build_pin_index_map (c->first, pin2index_a); + build_pin_index_map (c->second, pin2index_b); + for (db::NetlistCrossReference::PerCircuitData::pin_pairs_const_iterator n = pcd->pins.begin (); n != pcd->pins.end (); ++n) { - stream () << indent1 << indent2 << Keys::pin_key << "(" << ion_to_s (n->pair.first) << " " << ion_to_s (n->pair.second) << status_to_s (n->status) << ")" << endl; + stream () << indent1 << indent2 << Keys::pin_key << "(" << pin_id_to_s (n->pair.first, pin2index_a) << " " << pin_id_to_s (n->pair.second, pin2index_b) << status_to_s (n->status) << message_to_s (n->msg) << ")" << endl; } for (db::NetlistCrossReference::PerCircuitData::device_pairs_const_iterator n = pcd->devices.begin (); n != pcd->devices.end (); ++n) { - stream () << indent1 << indent2 << Keys::device_key << "(" << ion_to_s (n->pair.first) << " " << ion_to_s (n->pair.second) << status_to_s (n->status) << ")" << endl; + stream () << indent1 << indent2 << Keys::device_key << "(" << ion_to_s (n->pair.first) << " " << ion_to_s (n->pair.second) << status_to_s (n->status) << message_to_s (n->msg) << ")" << endl; } for (db::NetlistCrossReference::PerCircuitData::subcircuit_pairs_const_iterator n = pcd->subcircuits.begin (); n != pcd->subcircuits.end (); ++n) { - stream () << indent1 << indent2 << Keys::circuit_key << "(" << ion_to_s (n->pair.first) << " " << ion_to_s (n->pair.second) << status_to_s (n->status) << ")" << endl; + stream () << indent1 << indent2 << Keys::circuit_key << "(" << ion_to_s (n->pair.first) << " " << ion_to_s (n->pair.second) << status_to_s (n->status) << message_to_s (n->msg) << ")" << endl; } stream () << indent2 << ")" << endl; diff --git a/src/db/db/dbLocalOperation.h b/src/db/db/dbLocalOperation.h index abf6b4165..972e36c96 100644 --- a/src/db/db/dbLocalOperation.h +++ b/src/db/db/dbLocalOperation.h @@ -54,6 +54,11 @@ enum OnEmptyIntruderHint { */ Copy, + /** + * @brief Copy the subject shape to the second result + */ + CopyToSecond, + /** * @brief Drop the subject shape */ diff --git a/src/db/db/dbNetlistCompare.cc b/src/db/db/dbNetlistCompare.cc index 72eb4cfe9..99ad08829 100644 --- a/src/db/db/dbNetlistCompare.cc +++ b/src/db/db/dbNetlistCompare.cc @@ -397,7 +397,7 @@ public: * @brief A generic categorizer * * The objective of this class is to supply a category ID for a given object. - * The category ID also identities equivalent objects from netlist A and B. + * The category ID also identifies equivalent objects from netlist A and B. */ template class generic_categorizer @@ -2991,6 +2991,23 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const } } + // impose the compare tolerances of the layout (first netlist) on the schematic (second netlist) + // TODO: this is kind of clumsy. But it's very important to use the same device sorting for both netlists, so we play this trick. + // A better solution was to have a common compare framework for both netlists. + for (std::map >::const_iterator i = cat2dc.begin (); i != cat2dc.end (); ++i) { + + if (i->second.first && i->second.second) { + + const db::DeviceClass *da = i->second.first; + db::DeviceClass *db = const_cast (i->second.second); + + const db::DeviceParameterCompareDelegate *cmp = da->parameter_compare_delegate (); + db->set_parameter_compare_delegate (cmp ? cmp->clone () : 0); + + } + + } + // device whether to use a device category in strict mode device_categorizer.clear_strict_device_categories (); @@ -3083,7 +3100,7 @@ NetlistComparer::compare (const db::Netlist *a, const db::Netlist *b) const } else { if (mp_logger) { - mp_logger->circuit_skipped (ca, cb); + mp_logger->circuit_skipped (ca, cb, generate_subcircuits_not_verified_warning (ca, verified_circuits_a, cb, verified_circuits_b)); good = false; } @@ -3130,24 +3147,61 @@ NetlistComparer::derive_pin_equivalence (const db::Circuit *ca, const db::Circui circuit_pin_mapper->map_pins (cb, pb); } +static bool is_valid_circuit (const db::Circuit *c) +{ + // typical via subcircuits attach through one pin. We can safely ignore such subcircuits because they don't + // contribute graph edges. + return c->pin_count () > 1; +} + bool NetlistComparer::all_subcircuits_verified (const db::Circuit *c, const std::set &verified_circuits) const { for (db::Circuit::const_subcircuit_iterator sc = c->begin_subcircuits (); sc != c->end_subcircuits (); ++sc) { - const db::Circuit *cr = sc->circuit_ref (); - - // typical via subcircuits attach through one pin. We can safely ignore such subcircuits because they don't - // contribute graph edges. - if (cr->pin_count () > 1 && verified_circuits.find (cr) == verified_circuits.end ()) { + if (is_valid_circuit (cr) && verified_circuits.find (cr) == verified_circuits.end ()) { return false; } - } return true; } +static std::vector unverified_names (const db::Circuit *c, const std::set &verified_circuits) +{ + std::vector names; + + std::set seen; + for (db::Circuit::const_subcircuit_iterator sc = c->begin_subcircuits (); sc != c->end_subcircuits (); ++sc) { + const db::Circuit *cr = sc->circuit_ref (); + if (is_valid_circuit (cr) && seen.find (cr) == seen.end () && verified_circuits.find (cr) == verified_circuits.end ()) { + seen.insert (cr); + names.push_back (cr->name ()); + } + } + + std::sort (names.begin (), names.end ()); + return names; +} + +std::string +NetlistComparer::generate_subcircuits_not_verified_warning (const db::Circuit *ca, const std::set &verified_circuits_a, const db::Circuit *cb, const std::set &verified_circuits_b) const +{ + std::string msg = tl::sprintf (tl::to_string (tr ("Circuits %s and %s could not be compared because the following subcircuits failed to compare:")), ca->name (), cb->name ()); + + std::vector names_a = unverified_names (ca, verified_circuits_a); + if (! names_a.empty ()) { + msg += "\n A: " + tl::join (names_a, ","); + } + + std::vector names_b = unverified_names (cb, verified_circuits_b); + if (! names_b.empty ()) { + msg += "\n B: " + tl::join (names_b, ","); + } + + return msg; +} + static std::vector > compute_device_key (const db::Device &device, const db::NetGraph &g, bool strict) { diff --git a/src/db/db/dbNetlistCompare.h b/src/db/db/dbNetlistCompare.h index 97f6efa23..3876cc31b 100644 --- a/src/db/db/dbNetlistCompare.h +++ b/src/db/db/dbNetlistCompare.h @@ -64,7 +64,7 @@ public: * @brief There is a device class mismatch * "a" is null if there is no match for b and vice versa. */ - virtual void device_class_mismatch (const db::DeviceClass * /*a*/, const db::DeviceClass * /*b*/) { } + virtual void device_class_mismatch (const db::DeviceClass * /*a*/, const db::DeviceClass * /*b*/, const std::string & /*msg*/ = std::string ()) { } /** * @brief Begin logging for circuit a and b @@ -74,19 +74,19 @@ public: /** * @brief End logging for circuit a and b */ - virtual void end_circuit (const db::Circuit * /*a*/, const db::Circuit * /*b*/, bool /*matching*/) { } + virtual void end_circuit (const db::Circuit * /*a*/, const db::Circuit * /*b*/, bool /*matching*/, const std::string & /*msg*/ = std::string ()) { } /** * @brief Circuits are skipped * Circuits are skipped if their subcircuits could not be matched. */ - virtual void circuit_skipped (const db::Circuit * /*a*/, const db::Circuit * /*b*/) { } + virtual void circuit_skipped (const db::Circuit * /*a*/, const db::Circuit * /*b*/, const std::string & /*msg*/ = std::string ()) { } /** * @brief There is a circuit mismatch * "a" is null if there is no match for b and vice versa. */ - virtual void circuit_mismatch (const db::Circuit * /*a*/, const db::Circuit * /*b*/) { } + virtual void circuit_mismatch (const db::Circuit * /*a*/, const db::Circuit * /*b*/, const std::string & /*msg*/ = std::string ()) { } /** * @brief Nets a and b match exactly @@ -98,7 +98,7 @@ public: * Other nets might also match with a and also with b. Matching this a and b is * an arbitrary decision. */ - virtual void match_ambiguous_nets (const db::Net * /*a*/, const db::Net * /*b*/) { } + virtual void match_ambiguous_nets (const db::Net * /*a*/, const db::Net * /*b*/, const std::string & /*msg*/ = std::string ()) { } /** * @brief Net a or b doesn't match @@ -107,7 +107,7 @@ public: * nets are known not to match. Still the compare algorithm will proceed as * if these nets were equivalent to derive further matches. */ - virtual void net_mismatch (const db::Net * /*a*/, const db::Net * /*b*/) { } + virtual void net_mismatch (const db::Net * /*a*/, const db::Net * /*b*/, const std::string & /*msg*/ = std::string ()) { } /** * @brief Devices a and b match exactly @@ -128,7 +128,7 @@ public: * @brief Device a or b doesn't match * "a" is null if there is no match for b and vice versa. */ - virtual void device_mismatch (const db::Device * /*a*/, const db::Device * /*b*/) { } + virtual void device_mismatch (const db::Device * /*a*/, const db::Device * /*b*/, const std::string & /*msg*/ = std::string ()) { } /** * @brief Pins a and b of the current circuit are matched @@ -139,7 +139,7 @@ public: * @brief Pin a or b doesn't match * "a" is null if there is no match for b and vice versa. */ - virtual void pin_mismatch (const db::Pin * /*a*/, const db::Pin * /*b*/) { } + virtual void pin_mismatch (const db::Pin * /*a*/, const db::Pin * /*b*/, const std::string & /*msg*/ = std::string ()) { } /** * @brief Subcircuits a and b match exactly @@ -150,7 +150,7 @@ public: * @brief SubCircuit a or b doesn't match * "a" is null if there is no match for b and vice versa. */ - virtual void subcircuit_mismatch (const db::SubCircuit * /*a*/, const db::SubCircuit * /*b*/) { } + virtual void subcircuit_mismatch (const db::SubCircuit * /*a*/, const db::SubCircuit * /*b*/, const std::string & /*msg*/ = std::string ()) { } private: // No copying @@ -346,6 +346,7 @@ private: protected: bool compare_circuits (const db::Circuit *c1, const db::Circuit *c2, db::DeviceCategorizer &device_categorizer, db::CircuitCategorizer &circuit_categorizer, db::CircuitPinMapper &circuit_pin_mapper, const std::vector > &net_identity, bool &pin_mismatch, std::map &c12_circuit_and_pin_mapping, std::map &c22_circuit_and_pin_mapping) const; bool all_subcircuits_verified (const db::Circuit *c, const std::set &verified_circuits) const; + std::string generate_subcircuits_not_verified_warning (const db::Circuit *ca, const std::set &verified_circuits_a, const db::Circuit *cb, const std::set &verified_circuits_b) const; static void derive_pin_equivalence (const db::Circuit *ca, const db::Circuit *cb, CircuitPinMapper *circuit_pin_mapper); void do_pin_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, std::map &c12_circuit_and_pin_mapping, std::map &c22_circuit_and_pin_mapping, bool &pin_mismatch, bool &good) const; void do_device_assignment (const db::Circuit *c1, const db::NetGraph &g1, const db::Circuit *c2, const db::NetGraph &g2, const db::DeviceFilter &device_filter, DeviceCategorizer &device_categorizer, db::DeviceEquivalenceTracker &device_eq, bool &good) const; diff --git a/src/db/db/dbNetlistCrossReference.cc b/src/db/db/dbNetlistCrossReference.cc index 2343ecbfb..4ebae1072 100644 --- a/src/db/db/dbNetlistCrossReference.cc +++ b/src/db/db/dbNetlistCrossReference.cc @@ -338,9 +338,9 @@ NetlistCrossReference::establish_pair (const db::Circuit *a, const db::Circuit * } void -NetlistCrossReference::establish_pair (const db::Net *a, const db::Net *b, Status status) +NetlistCrossReference::establish_pair (const db::Net *a, const db::Net *b, Status status, const std::string &msg) { - mp_per_circuit_data->nets.push_back (NetPairData (a, b, status)); + mp_per_circuit_data->nets.push_back (NetPairData (a, b, status, msg)); if (a) { m_other_net [a] = b; } @@ -350,9 +350,9 @@ NetlistCrossReference::establish_pair (const db::Net *a, const db::Net *b, Statu } void -NetlistCrossReference::establish_pair (const db::Device *a, const db::Device *b, Status status) +NetlistCrossReference::establish_pair (const db::Device *a, const db::Device *b, Status status, const std::string &msg) { - mp_per_circuit_data->devices.push_back (DevicePairData (a, b, status)); + mp_per_circuit_data->devices.push_back (DevicePairData (a, b, status, msg)); if (a) { m_other_device [a] = b; } @@ -362,9 +362,9 @@ NetlistCrossReference::establish_pair (const db::Device *a, const db::Device *b, } void -NetlistCrossReference::establish_pair (const db::Pin *a, const db::Pin *b, Status status) +NetlistCrossReference::establish_pair (const db::Pin *a, const db::Pin *b, Status status, const std::string &msg) { - mp_per_circuit_data->pins.push_back (PinPairData (a, b, status)); + mp_per_circuit_data->pins.push_back (PinPairData (a, b, status, msg)); if (a) { m_other_pin [a] = b; } @@ -374,9 +374,9 @@ NetlistCrossReference::establish_pair (const db::Pin *a, const db::Pin *b, Statu } void -NetlistCrossReference::establish_pair (const db::SubCircuit *a, const db::SubCircuit *b, Status status) +NetlistCrossReference::establish_pair (const db::SubCircuit *a, const db::SubCircuit *b, Status status, const std::string &msg) { - mp_per_circuit_data->subcircuits.push_back (SubCircuitPairData (a, b, status)); + mp_per_circuit_data->subcircuits.push_back (SubCircuitPairData (a, b, status, msg)); if (a) { m_other_subcircuit [a] = b; } @@ -403,36 +403,37 @@ NetlistCrossReference::sort_circuit () } void -NetlistCrossReference::gen_end_circuit (const db::Circuit *, const db::Circuit *, Status status) +NetlistCrossReference::gen_end_circuit (const db::Circuit *, const db::Circuit *, Status status, const std::string &msg) { mp_per_circuit_data->status = status; + mp_per_circuit_data->msg = msg; m_current_circuits = std::make_pair((const db::Circuit *)0, (const db::Circuit *)0); mp_per_circuit_data = 0; } void -NetlistCrossReference::gen_nets (const db::Net *a, const db::Net *b, Status status) +NetlistCrossReference::gen_nets (const db::Net *a, const db::Net *b, Status status, const std::string &msg) { - establish_pair (a, b, status); + establish_pair (a, b, status, msg); } void -NetlistCrossReference::gen_devices (const db::Device *a, const db::Device *b, Status status) +NetlistCrossReference::gen_devices (const db::Device *a, const db::Device *b, Status status, const std::string &msg) { - establish_pair (a, b, status); + establish_pair (a, b, status, msg); } void -NetlistCrossReference::gen_pins (const db::Pin *a, const db::Pin *b, Status status) +NetlistCrossReference::gen_pins (const db::Pin *a, const db::Pin *b, Status status, const std::string &msg) { - establish_pair (a, b, status); + establish_pair (a, b, status, msg); } void -NetlistCrossReference::gen_subcircuits (const db::SubCircuit *a, const db::SubCircuit *b, Status status) +NetlistCrossReference::gen_subcircuits (const db::SubCircuit *a, const db::SubCircuit *b, Status status, const std::string &msg) { - establish_pair (a, b, status); + establish_pair (a, b, status, msg); } static void init_data_from_single (const db::Net *net, NetlistCrossReference::PerNetData &data, bool first) diff --git a/src/db/db/dbNetlistCrossReference.h b/src/db/db/dbNetlistCrossReference.h index ceb7ba7b5..6b7bcb239 100644 --- a/src/db/db/dbNetlistCrossReference.h +++ b/src/db/db/dbNetlistCrossReference.h @@ -61,44 +61,48 @@ public: { typedef db::Net object_type; - NetPairData (const db::Net *a, const db::Net *b, Status s) : pair (a, b), status (s) { } + NetPairData (const db::Net *a, const db::Net *b, Status s, const std::string &m) : pair (a, b), status (s), msg (m) { } NetPairData () : pair ((const db::Net *)0, (const db::Net *)0), status (None) { } std::pair pair; Status status; + std::string msg; }; struct DevicePairData { typedef db::Device object_type; - DevicePairData (const db::Device *a, const db::Device *b, Status s) : pair (a, b), status (s) { } + DevicePairData (const db::Device *a, const db::Device *b, Status s, const std::string &m) : pair (a, b), status (s), msg (m) { } DevicePairData () : pair ((const db::Device *)0, (const db::Device *)0), status (None) { } std::pair pair; Status status; + std::string msg; }; struct PinPairData { typedef db::Pin object_type; - PinPairData (const db::Pin *a, const db::Pin *b, Status s) : pair (a, b), status (s) { } + PinPairData (const db::Pin *a, const db::Pin *b, Status s, const std::string &m) : pair (a, b), status (s), msg (m) { } PinPairData () : pair ((const db::Pin *)0, (const db::Pin *)0), status (None) { } std::pair pair; Status status; + std::string msg; }; struct SubCircuitPairData { typedef db::SubCircuit object_type; - SubCircuitPairData (const db::SubCircuit *a, const db::SubCircuit *b, Status s) : pair (a, b), status (s) { } + SubCircuitPairData (const db::SubCircuit *a, const db::SubCircuit *b, Status s, const std::string &m) : pair (a, b), status (s), msg (m) { } SubCircuitPairData () : pair ((const db::SubCircuit *)0, (const db::SubCircuit *)0), status (None) { } std::pair pair; Status status; + std::string msg; }; struct PerCircuitData @@ -115,6 +119,7 @@ public: typedef subcircuit_pairs_type::const_iterator subcircuit_pairs_const_iterator; Status status; + std::string msg; net_pairs_type nets; device_pairs_type devices; pin_pairs_type pins; @@ -139,11 +144,11 @@ public: void gen_begin_netlist (const db::Netlist *a, const db::Netlist *b); void gen_end_netlist (const db::Netlist *a, const db::Netlist *b); void gen_begin_circuit (const db::Circuit *a, const db::Circuit *b); - void gen_end_circuit (const db::Circuit *a, const db::Circuit *b, Status status); - void gen_nets (const db::Net *a, const db::Net *b, Status status); - void gen_devices (const db::Device *a, const db::Device *b, Status status); - void gen_pins (const db::Pin *a, const db::Pin *b, Status status); - void gen_subcircuits (const db::SubCircuit *a, const db::SubCircuit *b, Status status); + void gen_end_circuit (const db::Circuit *a, const db::Circuit *b, Status status, const std::string &msg); + void gen_nets (const db::Net *a, const db::Net *b, Status status, const std::string &msg); + void gen_devices (const db::Device *a, const db::Device *b, Status status, const std::string &msg); + void gen_pins (const db::Pin *a, const db::Pin *b, Status status, const std::string &msg); + void gen_subcircuits (const db::SubCircuit *a, const db::SubCircuit *b, Status status, const std::string &msg); // db::NetlistCompareLogger interface virtual void begin_netlist (const db::Netlist *a, const db::Netlist *b) @@ -162,77 +167,77 @@ public: gen_begin_circuit (a, b); } - virtual void end_circuit (const db::Circuit *a, const db::Circuit *b, bool matching) + virtual void end_circuit (const db::Circuit *a, const db::Circuit *b, bool matching, const std::string &msg) { sort_circuit (); - gen_end_circuit (a, b, matching ? Match : NoMatch); + gen_end_circuit (a, b, matching ? Match : NoMatch, msg); } - virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b) + virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b, const std::string &msg) { gen_begin_circuit (a, b); - gen_end_circuit (a, b, Skipped); + gen_end_circuit (a, b, Skipped, msg); } - virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b) + virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b, const std::string &msg) { gen_begin_circuit (a, b); - gen_end_circuit (a, b, Mismatch); + gen_end_circuit (a, b, Mismatch, msg); } virtual void match_nets (const db::Net *a, const db::Net *b) { - gen_nets (a, b, Match); + gen_nets (a, b, Match, std::string ()); } - virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b) + virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b, const std::string &msg) { - gen_nets (a, b, MatchWithWarning); + gen_nets (a, b, MatchWithWarning, msg); } - virtual void net_mismatch (const db::Net *a, const db::Net *b) + virtual void net_mismatch (const db::Net *a, const db::Net *b, const std::string &msg) { - gen_nets (a, b, Mismatch); + gen_nets (a, b, Mismatch, msg); } virtual void match_devices (const db::Device *a, const db::Device *b) { - gen_devices (a, b, Match); + gen_devices (a, b, Match, std::string ()); } virtual void match_devices_with_different_parameters (const db::Device *a, const db::Device *b) { - gen_devices (a, b, MatchWithWarning); + gen_devices (a, b, MatchWithWarning, std::string ()); } virtual void match_devices_with_different_device_classes (const db::Device *a, const db::Device *b) { - gen_devices (a, b, MatchWithWarning); + gen_devices (a, b, MatchWithWarning, std::string ()); } - virtual void device_mismatch (const db::Device *a, const db::Device *b) + virtual void device_mismatch (const db::Device *a, const db::Device *b, const std::string &msg) { - gen_devices (a, b, Mismatch); + gen_devices (a, b, Mismatch, msg); } virtual void match_pins (const db::Pin *a, const db::Pin *b) { - gen_pins (a, b, Match); + gen_pins (a, b, Match, std::string ()); } - virtual void pin_mismatch (const db::Pin *a, const db::Pin *b) + virtual void pin_mismatch (const db::Pin *a, const db::Pin *b, const std::string &msg) { - gen_pins (a, b, Mismatch); + gen_pins (a, b, Mismatch, msg); } virtual void match_subcircuits (const db::SubCircuit *a, const db::SubCircuit *b) { - gen_subcircuits (a, b, Match); + gen_subcircuits (a, b, Match, std::string ()); } - virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b) + virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b, const std::string &msg) { - gen_subcircuits (a, b, Mismatch); + gen_subcircuits (a, b, Mismatch, msg); } void clear (); @@ -292,10 +297,10 @@ private: PerCircuitData *mp_per_circuit_data; void establish_pair (const db::Circuit *a, const db::Circuit *b); - void establish_pair (const db::Net *a, const db::Net *b, Status status); - void establish_pair (const db::Device *a, const db::Device *b, Status status); - void establish_pair (const db::Pin *a, const db::Pin *b, Status status); - void establish_pair (const db::SubCircuit *a, const db::SubCircuit *b, Status status); + void establish_pair (const db::Net *a, const db::Net *b, Status status, const std::string &msg); + void establish_pair (const db::Device *a, const db::Device *b, Status status, const std::string &msg); + void establish_pair (const db::Pin *a, const db::Pin *b, Status status, const std::string &msg); + void establish_pair (const db::SubCircuit *a, const db::SubCircuit *b, Status status, const std::string &msg); void sort_circuit (); void sort_netlist (); diff --git a/src/db/db/dbNetlistDeviceClasses.cc b/src/db/db/dbNetlistDeviceClasses.cc index f1c9af24c..915f03f27 100644 --- a/src/db/db/dbNetlistDeviceClasses.cc +++ b/src/db/db/dbNetlistDeviceClasses.cc @@ -35,6 +35,8 @@ static tl::RegisteredClass dct_ind (new db::device_ static tl::RegisteredClass dct_diode (new db::device_class_template ("DIODE")); static tl::RegisteredClass dct_mos3 (new db::device_class_template ("MOS3")); static tl::RegisteredClass dct_mos4 (new db::device_class_template ("MOS4")); +static tl::RegisteredClass dct_bjt3 (new db::device_class_template ("BJT3")); +static tl::RegisteredClass dct_bjt4 (new db::device_class_template ("BJT4")); // ------------------------------------------------------------------------------------ // DeviceClassTwoTerminalDevice implementation diff --git a/src/db/db/dbRegion.h b/src/db/db/dbRegion.h index b05e04184..fea1d8e8b 100644 --- a/src/db/db/dbRegion.h +++ b/src/db/db/dbRegion.h @@ -267,6 +267,16 @@ public: return mp_delegate; } + /** + * @brief Takes the underlying delegate object + */ + RegionDelegate *take_delegate () + { + RegionDelegate *delegate = mp_delegate; + mp_delegate = 0; + return delegate; + } + /** * @brief Sets the base verbosity * @@ -1132,6 +1142,19 @@ public: return Region (mp_delegate->selected_not_outside (other)); } + /** + * @brief Returns all polygons of this which are completly outside polygons from the other region and the opposite ones at the same time + * + * This method is equivalent to calling selected_outside and selected_not_outside, but faster. + * + * Merged semantics applies. + */ + std::pair selected_outside_differential (const Region &other) const + { + std::pair p = mp_delegate->selected_outside_pair (other); + return std::pair (Region (p.first), Region (p.second)); + } + /** * @brief Selects all polygons of this region which are completly inside polygons from the other region * @@ -1178,6 +1201,19 @@ public: return Region (mp_delegate->selected_not_inside (other)); } + /** + * @brief Returns all polygons of this which are completly inside polygons from the other region and the opposite ones at the same time + * + * This method is equivalent to calling selected_inside and selected_not_inside, but faster. + * + * Merged semantics applies. + */ + std::pair selected_inside_differential (const Region &other) const + { + std::pair p = mp_delegate->selected_inside_pair (other); + return std::pair (Region (p.first), Region (p.second)); + } + /** * @brief Returns all polygons of this which are enclosing polygons from the other region * @@ -1224,6 +1260,19 @@ public: return Region (mp_delegate->selected_not_enclosing (other, min_count, max_count)); } + /** + * @brief Returns all polygons of this which are completly enclosing polygons from the other region and the opposite ones at the same time + * + * This method is equivalent to calling selected_enclosing and selected_not_enclosing, but faster. + * + * Merged semantics applies. + */ + std::pair selected_enclosing_differential (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits::max ()) const + { + std::pair p = mp_delegate->selected_enclosing_pair (other, min_count, max_count); + return std::pair (Region (p.first), Region (p.second)); + } + /** * @brief Selects all polygons of this region which overlap or touch polygons from the other region * @@ -1278,6 +1327,19 @@ public: return Region (mp_delegate->selected_not_interacting (other, min_count, max_count)); } + /** + * @brief Returns all polygons of this which are interacting with polygons from the other region and the opposite ones at the same time + * + * This method is equivalent to calling selected_interacting and selected_not_interacting, but faster. + * + * Merged semantics applies. + */ + std::pair selected_interacting_differential (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits::max ()) const + { + std::pair p = mp_delegate->selected_interacting_pair (other, min_count, max_count); + return std::pair (Region (p.first), Region (p.second)); + } + /** * @brief Selects all polygons of this region which overlap or touch edges from the given edge collection * @@ -1324,6 +1386,19 @@ public: return Region (mp_delegate->selected_not_interacting (other, min_count, max_count)); } + /** + * @brief Returns all polygons of this which are interacting with edges from the other region and the opposite ones at the same time + * + * This method is equivalent to calling selected_interacting and selected_not_interacting, but faster. + * + * Merged semantics applies. + */ + std::pair selected_interacting_differential (const Edges &other, size_t min_count = 1, size_t max_count = std::numeric_limits::max ()) const + { + std::pair p = mp_delegate->selected_interacting_pair (other, min_count, max_count); + return std::pair (Region (p.first), Region (p.second)); + } + /** * @brief Selects all polygons of this region which overlap or touch texts from the text collection * @@ -1370,6 +1445,19 @@ public: return Region (mp_delegate->selected_not_interacting (other, min_count, max_count)); } + /** + * @brief Returns all polygons of this which are interacting with texts from the other region and the opposite ones at the same time + * + * This method is equivalent to calling selected_interacting and selected_not_interacting, but faster. + * + * Merged semantics applies. + */ + std::pair selected_interacting_differential (const Texts &other, size_t min_count = 1, size_t max_count = std::numeric_limits::max ()) const + { + std::pair p = mp_delegate->selected_interacting_pair (other, min_count, max_count); + return std::pair (Region (p.first), Region (p.second)); + } + /** * @brief Selects all polygons of this region which overlap polygons from the other region * @@ -1416,6 +1504,19 @@ public: return Region (mp_delegate->selected_not_overlapping (other, min_count, max_count)); } + /** + * @brief Returns all polygons of this which are overlapping polygons from the other region and the opposite ones at the same time + * + * This method is equivalent to calling selected_overlapping and selected_not_overlapping, but faster. + * + * Merged semantics applies. + */ + std::pair selected_overlapping_differential (const Region &other, size_t min_count = 1, size_t max_count = std::numeric_limits::max ()) const + { + std::pair p = mp_delegate->selected_overlapping_pair (other, min_count, max_count); + return std::pair (Region (p.first), Region (p.second)); + } + /** * @brief Returns all polygons of "other" which are inside polygons of this region * diff --git a/src/db/db/dbRegionDelegate.h b/src/db/db/dbRegionDelegate.h index 593e4ed1d..a5178f606 100644 --- a/src/db/db/dbRegionDelegate.h +++ b/src/db/db/dbRegionDelegate.h @@ -281,18 +281,25 @@ public: virtual RegionDelegate *selected_outside (const Region &other) const = 0; virtual RegionDelegate *selected_not_outside (const Region &other) const = 0; + virtual std::pair selected_outside_pair (const Region &other) const = 0; virtual RegionDelegate *selected_inside (const Region &other) const = 0; virtual RegionDelegate *selected_not_inside (const Region &other) const = 0; + virtual std::pair selected_inside_pair (const Region &other) const = 0; virtual RegionDelegate *selected_enclosing (const Region &other, size_t min_count, size_t max_count) const = 0; virtual RegionDelegate *selected_not_enclosing (const Region &other, size_t min_count, size_t max_count) const = 0; + virtual std::pair selected_enclosing_pair (const Region &other, size_t min_count, size_t max_count) const = 0; virtual RegionDelegate *selected_interacting (const Region &other, size_t min_count, size_t max_count) const = 0; virtual RegionDelegate *selected_not_interacting (const Region &other, size_t min_count, size_t max_count) const = 0; + virtual std::pair selected_interacting_pair (const Region &other, size_t min_count, size_t max_count) const = 0; virtual RegionDelegate *selected_interacting (const Edges &other, size_t min_count, size_t max_count) const = 0; virtual RegionDelegate *selected_not_interacting (const Edges &other, size_t min_count, size_t max_count) const = 0; + virtual std::pair selected_interacting_pair (const Edges &other, size_t min_count, size_t max_count) const = 0; virtual RegionDelegate *selected_interacting (const Texts &other, size_t min_count, size_t max_count) const = 0; virtual RegionDelegate *selected_not_interacting (const Texts &other, size_t min_count, size_t max_count) const = 0; + virtual std::pair selected_interacting_pair (const Texts &other, size_t min_count, size_t max_count) const = 0; virtual RegionDelegate *selected_overlapping (const Region &other, size_t min_count, size_t max_count) const = 0; virtual RegionDelegate *selected_not_overlapping (const Region &other, size_t min_count, size_t max_count) const = 0; + virtual std::pair selected_overlapping_pair (const Region &other, size_t min_count, size_t max_count) const = 0; virtual RegionDelegate *pull_inside (const Region &other) const = 0; virtual RegionDelegate *pull_interacting (const Region &other) const = 0; virtual EdgesDelegate *pull_interacting (const Edges &other) const = 0; diff --git a/src/db/db/dbRegionLocalOperations.cc b/src/db/db/dbRegionLocalOperations.cc index 0b5f68c42..4ce824442 100644 --- a/src/db/db/dbRegionLocalOperations.cc +++ b/src/db/db/dbRegionLocalOperations.cc @@ -537,8 +537,8 @@ private: } template -interacting_local_operation::interacting_local_operation (int mode, bool touching, bool inverse, size_t min_count, size_t max_count, bool other_is_merged) - : m_mode (mode), m_touching (touching), m_inverse (inverse), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count), m_other_is_merged (other_is_merged) +interacting_local_operation::interacting_local_operation (int mode, bool touching, InteractingOutputMode output_mode, size_t min_count, size_t max_count, bool other_is_merged) + : m_mode (mode), m_touching (touching), m_output_mode (output_mode), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count), m_other_is_merged (other_is_merged) { // .. nothing yet .. } @@ -552,8 +552,13 @@ db::Coord interacting_local_operation::dist () const template void interacting_local_operation::do_compute_local (db::Layout * /*layout*/, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const { - tl_assert (results.size () == 1); - std::unordered_set &result = results.front (); + if (m_output_mode == None) { + return; + } else if (m_output_mode == Positive || m_output_mode == Negative) { + tl_assert (results.size () == 1); + } else { + tl_assert (results.size () == 2); + } db::EdgeProcessor ep; @@ -652,9 +657,21 @@ void interacting_local_operation::do_compute_local (db::Layout * /*l if (c != interaction_counts.end ()) { count = c->second; } - if ((count >= m_min_count && count <= m_max_count) != m_inverse) { - const TS &subject = interactions.subject_shape (i->first); - result.insert (subject); + bool good = (count >= m_min_count && count <= m_max_count); + if (good) { + if (m_output_mode == Positive || m_output_mode == PositiveAndNegative) { + const TS &subject = interactions.subject_shape (i->first); + results [0].insert (subject); + } + } else { + if (m_output_mode == Negative) { + const TS &subject = interactions.subject_shape (i->first); + // Yes, it's "positive_result" as this is the first one. + results [0].insert (subject); + } else if (m_output_mode == PositiveAndNegative) { + const TS &subject = interactions.subject_shape (i->first); + results [1].insert (subject); + } } } } @@ -663,11 +680,22 @@ template OnEmptyIntruderHint interacting_local_operation::on_empty_intruder_hint () const { - if ((m_mode <= 0) != m_inverse) { - return OnEmptyIntruderHint::Drop; + if ((m_mode <= 0)) { + if (m_output_mode == Positive) { + return OnEmptyIntruderHint::Drop; + } else if (m_output_mode == Negative) { + return OnEmptyIntruderHint::Copy; + } else if (m_output_mode == PositiveAndNegative) { + return OnEmptyIntruderHint::CopyToSecond; + } } else { - return OnEmptyIntruderHint::Copy; + if (m_output_mode == Positive || m_output_mode == PositiveAndNegative) { + return OnEmptyIntruderHint::Copy; + } else if (m_output_mode == Negative) { + return OnEmptyIntruderHint::Drop; + } } + return OnEmptyIntruderHint::Ignore; } template @@ -761,8 +789,8 @@ template class DB_PUBLIC pull_local_operation -interacting_with_edge_local_operation::interacting_with_edge_local_operation (bool inverse, size_t min_count, size_t max_count, bool other_is_merged) - : m_inverse (inverse), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count), m_other_is_merged (other_is_merged) +interacting_with_edge_local_operation::interacting_with_edge_local_operation (InteractingOutputMode output_mode, size_t min_count, size_t max_count, bool other_is_merged) + : m_output_mode (output_mode), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count), m_other_is_merged (other_is_merged) { // .. nothing yet .. } @@ -777,6 +805,14 @@ db::Coord interacting_with_edge_local_operation::dist () const template void interacting_with_edge_local_operation::do_compute_local (db::Layout *layout, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const { + if (m_output_mode == None) { + return; + } else if (m_output_mode == Positive || m_output_mode == Negative) { + tl_assert (results.size () == 1); + } else { + tl_assert (results.size () == 2); + } + std::unordered_map counted_results; bool counting = !(m_min_count == 1 && m_max_count == std::numeric_limits::max ()); @@ -829,7 +865,7 @@ void interacting_with_edge_local_operation::do_compute_local (db::La const TR *addressable = push_polygon_to_heap (layout, subject, heap); scanner.insert1 (addressable, 0); - if (m_inverse) { + if (m_output_mode == Negative || m_output_mode == PositiveAndNegative) { inserter.init (*addressable); } @@ -839,13 +875,18 @@ void interacting_with_edge_local_operation::do_compute_local (db::La // select hits based on their count - tl_assert (results.size () == 1); - std::unordered_set &result = results.front (); - for (typename std::unordered_map::const_iterator r = counted_results.begin (); r != counted_results.end (); ++r) { bool hit = r->second >= m_min_count && r->second <= m_max_count; - if (hit != m_inverse) { - result.insert (r->first); + if (hit) { + if (m_output_mode == Positive || m_output_mode == PositiveAndNegative) { + results [0].insert (r->first); + } + } else { + if (m_output_mode == Negative) { + results [0].insert (r->first); + } else if (m_output_mode == PositiveAndNegative) { + results [1].insert (r->first); + } } } } @@ -853,10 +894,14 @@ void interacting_with_edge_local_operation::do_compute_local (db::La template OnEmptyIntruderHint interacting_with_edge_local_operation::on_empty_intruder_hint () const { - if (!m_inverse) { + if (m_output_mode == Positive) { return OnEmptyIntruderHint::Drop; - } else { + } else if (m_output_mode == Negative) { return OnEmptyIntruderHint::Copy; + } else if (m_output_mode == PositiveAndNegative) { + return OnEmptyIntruderHint::CopyToSecond; + } else { + return OnEmptyIntruderHint::Ignore; } } @@ -1000,8 +1045,8 @@ template class DB_PUBLIC pull_with_text_local_operation -interacting_with_text_local_operation::interacting_with_text_local_operation (bool inverse, size_t min_count, size_t max_count) - : m_inverse (inverse), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count) +interacting_with_text_local_operation::interacting_with_text_local_operation (InteractingOutputMode output_mode, size_t min_count, size_t max_count) + : m_output_mode (output_mode), m_min_count (std::max (size_t (1), min_count)), m_max_count (max_count) { // .. nothing yet .. } @@ -1017,6 +1062,14 @@ db::Coord interacting_with_text_local_operation::dist () const template void interacting_with_text_local_operation::do_compute_local (db::Layout *layout, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const { + if (m_output_mode == None) { + return; + } else if (m_output_mode == Positive || m_output_mode == Negative) { + tl_assert (results.size () == 1); + } else { + tl_assert (results.size () == 2); + } + std::unordered_map counted_results; bool counting = !(m_min_count == 1 && m_max_count == std::numeric_limits::max ()); @@ -1042,7 +1095,7 @@ void interacting_with_text_local_operation::do_compute_local (db::La const TR *addressable = push_polygon_to_heap (layout, interactions.subject_shape (i->first), heap); scanner.insert1 (addressable, 0); - if (m_inverse) { + if (m_output_mode == Negative || m_output_mode == PositiveAndNegative) { inserter.init (*addressable); } @@ -1052,13 +1105,19 @@ void interacting_with_text_local_operation::do_compute_local (db::La // select hits based on their count - tl_assert (results.size () == 1); - std::unordered_set &result = results.front (); - for (typename std::unordered_map::const_iterator r = counted_results.begin (); r != counted_results.end (); ++r) { bool hit = r->second >= m_min_count && r->second <= m_max_count; - if (hit != m_inverse) { - result.insert (r->first); + if (hit) { + if (m_output_mode == Positive || m_output_mode == PositiveAndNegative) { + results [0].insert (r->first); + } + } else { + if (m_output_mode == Negative) { + // Yes. It's "positive"! This is the first output. + results [0].insert (r->first); + } else if (m_output_mode == PositiveAndNegative) { + results [1].insert (r->first); + } } } } @@ -1066,10 +1125,14 @@ void interacting_with_text_local_operation::do_compute_local (db::La template OnEmptyIntruderHint interacting_with_text_local_operation::on_empty_intruder_hint () const { - if (!m_inverse) { + if (m_output_mode == Positive) { return OnEmptyIntruderHint::Drop; - } else { + } else if (m_output_mode == Negative) { return OnEmptyIntruderHint::Copy; + } else if (m_output_mode == PositiveAndNegative) { + return OnEmptyIntruderHint::CopyToSecond; + } else { + return OnEmptyIntruderHint::Ignore; } } diff --git a/src/db/db/dbRegionLocalOperations.h b/src/db/db/dbRegionLocalOperations.h index 2b3977c25..d3958e15e 100644 --- a/src/db/db/dbRegionLocalOperations.h +++ b/src/db/db/dbRegionLocalOperations.h @@ -222,12 +222,16 @@ private: typedef check_local_operation CheckLocalOperation; +enum InteractingOutputMode { + None = 0, Positive = 1, Negative = 2, PositiveAndNegative = 3 +}; + template class interacting_local_operation : public local_operation { public: - interacting_local_operation (int mode, bool touching, bool inverse, size_t min_count, size_t max_count, bool other_is_merged); + interacting_local_operation (int mode, bool touching, InteractingOutputMode output_mode, size_t min_count, size_t max_count, bool other_is_merged); virtual db::Coord dist () const; virtual void do_compute_local (db::Layout * /*layout*/, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const; @@ -237,7 +241,7 @@ public: private: int m_mode; bool m_touching; - bool m_inverse; + InteractingOutputMode m_output_mode; size_t m_min_count, m_max_count; bool m_other_is_merged; }; @@ -268,7 +272,7 @@ class interacting_with_edge_local_operation : public local_operation { public: - interacting_with_edge_local_operation (bool inverse, size_t min_count, size_t max_count, bool other_is_merged); + interacting_with_edge_local_operation (InteractingOutputMode output_mode, size_t min_count, size_t max_count, bool other_is_merged); virtual db::Coord dist () const; virtual void do_compute_local (db::Layout *layout, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const; @@ -276,7 +280,7 @@ public: virtual std::string description () const; private: - bool m_inverse; + InteractingOutputMode m_output_mode; size_t m_min_count, m_max_count; bool m_other_is_merged; }; @@ -303,7 +307,7 @@ class interacting_with_text_local_operation : public local_operation { public: - interacting_with_text_local_operation (bool inverse, size_t min_count, size_t max_count); + interacting_with_text_local_operation (InteractingOutputMode output_mode, size_t min_count, size_t max_count); virtual db::Coord dist () const; virtual void do_compute_local (db::Layout *layout, const shape_interactions &interactions, std::vector > &results, size_t /*max_vertex_count*/, double /*area_ratio*/) const; @@ -311,7 +315,7 @@ public: virtual std::string description () const; private: - bool m_inverse; + InteractingOutputMode m_output_mode; size_t m_min_count, m_max_count; }; diff --git a/src/db/db/dbTestSupport.cc b/src/db/db/dbTestSupport.cc index 546c196f2..ad0cf1ab9 100644 --- a/src/db/db/dbTestSupport.cc +++ b/src/db/db/dbTestSupport.cc @@ -190,17 +190,17 @@ public: m_circuit = circuit2str (a) + " vs. " + circuit2str (b); } - virtual void device_class_mismatch (const db::DeviceClass *a, const db::DeviceClass *b) + virtual void device_class_mismatch (const db::DeviceClass *a, const db::DeviceClass *b, const std::string & /*msg*/) { out ("device_class_mismatch " + device_class2str (a) + " " + device_class2str (b)); } - virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b) + virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b, const std::string & /*msg*/) { out ("circuit_skipped " + circuit2str (a) + " " + circuit2str (b)); } - virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b) + virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b, const std::string & /*msg*/) { out ("circuit_mismatch " + circuit2str (a) + " " + circuit2str (b)); } @@ -210,12 +210,12 @@ public: out ("match_nets " + net2str (a) + " " + net2str (b)); } - virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b) + virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b, const std::string & /*msg*/) { out ("match_ambiguous_nets " + net2str (a) + " " + net2str (b)); } - virtual void net_mismatch (const db::Net *a, const db::Net *b) + virtual void net_mismatch (const db::Net *a, const db::Net *b, const std::string & /*msg*/) { out ("net_mismatch " + net2str (a) + " " + net2str (b)); } @@ -225,7 +225,7 @@ public: out ("match_devices " + device2str (a) + " " + device2str (b)); } - virtual void device_mismatch (const db::Device *a, const db::Device *b) + virtual void device_mismatch (const db::Device *a, const db::Device *b, const std::string & /*msg*/) { out ("device_mismatch " + device2str (a) + " " + device2str (b)); } @@ -245,7 +245,7 @@ public: out ("match_pins " + pin2str (a) + " " + pin2str (b)); } - virtual void pin_mismatch (const db::Pin *a, const db::Pin *b) + virtual void pin_mismatch (const db::Pin *a, const db::Pin *b, const std::string & /*msg*/) { out ("pin_mismatch " + pin2str (a) + " " + pin2str (b)); } @@ -255,7 +255,7 @@ public: out ("match_subcircuits " + subcircuit2str (a) + " " + subcircuit2str (b)); } - virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b) + virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b, const std::string & /*msg*/) { out ("subcircuit_mismatch " + subcircuit2str (a) + " " + subcircuit2str (b)); } diff --git a/src/db/db/gsiDeclDbNetlistCompare.cc b/src/db/db/gsiDeclDbNetlistCompare.cc index de1a0b64c..ee10d9365 100644 --- a/src/db/db/gsiDeclDbNetlistCompare.cc +++ b/src/db/db/gsiDeclDbNetlistCompare.cc @@ -66,18 +66,18 @@ public: db::NetlistCompareLogger::end_netlist (a, b); } - virtual void device_class_mismatch (const db::DeviceClass *a, const db::DeviceClass *b) + virtual void device_class_mismatch (const db::DeviceClass *a, const db::DeviceClass *b, const std::string &msg) { if (cb_device_class_mismatch.can_issue ()) { - cb_device_class_mismatch.issue (&GenericNetlistCompareLogger::device_class_mismatch_fb, a, b); + cb_device_class_mismatch.issue (&GenericNetlistCompareLogger::device_class_mismatch_fb, a, b, msg); } else { db::NetlistCompareLogger::device_class_mismatch (a, b); } } - void device_class_mismatch_fb (const db::DeviceClass *a, const db::DeviceClass *b) + void device_class_mismatch_fb (const db::DeviceClass *a, const db::DeviceClass *b, const std::string &msg) { - db::NetlistCompareLogger::device_class_mismatch (a, b); + db::NetlistCompareLogger::device_class_mismatch (a, b, msg); } virtual void begin_circuit (const db::Circuit *a, const db::Circuit *b) @@ -94,46 +94,46 @@ public: db::NetlistCompareLogger::begin_circuit (a, b); } - virtual void end_circuit (const db::Circuit *a, const db::Circuit *b, bool matching) + virtual void end_circuit (const db::Circuit *a, const db::Circuit *b, bool matching, const std::string &msg) { if (cb_end_circuit.can_issue ()) { - cb_end_circuit.issue (&GenericNetlistCompareLogger::end_circuit_fb, a, b, matching); + cb_end_circuit.issue (&GenericNetlistCompareLogger::end_circuit_fb, a, b, matching, msg); } else { db::NetlistCompareLogger::end_circuit (a, b, matching); } } - void end_circuit_fb (const db::Circuit *a, const db::Circuit *b, bool matching) + void end_circuit_fb (const db::Circuit *a, const db::Circuit *b, bool matching, const std::string &msg) { - db::NetlistCompareLogger::end_circuit (a, b, matching); + db::NetlistCompareLogger::end_circuit (a, b, matching, msg); } - virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b) + virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b, const std::string &msg) { if (cb_circuit_skipped.can_issue ()) { - cb_circuit_skipped.issue (&GenericNetlistCompareLogger::circuit_skipped_fb, a, b); + cb_circuit_skipped.issue (&GenericNetlistCompareLogger::circuit_skipped_fb, a, b, msg); } else { db::NetlistCompareLogger::circuit_skipped (a, b); } } - void circuit_skipped_fb (const db::Circuit *a, const db::Circuit *b) + void circuit_skipped_fb (const db::Circuit *a, const db::Circuit *b, const std::string &msg) { - db::NetlistCompareLogger::circuit_skipped (a, b); + db::NetlistCompareLogger::circuit_skipped (a, b, msg); } - virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b) + virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b, const std::string &msg) { if (cb_circuit_mismatch.can_issue ()) { - cb_circuit_mismatch.issue (&GenericNetlistCompareLogger::circuit_mismatch_fb, a, b); + cb_circuit_mismatch.issue (&GenericNetlistCompareLogger::circuit_mismatch_fb, a, b, msg); } else { db::NetlistCompareLogger::circuit_mismatch (a, b); } } - void circuit_mismatch_fb (const db::Circuit *a, const db::Circuit *b) + void circuit_mismatch_fb (const db::Circuit *a, const db::Circuit *b, const std::string &msg) { - db::NetlistCompareLogger::circuit_mismatch (a, b); + db::NetlistCompareLogger::circuit_mismatch (a, b, msg); } virtual void match_nets (const db::Net *a, const db::Net *b) @@ -150,32 +150,32 @@ public: db::NetlistCompareLogger::match_nets (a, b); } - virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b) + virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b, const std::string &msg) { if (cb_match_ambiguous_nets.can_issue ()) { - cb_match_ambiguous_nets.issue (&GenericNetlistCompareLogger::match_ambiguous_nets_fb, a, b); + cb_match_ambiguous_nets.issue (&GenericNetlistCompareLogger::match_ambiguous_nets_fb, a, b, msg); } else { db::NetlistCompareLogger::match_ambiguous_nets (a, b); } } - void match_ambiguous_nets_fb (const db::Net *a, const db::Net *b) + void match_ambiguous_nets_fb (const db::Net *a, const db::Net *b, const std::string &msg) { - db::NetlistCompareLogger::match_ambiguous_nets (a, b); + db::NetlistCompareLogger::match_ambiguous_nets (a, b, msg); } - virtual void net_mismatch (const db::Net *a, const db::Net *b) + virtual void net_mismatch (const db::Net *a, const db::Net *b, const std::string &msg) { if (cb_net_mismatch.can_issue ()) { - cb_net_mismatch.issue (&GenericNetlistCompareLogger::net_mismatch_fb, a, b); + cb_net_mismatch.issue (&GenericNetlistCompareLogger::net_mismatch_fb, a, b, msg); } else { db::NetlistCompareLogger::net_mismatch (a, b); } } - void net_mismatch_fb (const db::Net *a, const db::Net *b) + void net_mismatch_fb (const db::Net *a, const db::Net *b, const std::string &msg) { - db::NetlistCompareLogger::net_mismatch (a, b); + db::NetlistCompareLogger::net_mismatch (a, b, msg); } virtual void match_devices (const db::Device *a, const db::Device *b) @@ -220,18 +220,18 @@ public: db::NetlistCompareLogger::match_devices_with_different_device_classes (a, b); } - virtual void device_mismatch (const db::Device *a, const db::Device *b) + virtual void device_mismatch (const db::Device *a, const db::Device *b, const std::string &msg) { if (cb_device_mismatch.can_issue ()) { - cb_device_mismatch.issue (&GenericNetlistCompareLogger::device_mismatch_fb, a, b); + cb_device_mismatch.issue (&GenericNetlistCompareLogger::device_mismatch_fb, a, b, msg); } else { db::NetlistCompareLogger::device_mismatch (a, b); } } - void device_mismatch_fb (const db::Device *a, const db::Device *b) + void device_mismatch_fb (const db::Device *a, const db::Device *b, const std::string &msg) { - db::NetlistCompareLogger::device_mismatch (a, b); + db::NetlistCompareLogger::device_mismatch (a, b, msg); } virtual void match_pins (const db::Pin *a, const db::Pin *b) @@ -248,18 +248,18 @@ public: db::NetlistCompareLogger::match_pins (a, b); } - virtual void pin_mismatch (const db::Pin *a, const db::Pin *b) + virtual void pin_mismatch (const db::Pin *a, const db::Pin *b, const std::string &msg) { if (cb_pin_mismatch.can_issue ()) { - cb_pin_mismatch.issue (&GenericNetlistCompareLogger::pin_mismatch_fb, a, b); + cb_pin_mismatch.issue (&GenericNetlistCompareLogger::pin_mismatch_fb, a, b, msg); } else { db::NetlistCompareLogger::pin_mismatch (a, b); } } - void pin_mismatch_fb (const db::Pin *a, const db::Pin *b) + void pin_mismatch_fb (const db::Pin *a, const db::Pin *b, const std::string &msg) { - db::NetlistCompareLogger::pin_mismatch (a, b); + db::NetlistCompareLogger::pin_mismatch (a, b, msg); } virtual void match_subcircuits (const db::SubCircuit *a, const db::SubCircuit *b) @@ -276,18 +276,18 @@ public: db::NetlistCompareLogger::match_subcircuits (a, b); } - virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b) + virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b, const std::string &msg) { if (cb_subcircuit_mismatch.can_issue ()) { - cb_subcircuit_mismatch.issue (&GenericNetlistCompareLogger::subcircuit_mismatch_fb, a, b); + cb_subcircuit_mismatch.issue (&GenericNetlistCompareLogger::subcircuit_mismatch_fb, a, b, msg); } else { db::NetlistCompareLogger::subcircuit_mismatch (a, b); } } - void subcircuit_mismatch_fb (const db::SubCircuit *a, const db::SubCircuit *b) + void subcircuit_mismatch_fb (const db::SubCircuit *a, const db::SubCircuit *b, const std::string &msg) { - db::NetlistCompareLogger::subcircuit_mismatch (a, b); + db::NetlistCompareLogger::subcircuit_mismatch (a, b, msg); } gsi::Callback cb_begin_netlist; @@ -339,7 +339,7 @@ Class decl_GenericNetlistCompareLogger (decl_dbNetl "@brief This function is called at the end of the compare process.\n" "This method is called once when the compare run ended.\n" ) + - gsi::callback ("device_class_mismatch", &GenericNetlistCompareLogger::device_class_mismatch, &GenericNetlistCompareLogger::cb_device_class_mismatch, gsi::arg ("a"), gsi::arg ("b"), + gsi::callback ("device_class_mismatch", &GenericNetlistCompareLogger::device_class_mismatch, &GenericNetlistCompareLogger::cb_device_class_mismatch, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("msg"), "@brief This function is called when device classes can't be compared.\n" "This method is called when a device class can't be mapped to a partner in the other netlist. In this case, " "this method is called with the one device class and nil for the other class.\n" @@ -354,19 +354,19 @@ Class decl_GenericNetlistCompareLogger (decl_dbNetl "some or all subcircuits the pin assignment can't be derived. In this case, \\circuit_skipped will be called once " "instead of \\begin_circuit and \\end_circuit.\n" ) + - gsi::callback ("end_circuit", &GenericNetlistCompareLogger::end_circuit, &GenericNetlistCompareLogger::cb_end_circuit, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("matching"), + gsi::callback ("end_circuit", &GenericNetlistCompareLogger::end_circuit, &GenericNetlistCompareLogger::cb_end_circuit, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("matching"), gsi::arg ("msg"), "@brief This function is called at the end of the compare process.\n" "The 'matching' argument indicates whether the circuits have been identified as identical.\n" "See \\begin_circuit for details." ) + - gsi::callback ("circuit_skipped", &GenericNetlistCompareLogger::circuit_skipped, &GenericNetlistCompareLogger::cb_circuit_skipped, gsi::arg ("a"), gsi::arg ("b"), + gsi::callback ("circuit_skipped", &GenericNetlistCompareLogger::circuit_skipped, &GenericNetlistCompareLogger::cb_circuit_skipped, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("msg"), "@brief This function is called when circuits can't be compared.\n" "If there is a known circuit pair, but the circuits can be compared - for example because subcircuits can't be identified - this method will be called with " "both circuits.\n" "\n" "This method is called instead of \\begin_circuit and \\end_circuit." ) + - gsi::callback ("circuit_mismatch", &GenericNetlistCompareLogger::circuit_mismatch, &GenericNetlistCompareLogger::cb_circuit_mismatch, gsi::arg ("a"), gsi::arg ("b"), + gsi::callback ("circuit_mismatch", &GenericNetlistCompareLogger::circuit_mismatch, &GenericNetlistCompareLogger::cb_circuit_mismatch, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("msg"), "@brief This function is called when circuits can't be compared.\n" "This method is called when a circuit can't be mapped to a partner in the other netlist. In this case, " "this method is called with the one circuit and nil for the other circuit.\n" @@ -379,13 +379,13 @@ Class decl_GenericNetlistCompareLogger (decl_dbNetl "If the nets can be paired, but this match is ambiguous, \\match_ambiguous_nets will be called instead.\n" "If nets can't be matched to a partner, \\net_mismatch will be called.\n" ) + - gsi::callback ("match_ambiguous_nets", &GenericNetlistCompareLogger::match_ambiguous_nets, &GenericNetlistCompareLogger::cb_match_ambiguous_nets, gsi::arg ("a"), gsi::arg ("b"), + gsi::callback ("match_ambiguous_nets", &GenericNetlistCompareLogger::match_ambiguous_nets, &GenericNetlistCompareLogger::cb_match_ambiguous_nets, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("msg"), "@brief This function is called when two nets are identified, but this choice is ambiguous.\n" "This choice is a last-resort fallback to allow continuation of the compare procedure. It is likely that this " "compare will fail later. Looking for ambiguous nets allows deduction of the origin of this faulty decision. " "See \\match_nets for more details." ) + - gsi::callback ("net_mismatch", &GenericNetlistCompareLogger::net_mismatch, &GenericNetlistCompareLogger::cb_net_mismatch, gsi::arg ("a"), gsi::arg ("b"), + gsi::callback ("net_mismatch", &GenericNetlistCompareLogger::net_mismatch, &GenericNetlistCompareLogger::cb_net_mismatch, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("msg"), "@brief This function is called when a net can't be paired.\n" "This method will be called, if a net cannot be identified as identical with another net. The corresponding argument " "will identify the net and source netlist. The other argument will be nil.\n" @@ -409,7 +409,7 @@ Class decl_GenericNetlistCompareLogger (decl_dbNetl "@brief This function is called when two devices are identified but have different device classes.\n" "See \\match_devices for details.\n" ) + - gsi::callback ("device_mismatch", &GenericNetlistCompareLogger::device_mismatch, &GenericNetlistCompareLogger::cb_device_mismatch, gsi::arg ("a"), gsi::arg ("b"), + gsi::callback ("device_mismatch", &GenericNetlistCompareLogger::device_mismatch, &GenericNetlistCompareLogger::cb_device_mismatch, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("msg"), "@brief This function is called when two devices can't be paired.\n" "This will report the device considered in a or b. The other argument is nil. " "See \\match_devices for details.\n" @@ -419,7 +419,7 @@ Class decl_GenericNetlistCompareLogger (decl_dbNetl "If two pins are identified as a corresponding pair, this method will be called with both pins.\n" "If pins can't be matched, \\pin_mismatch will be called with the one pin considered and the other pin being nil." ) + - gsi::callback ("pin_mismatch", &GenericNetlistCompareLogger::pin_mismatch, &GenericNetlistCompareLogger::cb_pin_mismatch, gsi::arg ("a"), gsi::arg ("b"), + gsi::callback ("pin_mismatch", &GenericNetlistCompareLogger::pin_mismatch, &GenericNetlistCompareLogger::cb_pin_mismatch, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("msg"), "@brief This function is called when two pins can't be paired.\n" "This will report the pin considered in a or b. The other argument is nil. " "See \\match_pins for details.\n" @@ -429,7 +429,7 @@ Class decl_GenericNetlistCompareLogger (decl_dbNetl "If two subcircuits are identified as a corresponding pair, this method will be called with both subcircuits.\n" "If subcircuits can't be matched, \\subcircuit_mismatch will be called with the one subcircuit considered and the other subcircuit being nil." ) + - gsi::callback ("subcircuit_mismatch", &GenericNetlistCompareLogger::subcircuit_mismatch, &GenericNetlistCompareLogger::cb_subcircuit_mismatch, gsi::arg ("a"), gsi::arg ("b"), + gsi::callback ("subcircuit_mismatch", &GenericNetlistCompareLogger::subcircuit_mismatch, &GenericNetlistCompareLogger::cb_subcircuit_mismatch, gsi::arg ("a"), gsi::arg ("b"), gsi::arg ("msg"), "@brief This function is called when two subcircuits can't be paired.\n" "This will report the subcircuit considered in a or b. The other argument is nil. " "See \\match_subcircuits for details.\n" diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index 6614be324..d1e7cdd87 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -610,15 +610,53 @@ static db::EdgePairs separation2 (const db::Region *r, const db::Region &other, ); } +static inline std::vector as_2region_vector (const std::pair &rp) +{ + std::vector res; + res.reserve (2); + res.push_back (db::Region (const_cast (rp.first).take_delegate ())); + res.push_back (db::Region (const_cast (rp.second).take_delegate ())); + return res; +} + static std::vector andnot (const db::Region *r, const db::Region &other) { - std::pair rp = r->andnot (other); + return as_2region_vector (r->andnot (other)); +} - std::vector res; - res.resize (2, db::Region ()); - res [0] = rp.first; - res [1] = rp.second; - return res; +static std::vector split_inside (const db::Region *r, const db::Region &other) +{ + return as_2region_vector (r->selected_inside_differential (other)); +} + +static std::vector split_outside (const db::Region *r, const db::Region &other) +{ + return as_2region_vector (r->selected_outside_differential (other)); +} + +static std::vector split_overlapping (const db::Region *r, const db::Region &other, size_t min_count, size_t max_count) +{ + return as_2region_vector (r->selected_overlapping_differential (other, min_count, max_count)); +} + +static std::vector split_covering (const db::Region *r, const db::Region &other, size_t min_count, size_t max_count) +{ + return as_2region_vector (r->selected_enclosing_differential (other, min_count, max_count)); +} + +static std::vector split_interacting_with_region (const db::Region *r, const db::Region &other, size_t min_count, size_t max_count) +{ + return as_2region_vector (r->selected_interacting_differential (other, min_count, max_count)); +} + +static std::vector split_interacting_with_edges (const db::Region *r, const db::Edges &other, size_t min_count, size_t max_count) +{ + return as_2region_vector (r->selected_interacting_differential (other, min_count, max_count)); +} + +static std::vector split_interacting_with_texts (const db::Region *r, const db::Texts &other, size_t min_count, size_t max_count) +{ + return as_2region_vector (r->selected_interacting_differential (other, min_count, max_count)); } template @@ -681,6 +719,7 @@ int po_any (); extern Class decl_dbShapeCollection; + Class decl_Region (decl_dbShapeCollection, "db", "Region", constructor ("new", &new_v, "@brief Default constructor\n" @@ -903,7 +942,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "polygons which have the given perimeter are returned. If \"inverse\" is true, " "polygons not having the given perimeter are returned.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method_ext ("with_perimeter", with_perimeter2, gsi::arg ("min_perimeter"), gsi::arg ("max_perimeter"), gsi::arg ("inverse"), "@brief Filter the polygons by perimeter\n" @@ -915,7 +954,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "If you don't want to specify a lower or upper limit, pass nil to that parameter.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method_ext ("with_area", with_area1, gsi::arg ("area"), gsi::arg ("inverse"), "@brief Filter the polygons by area\n" @@ -923,7 +962,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "polygons which have the given area are returned. If \"inverse\" is true, " "polygons not having the given area are returned.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method_ext ("with_area", with_area2, gsi::arg ("min_area"), gsi::arg ("max_area"), gsi::arg ("inverse"), "@brief Filter the polygons by area\n" @@ -935,7 +974,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "If you don't want to specify a lower or upper limit, pass nil to that parameter.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method_ext ("with_holes", with_holes1, gsi::arg ("nholes"), gsi::arg ("inverse"), "@brief Filters the polygons by their number of holes\n" @@ -943,7 +982,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "polygons which have the given number of holes are returned. If \"inverse\" is true, " "polygons not having the given of holes are returned.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "This method has been introduced in version 0.27.\n" ) + @@ -957,7 +996,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "If you don't want to specify a lower or upper limit, pass nil to that parameter.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "This method has been introduced in version 0.27.\n" ) + @@ -967,7 +1006,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "polygons whose bounding box has the given width are returned. If \"inverse\" is true, " "polygons whose bounding box does not have the given width are returned.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method_ext ("with_bbox_width", with_bbox_width2, gsi::arg ("min_width"), gsi::arg ("max_width"), gsi::arg ("inverse"), "@brief Filter the polygons by bounding box width\n" @@ -977,7 +1016,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "If you don't want to specify a lower or upper limit, pass nil to that parameter.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method_ext ("with_bbox_height", with_bbox_height1, gsi::arg ("height"), gsi::arg ("inverse"), "@brief Filter the polygons by bounding box height\n" @@ -985,7 +1024,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "polygons whose bounding box has the given height are returned. If \"inverse\" is true, " "polygons whose bounding box does not have the given height are returned.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method_ext ("with_bbox_height", with_bbox_height2, gsi::arg ("min_height"), gsi::arg ("max_height"), gsi::arg ("inverse"), "@brief Filter the polygons by bounding box height\n" @@ -995,7 +1034,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "If you don't want to specify a lower or upper limit, pass nil to that parameter.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method_ext ("with_bbox_min", with_bbox_min1, gsi::arg ("dim"), gsi::arg ("inverse"), "@brief Filter the polygons by bounding box width or height, whichever is smaller\n" @@ -1004,7 +1043,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "are returned. " "If \"inverse\" is true, all polygons not matching this criterion are returned." "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method_ext ("with_bbox_min", with_bbox_min2, gsi::arg ("min_dim"), gsi::arg ("max_dim"), gsi::arg ("inverse"), "@brief Filter the polygons by bounding box width or height, whichever is smaller\n" @@ -1015,7 +1054,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "If you don't want to specify a lower or upper limit, pass nil to that parameter.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method_ext ("with_bbox_max", with_bbox_max1, gsi::arg ("dim"), gsi::arg ("inverse"), "@brief Filter the polygons by bounding box width or height, whichever is larger\n" @@ -1024,7 +1063,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "are returned. " "If \"inverse\" is true, all polygons not matching this criterion are returned." "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method_ext ("with_bbox_max", with_bbox_max2, gsi::arg ("min_dim"), gsi::arg ("max_dim"), gsi::arg ("inverse"), "@brief Filter the polygons by bounding box width or height, whichever is larger\n" @@ -1035,7 +1074,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "If you don't want to specify a lower or upper limit, pass nil to that parameter.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method_ext ("with_bbox_aspect_ratio", with_bbox_aspect_ratio1, gsi::arg ("ratio"), gsi::arg ("inverse"), "@brief Filters the polygons by the aspect ratio of their bounding boxes\n" @@ -1046,7 +1085,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "With 'inverse' set to false, this version filters polygons which have a bounding box aspect ratio equal to the given value. " "With 'inverse' set to true, all other polygons will be returned.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "This method has been introduced in version 0.27.\n" ) + @@ -1062,7 +1101,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "If you don't want to specify a lower or upper limit, pass nil to that parameter.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "This method has been introduced in version 0.27.\n" ) + @@ -1075,7 +1114,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "With 'inverse' set to false, this version filters polygons which have an area ratio equal to the given value. " "With 'inverse' set to true, all other polygons will be returned.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "This method has been introduced in version 0.27.\n" ) + @@ -1091,7 +1130,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "If you don't want to specify a lower or upper limit, pass nil to that parameter.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "This method has been introduced in version 0.27.\n" ) + @@ -1105,7 +1144,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "With 'inverse' set to false, this version filters polygons which have a relative height equal to the given value. " "With 'inverse' set to true, all other polygons will be returned.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "This method has been introduced in version 0.27.\n" ) + @@ -1122,7 +1161,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "If you don't want to specify a lower or upper limit, pass nil to that parameter.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "This method has been introduced in version 0.27.\n" ) + @@ -1130,7 +1169,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "@brief Returns a region containing those parts of polygons which are \"strange\"\n" "Strange parts of polygons are self-overlapping parts or non-orientable parts (i.e. in the \"8\" configuration).\n" "\n" - "Merged semantics does not apply for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics does not apply for this method (see \\merged_semantics= for a description of this concept)\n" ) + method ("snapped", &db::Region::snapped, gsi::arg ("gx"), gsi::arg ("gy"), "@brief Returns the snapped region\n" @@ -1143,7 +1182,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "If gx or gy is 0, no snapping happens in that direction.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method ("scaled_and_snapped", &db::Region::scaled_and_snapped, gsi::arg ("gx"), gsi::arg ("mx"), gsi::arg ("dx"), gsi::arg ("gy"),gsi::arg ("my"), gsi::arg ("dy"), "@brief Returns the scaled and snapped region\n" @@ -1159,7 +1198,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "If gx or gy is 0, the result is brought on a grid of 1.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "This method has been introduced in version 0.26.1." ) + @@ -1171,7 +1210,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "If gx or gy is 0 or less, the grid is not checked in that direction.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method_ext ("with_angle", angle_check1, gsi::arg ("angle"), gsi::arg ("inverse"), "@brief Returns markers on every corner with the given angle (or not with the given angle)\n" @@ -1181,7 +1220,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "The edge pair objects returned will contain both edges forming the angle.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method_ext ("with_angle", angle_check2, gsi::arg ("amin"), gsi::arg ("amax"), gsi::arg ("inverse"), "@brief Returns markers on every corner with an angle of more than amin and less than amax (or the opposite)\n" @@ -1191,7 +1230,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "The edge pair objects returned will contain both edges forming the angle.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method ("insert", (void (db::Region::*)(const db::Box &)) &db::Region::insert, gsi::arg ("box"), "@brief Inserts a box\n" @@ -1266,7 +1305,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "The boxes will not be merged, so it is possible to determine overlaps " "of these boxes for example.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method_ext ("extents", &extents1, gsi::arg ("d"), "@brief Returns a region with the enlarged bounding boxes of the polygons\n" @@ -1275,7 +1314,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "The boxes will not be merged, so it is possible to determine overlaps " "of these boxes for example.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method_ext ("extents", &extents2, gsi::arg ("dx"), gsi::arg ("dy"), "@brief Returns a region with the enlarged bounding boxes of the polygons\n" @@ -1284,7 +1323,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "The boxes will not be merged, so it is possible to determine overlaps " "of these boxes for example.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method_ext ("extent_refs", &extent_refs, "@hide\n" @@ -1446,7 +1485,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "The mode defines at which bending angle cutoff occurs \n" "(0:>0, 1:>45, 2:>90, 3:>135, 4:>approx. 168, other:>approx. 179)\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "The result is a set of polygons which may be overlapping, but are not self-\n" "intersecting. Polygons may overlap afterwards because they grew big enough to overlap their neighbors.\n" @@ -1468,7 +1507,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "This method is equivalent to \"size(d, d, mode)\".\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method_ext ("size", size_ext, gsi::arg ("d"), "@brief Isotropic sizing (biasing)\n" @@ -1477,7 +1516,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "This method is equivalent to \"size(d, d, 2)\".\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method ("sized", (db::Region (db::Region::*) (db::Coord, db::Coord, unsigned int) const) &db::Region::sized, gsi::arg ("dx"), gsi::arg ("dy"), gsi::arg ("mode"), "@brief Returns the anisotropically sized region\n" @@ -1486,7 +1525,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "This method is returns the sized region (see \\size), but does not modify self.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method ("sized", (db::Region (db::Region::*) (db::Coord, unsigned int) const) &db::Region::sized, gsi::arg ("d"), gsi::arg ("mode"), "@brief Returns the isotropically sized region\n" @@ -1495,7 +1534,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "This method is returns the sized region (see \\size), but does not modify self.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method_ext ("sized", sized_ext, gsi::arg ("d"), "@brief Isotropic sizing (biasing)\n" @@ -1504,7 +1543,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "This method is equivalent to \"sized(d, d, 2)\".\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method_ext ("andnot", &andnot, gsi::arg ("other"), "@brief Returns the boolean AND and NOT between self and the other region\n" @@ -1601,7 +1640,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "@return A new region containing the polygons which are covering polygons from the other region\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "This attribute is sometimes called 'enclosing' instead of 'covering', but this term is reserved for the respective DRC function.\n" "\n" @@ -1612,18 +1651,28 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "@return A new region containing the polygons which are not covering polygons from the other region\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "This attribute is sometimes called 'enclosing' instead of 'covering', but this term is reserved for the respective DRC function.\n" "\n" "This method has been introduced in version 0.27." ) + + method_ext ("split_covering", &split_covering, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits::max ()), "unlimited"), + "@brief Returns the polygons of this region which are completely covering polygons from the other region and the ones which are not at the same time\n" + "\n" + "@return Two new regions: the first containing the result of \\covering, the second the result of \\not_covering\n" + "\n" + "This method is equivalent to calling \\covering and \\not_covering, but is faster when both results are required.\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept).\n" + "\n" + "This method has been introduced in version 0.27." + ) + method ("select_covering", &db::Region::select_enclosing, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits::max ()), "unlimited"), "@brief Selects the polygons of this region which are completely covering polygons from the other region\n" "\n" "@return The region after the polygons have been selected (self)\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "This attribute is sometimes called 'enclosing' instead of 'covering', but this term is reserved for the respective DRC function.\n" "\n" @@ -1634,7 +1683,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "@return The region after the polygons have been selected (self)\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "This attribute is sometimes called 'enclosing' instead of 'covering', but this term is reserved for the respective DRC function.\n" "\n" @@ -1645,56 +1694,76 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "@return A new region containing the polygons which are inside polygons from the other region\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method ("not_inside", &db::Region::selected_not_inside, gsi::arg ("other"), "@brief Returns the polygons of this region which are not completely inside polygons from the other region\n" "\n" "@return A new region containing the polygons which are not inside polygons from the other region\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + + method_ext ("split_inside", &split_inside, gsi::arg ("other"), + "@brief Returns the polygons of this region which are completely inside polygons from the other region and the ones which are not at the same time\n" + "\n" + "@return Two new regions: the first containing the result of \\inside, the second the result of \\not_inside\n" + "\n" + "This method is equivalent to calling \\inside and \\not_inside, but is faster when both results are required.\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept).\n" + "\n" + "This method has been introduced in version 0.27." + ) + method ("select_inside", &db::Region::select_inside, gsi::arg ("other"), "@brief Selects the polygons of this region which are completely inside polygons from the other region\n" "\n" "@return The region after the polygons have been selected (self)\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method ("select_not_inside", &db::Region::select_not_inside, gsi::arg ("other"), "@brief Selects the polygons of this region which are not completely inside polygons from the other region\n" "\n" "@return The region after the polygons have been selected (self)\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method ("outside", &db::Region::selected_outside, gsi::arg ("other"), "@brief Returns the polygons of this region which are completely outside polygons from the other region\n" "\n" "@return A new region containing the polygons which are outside polygons from the other region\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method ("not_outside", &db::Region::selected_not_outside, gsi::arg ("other"), "@brief Returns the polygons of this region which are not completely outside polygons from the other region\n" "\n" "@return A new region containing the polygons which are not outside polygons from the other region\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + + method_ext ("split_outside", &split_outside, gsi::arg ("other"), + "@brief Returns the polygons of this region which are completely outside polygons from the other region and the ones which are not at the same time\n" + "\n" + "@return Two new regions: the first containing the result of \\outside, the second the result of \\not_outside\n" + "\n" + "This method is equivalent to calling \\outside and \\not_outside, but is faster when both results are required.\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept).\n" + "\n" + "This method has been introduced in version 0.27." + ) + method ("select_outside", &db::Region::select_outside, gsi::arg ("other"), "@brief Selects the polygons of this region which are completely outside polygons from the other region\n" "\n" "@return The region after the polygons have been selected (self)\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method ("select_not_outside", &db::Region::select_not_outside, gsi::arg ("other"), "@brief Selects the polygons of this region which are not completely outside polygons from the other region\n" "\n" "@return The region after the polygons have been selected (self)\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method ("interacting", (db::Region (db::Region::*) (const db::Region &, size_t, size_t) const) &db::Region::selected_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits::max ()), "unlimited"), "@brief Returns the polygons of this region which overlap or touch polygons from the other region\n" @@ -1706,7 +1775,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "@return A new region containing the polygons overlapping or touching polygons from the other region\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "The min_count and max_count arguments have been added in version 0.27.\n" ) + @@ -1720,10 +1789,20 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "@return A new region containing the polygons not overlapping or touching polygons from the other region\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "The min_count and max_count arguments have been added in version 0.27.\n" ) + + method_ext ("split_interacting", &split_interacting_with_region, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits::max ()), "unlimited"), + "@brief Returns the polygons of this region which are interacting with polygons from the other region and the ones which are not at the same time\n" + "\n" + "@return Two new regions: the first containing the result of \\interacting, the second the result of \\not_interacting\n" + "\n" + "This method is equivalent to calling \\interacting and \\not_interacting, but is faster when both results are required.\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept).\n" + "\n" + "This method has been introduced in version 0.27." + ) + method ("select_interacting", (db::Region &(db::Region::*) (const db::Region &, size_t, size_t)) &db::Region::select_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits::max ()), "unlimited"), "@brief Selects the polygons from this region which overlap or touch polygons from the other region\n" "\n" @@ -1734,7 +1813,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "@return The region after the polygons have been selected (self)\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "The min_count and max_count arguments have been added in version 0.27.\n" ) + @@ -1748,7 +1827,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "@return The region after the polygons have been selected (self)\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "The min_count and max_count arguments have been added in version 0.27.\n" ) + @@ -1762,7 +1841,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "@return A new region containing the polygons overlapping or touching edges from the edge collection\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "This method has been introduced in version 0.25.\n" "The min_count and max_count arguments have been added in version 0.27.\n" @@ -1777,11 +1856,21 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "@return A new region containing the polygons not overlapping or touching edges from the edge collection\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "This method has been introduced in version 0.25\n" "The min_count and max_count arguments have been added in version 0.27.\n" ) + + method_ext ("split_interacting", &split_interacting_with_edges, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits::max ()), "unlimited"), + "@brief Returns the polygons of this region which are interacting with edges from the other edge collection and the ones which are not at the same time\n" + "\n" + "@return Two new regions: the first containing the result of \\interacting, the second the result of \\not_interacting\n" + "\n" + "This method is equivalent to calling \\interacting and \\not_interacting, but is faster when both results are required.\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept).\n" + "\n" + "This method has been introduced in version 0.27." + ) + method ("select_interacting", (db::Region &(db::Region::*) (const db::Edges &, size_t, size_t)) &db::Region::select_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits::max ()), "unlimited"), "@brief Selects the polygons from this region which overlap or touch edges from the edge collection\n" "\n" @@ -1792,7 +1881,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "@return The region after the polygons have been selected (self)\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "This method has been introduced in version 0.25\n" "The min_count and max_count arguments have been added in version 0.27.\n" @@ -1807,7 +1896,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "@return The region after the polygons have been selected (self)\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "This method has been introduced in version 0.25\n" "The min_count and max_count arguments have been added in version 0.27.\n" @@ -1822,7 +1911,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "@return A new region containing the polygons overlapping or touching texts\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "This method has been introduced in version 0.27\n" ) + @@ -1836,10 +1925,20 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "@return A new region containing the polygons not overlapping or touching texts\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "This method has been introduced in version 0.27\n" ) + + method_ext ("split_interacting", &split_interacting_with_texts, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits::max ()), "unlimited"), + "@brief Returns the polygons of this region which are interacting with texts from the other text collection and the ones which are not at the same time\n" + "\n" + "@return Two new regions: the first containing the result of \\interacting, the second the result of \\not_interacting\n" + "\n" + "This method is equivalent to calling \\interacting and \\not_interacting, but is faster when both results are required.\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept).\n" + "\n" + "This method has been introduced in version 0.27." + ) + method ("select_interacting", (db::Region &(db::Region::*) (const db::Texts &, size_t, size_t)) &db::Region::select_interacting, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits::max ()), "unlimited"), "@brief Selects the polygons of this region which overlap or touch texts\n" "\n" @@ -1850,7 +1949,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "selected by this method if the number of texts interacting with the polygon is between min_count and max_count " "(including max_count).\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "This method has been introduced in version 0.27\n" ) + @@ -1864,7 +1963,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "@return The region after the polygons have been selected (self)\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "This method has been introduced in version 0.27\n" ) + @@ -1873,7 +1972,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "@return A new region containing the polygons overlapping polygons from the other region\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "The count options have been introduced in version 0.27." ) + @@ -1882,16 +1981,26 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "@return A new region containing the polygons not overlapping polygons from the other region\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "The count options have been introduced in version 0.27." ) + + method_ext ("split_overlapping", &split_overlapping, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits::max ()), "unlimited"), + "@brief Returns the polygons of this region which are overlapping with polygons from the other region and the ones which are not at the same time\n" + "\n" + "@return Two new regions: the first containing the result of \\overlapping, the second the result of \\not_overlapping\n" + "\n" + "This method is equivalent to calling \\overlapping and \\not_overlapping, but is faster when both results are required.\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept).\n" + "\n" + "This method has been introduced in version 0.27." + ) + method ("select_overlapping", &db::Region::select_overlapping, gsi::arg ("other"), gsi::arg ("min_count", size_t (1)), gsi::arg ("max_count", size_t (std::numeric_limits::max ()), "unlimited"), "@brief Selects the polygons from this region which overlap polygons from the other region\n" "\n" "@return The region after the polygons have been selected (self)\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "The count options have been introduced in version 0.27." ) + @@ -1900,7 +2009,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "@return The region after the polygons have been selected (self)\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "The count options have been introduced in version 0.27." ) + @@ -1913,7 +2022,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "@return The region after the polygons have been selected (from other)\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "This method has been introduced in version 0.26.1\n" ) + @@ -1923,7 +2032,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "@return The region after the polygons have been selected (from other)\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "This method has been introduced in version 0.26.1\n" ) + @@ -1933,7 +2042,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "@return The region after the polygons have been selected (from other)\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "This method has been introduced in version 0.26.1\n" ) + @@ -1943,7 +2052,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "@return The edge collection after the edges have been selected (from other)\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "This method has been introduced in version 0.26.1\n" ) + @@ -1953,7 +2062,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\n" "@return The text collection after the texts have been selected (from other)\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "This method has been introduced in version 0.27\n" ) + @@ -1974,7 +2083,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "The edge collection returned can be manipulated in various ways. See \\Edges for a description of the " "possibilities of the edge collection.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + factory_ext ("decompose_convex", &decompose_convex, gsi::arg ("preferred_orientation", po_any (), "\\Polygon#PO_any"), "@brief Decomposes the region into convex pieces.\n" @@ -2018,7 +2127,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "@brief Returns the holes of the region\n" "This method returns all holes as filled polygons.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "If merge semantics is not enabled, the holes may not be detected if the polygons " "are taken from a hole-less representation (i.e. GDS2 file). Use explicit merge (\\merge method) " "in order to merge the polygons and detect holes.\n" @@ -2027,7 +2136,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "@brief Returns the hulls of the region\n" "This method returns all hulls as polygons. The holes will be removed (filles). " "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "If merge semantics is not enabled, the hull may also enclose holes if the polygons " "are taken from a hole-less representation (i.e. GDS2 file). Use explicit merge (\\merge method) " "in order to merge the polygons and detect holes.\n" @@ -2045,36 +2154,36 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", method_ext ("rectangles", &rectangles, "@brief Returns all polygons which are rectangles\n" "This method returns all polygons in self which are rectangles." - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method_ext ("non_rectangles", &non_rectangles, "@brief Returns all polygons which are not rectangles\n" "This method returns all polygons in self which are not rectangles." - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method_ext ("squares", &squares, "@brief Returns all polygons which are squares\n" "This method returns all polygons in self which are squares." - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "This method has been introduced in version 0.27.\n" ) + method_ext ("non_squares", &non_squares, "@brief Returns all polygons which are not squares\n" "This method returns all polygons in self which are not squares." - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "\n" "This method has been introduced in version 0.27.\n" ) + method_ext ("rectilinear", &rectilinear, "@brief Returns all polygons which are rectilinear\n" "This method returns all polygons in self which are rectilinear." - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method_ext ("non_rectilinear", &non_rectilinear, "@brief Returns all polygons which are not rectilinear\n" "This method returns all polygons in self which are not rectilinear." - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" ) + method_ext ("break", &break_polygons, gsi::arg ("max_vertex_count"), gsi::arg ("max_area_ratio", 0.0), "@brief Breaks the polygons of the region into smaller ones\n" @@ -2103,7 +2212,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "with a pencil that has the shape of the given region.\n" "\n" "The resulting polygons are not merged. In order to remove overlaps, use the \\merge or \\merged method." - "Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n" ) + method_ext ("minkowsky_sum", &minkowsky_sum_pp, gsi::arg ("p"), "@brief Compute the Minkowsky sum of the region and a polygon\n" @@ -2116,7 +2225,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "the region with a pen that has the shape of the second polygon.\n" "\n" "The resulting polygons are not merged. In order to remove overlaps, use the \\merge or \\merged method." - "Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n" ) + method_ext ("minkowsky_sum", &minkowsky_sum_pb, gsi::arg ("b"), "@brief Compute the Minkowsky sum of the region and a box\n" @@ -2129,7 +2238,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "as the second polygon.\n" "\n" "The resulting polygons are not merged. In order to remove overlaps, use the \\merge or \\merged method." - "Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n" ) + method_ext ("minkowsky_sum", &minkowsky_sum_pc, gsi::arg ("b"), "@brief Compute the Minkowsky sum of the region and a contour of points (a trace)\n" @@ -2143,7 +2252,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "with a pencil that has the shape of the given region.\n" "\n" "The resulting polygons are not merged. In order to remove overlaps, use the \\merge or \\merged method." - "Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n" ) + method_ext ("move", &move_p, gsi::arg ("v"), "@brief Moves the region\n" @@ -2268,7 +2377,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "violations between the original and the shielding features. If not necessary, shielding can be disabled by setting this flag to " "false. In general, this will improve performance somewhat.\n" "\n" - "Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n" "\n" "The 'shielded' and 'negative' options have been introduced in version 0.27." ) + @@ -2310,7 +2419,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\"opposite_filter\" specifies whether to require or reject errors happening on opposite sides of a figure. " "\"rect_filter\" allows suppressing specific error configurations on rectangular input figures.\n" "\n" - "Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n" "\n" "The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27." ) + @@ -2351,7 +2460,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "violations between the original and the shielding features. If not necessary, shielding can be disabled by setting this flag to " "false. In general, this will improve performance somewhat.\n" "\n" - "Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n" "\n" "The 'shielded' and 'negative' options have been introduced in version 0.27." ) + @@ -2393,7 +2502,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\"opposite_filter\" specifies whether to require or reject errors happening on opposite sides of a figure. " "\"rect_filter\" allows suppressing specific error configurations on rectangular input figures.\n" "\n" - "Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n" "\n" "The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27." ) + @@ -2436,7 +2545,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\"opposite_filter\" specifies whether to require or reject errors happening on opposite sides of a figure. " "\"rect_filter\" allows suppressing specific error configurations on rectangular input figures.\n" "\n" - "Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n" "\n" "The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27." ) + @@ -2479,7 +2588,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\"opposite_filter\" specifies whether to require or reject errors happening on opposite sides of a figure. " "\"rect_filter\" allows suppressing specific error configurations on rectangular input figures.\n" "\n" - "Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n" "\n" "The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27." ) + @@ -2522,7 +2631,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\"opposite_filter\" specifies whether to require or reject errors happening on opposite sides of a figure. " "\"rect_filter\" allows suppressing specific error configurations on rectangular input figures.\n" "\n" - "Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n" "\n" "The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27." ) + @@ -2565,27 +2674,27 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "\"opposite_filter\" specifies whether to require or reject errors happening on opposite sides of a figure. " "\"rect_filter\" allows suppressing specific error configurations on rectangular input figures.\n" "\n" - "Merged semantics applies for the input of this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for the input of this method (see \\merged_semantics= for a description of this concept)\n" "\n" "The 'shielded', 'negative', 'not_opposite' and 'rect_sides' options have been introduced in version 0.27." ) + method_ext ("area", &area1, "@brief The area of the region\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "If merged semantics is not enabled, overlapping areas are counted twice.\n" ) + method_ext ("area", &area2, gsi::arg ("rect"), "@brief The area of the region (restricted to a rectangle)\n" "This version will compute the area of the shapes, restricting the computation to the given rectangle.\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "If merged semantics is not enabled, overlapping areas are counted twice.\n" ) + method_ext ("perimeter", &perimeter1, "@brief The total perimeter of the polygons\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "If merged semantics is not enabled, internal edges are counted as well.\n" ) + method_ext ("perimeter", &perimeter2, gsi::arg ("rect"), @@ -2594,7 +2703,7 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", "Edges along the border are handled in a special way: they are counted when they are oriented with their inside " "side toward the rectangle (in other words: outside edges must coincide with the rectangle's border in order to be counted).\n" "\n" - "Merged semantics applies for this method (see \\merged_semantics= of merged semantics)\n" + "Merged semantics applies for this method (see \\merged_semantics= for a description of this concept)\n" "If merged semantics is not enabled, internal edges are counted as well.\n" ) + method ("bbox", &db::Region::bbox, diff --git a/src/db/unit_tests/dbNetlistCompareTests.cc b/src/db/unit_tests/dbNetlistCompareTests.cc index 1a9f6d882..17f102883 100644 --- a/src/db/unit_tests/dbNetlistCompareTests.cc +++ b/src/db/unit_tests/dbNetlistCompareTests.cc @@ -44,22 +44,22 @@ public: out ("begin_circuit " + circuit2str (a) + " " + circuit2str (b)); } - virtual void end_circuit (const db::Circuit *a, const db::Circuit *b, bool matching) + virtual void end_circuit (const db::Circuit *a, const db::Circuit *b, bool matching, const std::string & /*msg*/) { out ("end_circuit " + circuit2str (a) + " " + circuit2str (b) + " " + (matching ? "MATCH" : "NOMATCH")); } - virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b) + virtual void circuit_skipped (const db::Circuit *a, const db::Circuit *b, const std::string & /*msg*/) { out ("circuit_skipped " + circuit2str (a) + " " + circuit2str (b)); } - virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b) + virtual void circuit_mismatch (const db::Circuit *a, const db::Circuit *b, const std::string & /*msg*/) { out ("circuit_mismatch " + circuit2str (a) + " " + circuit2str (b)); } - virtual void device_class_mismatch (const db::DeviceClass *a, const db::DeviceClass *b) + virtual void device_class_mismatch (const db::DeviceClass *a, const db::DeviceClass *b, const std::string & /*msg*/) { out ("device_class_mismatch " + dc2str (a) + " " + dc2str (b)); } @@ -69,12 +69,12 @@ public: out ("match_nets " + net2str (a) + " " + net2str (b)); } - virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b) + virtual void match_ambiguous_nets (const db::Net *a, const db::Net *b, const std::string & /*msg*/) { out ("match_ambiguous_nets " + net2str (a) + " " + net2str (b)); } - virtual void net_mismatch (const db::Net *a, const db::Net *b) + virtual void net_mismatch (const db::Net *a, const db::Net *b, const std::string & /*msg*/) { out ("net_mismatch " + net2str (a) + " " + net2str (b)); } @@ -84,7 +84,7 @@ public: out ("match_devices " + device2str (a) + " " + device2str (b)); } - virtual void device_mismatch (const db::Device *a, const db::Device *b) + virtual void device_mismatch (const db::Device *a, const db::Device *b, const std::string & /*msg*/) { out ("device_mismatch " + device2str (a) + " " + device2str (b)); } @@ -104,7 +104,7 @@ public: out ("match_pins " + pin2str (a) + " " + pin2str (b)); } - virtual void pin_mismatch (const db::Pin *a, const db::Pin *b) + virtual void pin_mismatch (const db::Pin *a, const db::Pin *b, const std::string & /*msg*/) { out ("pin_mismatch " + pin2str (a) + " " + pin2str (b)); } @@ -114,7 +114,7 @@ public: out ("match_subcircuits " + subcircuit2str (a) + " " + subcircuit2str (b)); } - virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b) + virtual void subcircuit_mismatch (const db::SubCircuit *a, const db::SubCircuit *b, const std::string & /*msg*/) { out ("subcircuit_mismatch " + subcircuit2str (a) + " " + subcircuit2str (b)); } @@ -954,7 +954,7 @@ TEST(5_BufferTwoPathsDifferentParameters) EXPECT_EQ (good, false); logger.clear (); - nl2.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L, 1.5, 0.0)); + nl1.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L, 1.5, 0.0)); good = comp.compare (&nl1, &nl2); EXPECT_EQ (logger.text (), @@ -980,7 +980,7 @@ TEST(5_BufferTwoPathsDifferentParameters) EXPECT_EQ (good, true); logger.clear (); - nl2.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L, 0.0, 0.0)); + nl1.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L, 0.0, 0.0)); good = comp.compare (&nl1, &nl2); EXPECT_EQ (logger.text (), @@ -1006,7 +1006,7 @@ TEST(5_BufferTwoPathsDifferentParameters) EXPECT_EQ (good, false); logger.clear (); - nl2.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L, 0.0, 0.2)); + nl1.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L, 0.0, 0.2)); good = comp.compare (&nl1, &nl2); EXPECT_EQ (logger.text (), @@ -1032,7 +1032,7 @@ TEST(5_BufferTwoPathsDifferentParameters) EXPECT_EQ (good, false); logger.clear (); - nl2.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L, 0.0, 0.4)); + nl1.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L, 0.0, 0.4)); good = comp.compare (&nl1, &nl2); EXPECT_EQ (logger.text (), @@ -1059,7 +1059,7 @@ TEST(5_BufferTwoPathsDifferentParameters) logger.clear (); db::EqualDeviceParameters eq_dp = db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_W) + db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L, 0.2, 0.0); - nl2.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (eq_dp)); + nl1.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (eq_dp)); good = comp.compare (&nl1, &nl2); EXPECT_EQ (logger.text (), @@ -1086,7 +1086,7 @@ TEST(5_BufferTwoPathsDifferentParameters) logger.clear (); eq_dp = db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_W) + db::EqualDeviceParameters (db::DeviceClassMOS3Transistor::param_id_L); - nl2.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (eq_dp)); + nl1.device_class_by_name ("NMOS")->set_parameter_compare_delegate (new db::EqualDeviceParameters (eq_dp)); good = comp.compare (&nl1, &nl2); EXPECT_EQ (logger.text (), diff --git a/src/db/unit_tests/dbRegionTests.cc b/src/db/unit_tests/dbRegionTests.cc index c8b2334fa..b1a6c41a0 100644 --- a/src/db/unit_tests/dbRegionTests.cc +++ b/src/db/unit_tests/dbRegionTests.cc @@ -354,6 +354,8 @@ TEST(10a) r.set_merged_semantics (false); EXPECT_EQ (r.selected_interacting (db::Region (db::Box (db::Point (20, 20), db::Point (30, 30)))).to_string (), "(0,0;0,200;100,200;100,0)"); EXPECT_EQ (r.selected_not_interacting (db::Region (db::Box (db::Point (20, 20), db::Point (30, 30)))).to_string (), "(-100,-100;-100,0;0,0;0,-100)"); + EXPECT_EQ (r.selected_interacting_differential (db::Region (db::Box (db::Point (20, 20), db::Point (30, 30)))).first.to_string (), "(0,0;0,200;100,200;100,0)"); + EXPECT_EQ (r.selected_interacting_differential (db::Region (db::Box (db::Point (20, 20), db::Point (30, 30)))).second.to_string (), "(-100,-100;-100,0;0,0;0,-100)"); EXPECT_EQ (db::compare (r.selected_interacting (db::Region (db::Box (db::Point (-20, -20), db::Point (30, 30)))), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)"), true); EXPECT_EQ (r.selected_interacting (db::Region (db::Box (db::Point (-200, -200), db::Point (-190, -190)))).to_string (), ""); db::Region rr = r; @@ -836,6 +838,8 @@ TEST(18a) EXPECT_EQ (db::compare (o, "(50,10;50,30;70,30;70,10);(70,60;70,80;90,80;90,60)"), true); o = r; EXPECT_EQ (db::compare (o.selected_not_outside (rr), "(0,0;0,20;20,20;20,0);(20,30;20,50;40,50;40,30);(0,60;0,80;60,80;60,60);(0,100;0,130;30,130;30,100)"), true); + EXPECT_EQ (db::compare (o.selected_outside_differential (rr).first, "(50,10;50,30;70,30;70,10);(70,60;70,80;90,80;90,60)"), true); + EXPECT_EQ (db::compare (o.selected_outside_differential (rr).second, "(0,0;0,20;20,20;20,0);(20,30;20,50;40,50;40,30);(0,60;0,80;60,80;60,60);(0,100;0,130;30,130;30,100)"), true); EXPECT_EQ (o.selected_outside (rr).count () + o.selected_not_outside (rr).count (), size_t (6)); EXPECT_EQ (o.selected_outside (rr).hier_count () + o.selected_not_outside (rr).hier_count (), size_t (6)); o.select_not_outside (rr); @@ -848,6 +852,8 @@ TEST(18a) EXPECT_EQ (o.to_string (), "(20,30;20,50;40,50;40,30)"); o = r; EXPECT_EQ (db::compare (o.selected_not_inside (rr), "(0,0;0,20;20,20;20,0);(50,10;50,30;70,30;70,10);(70,60;70,80;90,80;90,60);(0,60;0,80;60,80;60,60);(0,100;0,130;30,130;30,100)"), true); + EXPECT_EQ (db::compare (o.selected_inside_differential (rr).first, "(20,30;20,50;40,50;40,30)"), true); + EXPECT_EQ (db::compare (o.selected_inside_differential (rr).second, "(0,0;0,20;20,20;20,0);(50,10;50,30;70,30;70,10);(70,60;70,80;90,80;90,60);(0,60;0,80;60,80;60,60);(0,100;0,130;30,130;30,100)"), true); EXPECT_EQ (o.selected_inside (rr).count () + o.selected_not_inside (rr).count (), size_t (6)); EXPECT_EQ (o.selected_inside (rr).hier_count () + o.selected_not_inside (rr).hier_count (), size_t (6)); o.select_not_inside (rr); @@ -860,6 +866,8 @@ TEST(18a) EXPECT_EQ (db::compare (o, "(0,0;0,20;20,20;20,0);(50,10;50,30;70,30;70,10);(20,30;20,50;40,50;40,30);(0,60;0,80;60,80;60,60);(0,100;0,130;30,130;30,100)"), true); o = r; EXPECT_EQ (o.selected_not_interacting (rr).to_string (), "(70,60;70,80;90,80;90,60)"); + EXPECT_EQ (db::compare (o.selected_interacting_differential (rr).first, "(0,0;0,20;20,20;20,0);(50,10;50,30;70,30;70,10);(20,30;20,50;40,50;40,30);(0,60;0,80;60,80;60,60);(0,100;0,130;30,130;30,100)"), true); + EXPECT_EQ (db::compare (o.selected_interacting_differential (rr).second, "(70,60;70,80;90,80;90,60)"), true); EXPECT_EQ (o.selected_interacting (rr).count () + o.selected_not_interacting (rr).count (), size_t (6)); EXPECT_EQ (o.selected_interacting (rr).hier_count () + o.selected_not_interacting (rr).hier_count (), size_t (6)); o.select_not_interacting (rr); @@ -872,6 +880,8 @@ TEST(18a) EXPECT_EQ (db::compare (o, "(0,0;0,20;20,20;20,0);(20,30;20,50;40,50;40,30);(0,60;0,80;60,80;60,60);(0,100;0,130;30,130;30,100)"), true); o = r; EXPECT_EQ (db::compare (o.selected_not_overlapping (rr), "(50,10;50,30;70,30;70,10);(70,60;70,80;90,80;90,60)"), true); + EXPECT_EQ (db::compare (o.selected_overlapping_differential (rr).first, "(0,0;0,20;20,20;20,0);(20,30;20,50;40,50;40,30);(0,60;0,80;60,80;60,60);(0,100;0,130;30,130;30,100)"), true); + EXPECT_EQ (db::compare (o.selected_overlapping_differential (rr).second, "(50,10;50,30;70,30;70,10);(70,60;70,80;90,80;90,60)"), true); EXPECT_EQ (o.selected_overlapping (rr).count () + o.selected_not_overlapping (rr).count (), size_t (6)); EXPECT_EQ (o.selected_overlapping (rr).hier_count () + o.selected_not_overlapping (rr).hier_count (), size_t (6)); o.select_not_overlapping (rr); @@ -884,6 +894,8 @@ TEST(18a) EXPECT_EQ (o.to_string (), "(0,100;0,130;30,130;30,100)"); o = r; EXPECT_EQ (db::compare (o.selected_not_enclosing (rr), "(0,0;0,20;20,20;20,0);(50,10;50,30;70,30;70,10);(70,60;70,80;90,80;90,60);(20,30;20,50;40,50;40,30);(0,60;0,80;60,80;60,60)"), true); + EXPECT_EQ (db::compare (o.selected_enclosing_differential (rr).first, "(0,100;0,130;30,130;30,100)"), true); + EXPECT_EQ (db::compare (o.selected_enclosing_differential (rr).second, "(0,0;0,20;20,20;20,0);(50,10;50,30;70,30;70,10);(70,60;70,80;90,80;90,60);(20,30;20,50;40,50;40,30);(0,60;0,80;60,80;60,60)"), true); EXPECT_EQ (o.selected_enclosing (rr).count () + o.selected_not_enclosing (rr).count (), size_t (6)); EXPECT_EQ (o.selected_enclosing (rr).hier_count () + o.selected_not_enclosing (rr).hier_count (), size_t (6)); o.select_not_enclosing (rr); @@ -1506,6 +1518,8 @@ TEST(30a) r.set_merged_semantics (false); EXPECT_EQ (r.selected_interacting (db::Edges (db::Edge (db::Point (20, 20), db::Point (30, 30)))).to_string (), "(0,0;0,200;100,200;100,0)"); EXPECT_EQ (r.selected_not_interacting (db::Edges (db::Edge (db::Point (20, 20), db::Point (30, 30)))).to_string (), "(-100,-100;-100,0;0,0;0,-100)"); + EXPECT_EQ (r.selected_interacting_differential (db::Edges (db::Edge (db::Point (20, 20), db::Point (30, 30)))).first.to_string (), "(0,0;0,200;100,200;100,0)"); + EXPECT_EQ (r.selected_interacting_differential (db::Edges (db::Edge (db::Point (20, 20), db::Point (30, 30)))).second.to_string (), "(-100,-100;-100,0;0,0;0,-100)"); EXPECT_EQ (db::compare (r.selected_interacting (db::Edges (db::Edge (db::Point (-20, -20), db::Point (30, 30)))), "(-100,-100;-100,0;0,0;0,-100);(0,0;0,200;100,200;100,0)"), true); EXPECT_EQ (r.selected_interacting (db::Edges (db::Edge (db::Point (-200, -200), db::Point (-190, -190)))).to_string (), ""); db::Region rr = r; @@ -1689,6 +1703,8 @@ TEST(34a) r.set_merged_semantics (false); EXPECT_EQ (r.selected_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), "(0,0;0,200;100,200;100,0)"); EXPECT_EQ (r.selected_not_interacting (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).to_string (), "(-100,-100;-100,0;0,0;0,-100)"); + EXPECT_EQ (r.selected_interacting_differential (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).first.to_string (), "(0,0;0,200;100,200;100,0)"); + EXPECT_EQ (r.selected_interacting_differential (db::Texts (db::Text ("abc", db::Trans (db::Vector (30, 30))))).second.to_string (), "(-100,-100;-100,0;0,0;0,-100)"); db::Texts tt; tt.insert (db::Text ("abc", db::Trans (db::Vector (30, 30)))); tt.insert (db::Text ("xyz", db::Trans (db::Vector (-100, 0)))); @@ -1782,6 +1798,7 @@ TEST(35a_interact_with_count_region) EXPECT_EQ (r.selected_interacting (rr, 0, 2).to_string (), ""); EXPECT_EQ (r.selected_interacting (rr, 1, 2).to_string (), ""); EXPECT_EQ (r.selected_interacting (rr, 1, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)"); + EXPECT_EQ (r.selected_interacting_differential (rr, 1, 4).first.to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)"); EXPECT_EQ (r.selected_interacting (rr, 2, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)"); EXPECT_EQ (r.selected_interacting (rr, 2, 1).to_string (), ""); EXPECT_EQ (r.selected_interacting (rr, 3, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)"); @@ -1797,6 +1814,7 @@ TEST(35a_interact_with_count_region) EXPECT_EQ (r.selected_not_interacting (rr).to_string (), ""); EXPECT_EQ (r.selected_not_interacting (rr, 0, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)"); EXPECT_EQ (r.selected_not_interacting (rr, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)"); + EXPECT_EQ (r.selected_interacting_differential (rr, 1, 2).second.to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)"); EXPECT_EQ (r.selected_not_interacting (rr, 1, 4).to_string (), ""); EXPECT_EQ (r.selected_not_interacting (rr, 2, 4).to_string (), ""); EXPECT_EQ (db::compare (r.selected_not_interacting (rr, 2, 1), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)"), true); @@ -1855,6 +1873,7 @@ TEST(35b_interact_with_count_edge) EXPECT_EQ (r.selected_interacting (rr, 1, 2).to_string (), ""); EXPECT_EQ (r.selected_interacting (rr, 1, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)"); EXPECT_EQ (r.selected_interacting (rr, 2, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)"); + EXPECT_EQ (r.selected_interacting_differential (rr, 2, 4).first.to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)"); EXPECT_EQ (r.selected_interacting (rr, 2, 1).to_string (), ""); EXPECT_EQ (r.selected_interacting (rr, 3, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)"); EXPECT_EQ (r.selected_interacting (rr, 4, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)"); @@ -1869,6 +1888,7 @@ TEST(35b_interact_with_count_edge) EXPECT_EQ (r.selected_not_interacting (rr).to_string (), ""); EXPECT_EQ (r.selected_not_interacting (rr, 0, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)"); EXPECT_EQ (r.selected_not_interacting (rr, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)"); + EXPECT_EQ (r.selected_interacting_differential (rr, 1, 2).second.to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)"); EXPECT_EQ (r.selected_not_interacting (rr, 1, 4).to_string (), ""); EXPECT_EQ (r.selected_not_interacting (rr, 2, 4).to_string (), ""); EXPECT_EQ (db::compare (r.selected_not_interacting (rr, 2, 1), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)"), true); @@ -1926,6 +1946,7 @@ TEST(35c_interact_with_count_text) EXPECT_EQ (r.selected_interacting (rr, 1, 2).to_string (), ""); EXPECT_EQ (r.selected_interacting (rr, 1, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)"); EXPECT_EQ (r.selected_interacting (rr, 2, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)"); + EXPECT_EQ (r.selected_interacting_differential (rr, 2, 4).first.to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)"); EXPECT_EQ (r.selected_interacting (rr, 2, 1).to_string (), ""); EXPECT_EQ (r.selected_interacting (rr, 3, 4).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)"); EXPECT_EQ (r.selected_interacting (rr, 4, 5).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)"); @@ -1940,6 +1961,7 @@ TEST(35c_interact_with_count_text) EXPECT_EQ (r.selected_not_interacting (rr).to_string (), ""); EXPECT_EQ (r.selected_not_interacting (rr, 0, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)"); EXPECT_EQ (r.selected_not_interacting (rr, 1, 2).to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)"); + EXPECT_EQ (r.selected_interacting_differential (rr, 1, 2).second.to_string (), "(-100,-100;-100,0;0,0;0,200;100,200;100,0;0,0;0,-100)"); EXPECT_EQ (r.selected_not_interacting (rr, 1, 4).to_string (), ""); EXPECT_EQ (r.selected_not_interacting (rr, 2, 4).to_string (), ""); EXPECT_EQ (db::compare (r.selected_not_interacting (rr, 2, 1), "(0,0;0,200;100,200;100,0);(-100,-100;-100,0;0,0;0,-100)"), true); diff --git a/src/drc/drc/built-in-macros/_drc_engine.rb b/src/drc/drc/built-in-macros/_drc_engine.rb index 8cb066c0b..65c76b590 100644 --- a/src/drc/drc/built-in-macros/_drc_engine.rb +++ b/src/drc/drc/built-in-macros/_drc_engine.rb @@ -48,6 +48,8 @@ module DRC @deep = false @netter = nil @netter_data = nil + @total_timer = nil + @drc_progress = nil # initialize the defaults for max_area_ratio, max_vertex_count dss = RBA::DeepShapeStore::new @@ -58,7 +60,7 @@ module DRC @verbose = false - @in_context = false + @in_context = nil end @@ -93,7 +95,7 @@ module DRC def transparent DRCShielded::new(false) end - + def projection_limits(*args) self._context("projection_limits") do if args.size == 0 @@ -211,6 +213,27 @@ module DRC end end + def tile_size(x, y = nil) + DRCTileSize::new(_make_value(x) * self.dbu, _make_value(y || x) * self.dbu) + end + + def tile_step(x, y = nil) + DRCTileStep::new(_make_value(x) * self.dbu, _make_value(y || x) * self.dbu) + end + + def tile_origin(x, y) + DRCTileOrigin::new(_make_value(x) * self.dbu, _make_value(y) * self.dbu) + end + + def tile_count(x, y) + DRCTileCount::new(_make_numeric_value(x), _make_numeric_value(y)) + end + + def tile_boundary(b) + b.is_a?(DRCLayer) || raise("'tile_boundary' requires a layer argument") + DRCTileBoundary::new(b) + end + # %DRC% # @brief Defines SPICE output format (with options) # @name write_spice @@ -455,15 +478,20 @@ module DRC # %DRC% # @name info - # @brief Outputs as message to the logger window + # @brief Outputs as message to the logger or progress window # @synopsis info(message) # @synopsis info(message, indent) # Prints the message to the log window in verbose mode. - # In non-verbose more, nothing is printed. + # In non-verbose more, nothing is printed but a statement is put into the progress window. # \log is a function that always prints a message. def info(arg, indent = 0) - @verbose && log(arg, indent) + if @verbose + log(arg, indent) + else + str = (" " * indent) + arg + RBA::Logger::log(str) + end end # %DRC% @@ -476,7 +504,7 @@ module DRC # verbose mode is enabled. def log(arg, indent = 0) - str = (" " * indent) + arg + str = (" " * indent) + arg if @log_file @log_file.puts(str) else @@ -1828,9 +1856,10 @@ CODE def _wrapper_context(func, *args, &proc) in_context_outer = @in_context begin - @in_context = true + @in_context = func return yield(*args) rescue => ex + RBA::MacroExecutionContext::ignore_next_exception raise("'" + func + "': " + ex.to_s) ensure @in_context = in_context_outer @@ -1842,22 +1871,41 @@ CODE return yield(*args) else begin - @in_context = true + @in_context = func return yield(*args) rescue => ex + RBA::MacroExecutionContext::ignore_next_exception raise("'" + func + "': " + ex.to_s) ensure - @in_context = false + @in_context = nil end end end + def _result_info(res, indent, prefix = "") + if res.is_a?(Array) + res.each_with_index do |a, index| + _result_info(a, indent, "[#{index + 1}] ") + end + elsif res.is_a?(RBA::Region) + info(prefix + "Polygons (raw): #{res.count} (flat) #{res.hier_count} (hierarchical)", indent) + elsif res.is_a?(RBA::Edges) + info(prefix + "Edges: #{res.count} (flat) #{res.hier_count} (hierarchical)", indent) + elsif res.is_a?(RBA::EdgePairs) + info(prefix + "Edge pairs: #{res.count} (flat) #{res.hier_count} (hierarchical)", indent) + elsif res.is_a?(RBA::Texts) + info(prefix + "Texts: #{res.count} (flat) #{res.hier_count} (hierarchical)", indent) + end + end + def run_timed(desc, obj) - log(desc) + info(desc) # enable progress + disable_progress = false if obj.is_a?(RBA::Region) || obj.is_a?(RBA::Edges) || obj.is_a?(RBA::EdgePairs) || obj.is_a?(RBA::Texts) + disable_progress = true obj.enable_progress(desc) end @@ -1867,39 +1915,37 @@ CODE res = yield t.stop - if @verbose + begin + + if @verbose + + # Report result statistics + _result_info(res, 1) + + mem = RBA::Timer::memory_size + if mem > 0 + info("Elapsed: #{'%.3f'%(t.sys+t.user)}s Memory: #{'%.2f'%(mem/(1024*1024))}M", 1) + else + info("Elapsed: #{'%.3f'%(t.sys+t.user)}s", 1) + end - # Report result statistics - if res.is_a?(RBA::Region) - info("Polygons (raw): #{res.count} (flat) #{res.hier_count} (hierarchical)", 1) - elsif res.is_a?(RBA::Edges) - info("Edges: #{res.count} (flat) #{res.hier_count} (hierarchical)", 1) - elsif res.is_a?(RBA::EdgePairs) - info("Edge pairs: #{res.count} (flat) #{res.hier_count} (hierarchical)", 1) - elsif res.is_a?(RBA::Texts) - info("Texts: #{res.count} (flat) #{res.hier_count} (hierarchical)", 1) end - mem = RBA::Timer::memory_size - if mem > 0 - info("Elapsed: #{'%.3f'%(t.sys+t.user)}s Memory: #{'%.2f'%(mem/(1024*1024))}M", 1) - else - info("Elapsed: #{'%.3f'%(t.sys+t.user)}s", 1) + ensure + + # disable progress again + if disable_progress + obj.disable_progress end end - - # disable progress - if obj.is_a?(RBA::Region) || obj.is_a?(RBA::Edges) || obj.is_a?(RBA::EdgePairs) || obj.is_a?(RBA::Texts) - obj.disable_progress - end res end def _cmd(obj, method, *args) - run_timed("\"#{method}\" in: #{src_line}", obj) do + run_timed("\"#{@in_context || method}\" in: #{src_line}", obj) do obj.send(method, *args) end end @@ -1929,8 +1975,9 @@ CODE end av = args.size.times.collect { |i| "a#{i}" }.join(", ") tp.queue("_output(res, self.#{method}(#{av}))") - run_timed("\"#{method}\" in: #{src_line}", obj) do + run_timed("\"#{@in_context || method}\" in: #{src_line}", obj) do tp.execute("Tiled \"#{method}\" in: #{src_line}") + res end else @@ -1940,17 +1987,12 @@ CODE end res = nil - run_timed("\"#{method}\" in: #{src_line}", obj) do + run_timed("\"#{@in_context || method}\" in: #{src_line}", obj) do res = obj.send(method, *args) end end - # disable progress again - if obj.is_a?(RBA::Region) - obj.disable_progress - end - res end @@ -1984,8 +2026,9 @@ CODE end av = args.size.times.collect { |i| "a#{i}" }.join(", ") tp.queue("var rr = self.#{method}(#{av}); _output(res1, rr[0]); _output(res2, rr[1])") - run_timed("\"#{method}\" in: #{src_line}", obj) do + run_timed("\"#{@in_context || method}\" in: #{src_line}", obj) do tp.execute("Tiled \"#{method}\" in: #{src_line}") + res end else @@ -1995,17 +2038,12 @@ CODE end res = nil - run_timed("\"#{method}\" in: #{src_line}", obj) do + run_timed("\"#{@in_context || method}\" in: #{src_line}", obj) do res = obj.send(method, *args) end end - # disable progress again - if obj.is_a?(RBA::Region) - obj.disable_progress - end - res end @@ -2025,8 +2063,9 @@ CODE tp.input("self", obj) tp.threads = (@tt || 1) tp.queue("_output(res, _tile ? self.#{method}(_tile.bbox) : self.#{method})") - run_timed("\"#{method}\" in: #{src_line}", obj) do + run_timed("\"#{@in_context || method}\" in: #{src_line}", obj) do tp.execute("Tiled \"#{method}\" in: #{src_line}") + res end res = res.value @@ -2038,39 +2077,39 @@ CODE end res = nil - run_timed("\"#{method}\" in: #{src_line}", obj) do + run_timed("\"#{@in_context || method}\" in: #{src_line}", obj) do res = obj.send(method) end end - # disable progress again - if obj.is_a?(RBA::Region) - obj.disable_progress - end - res end def _rcmd(obj, method, *args) - run_timed("\"#{method}\" in: #{src_line}", obj) do + run_timed("\"#{@in_context || method}\" in: #{src_line}", obj) do RBA::Region::new(obj.send(method, *args)) end end def _vcmd(obj, method, *args) - run_timed("\"#{method}\" in: #{src_line}", obj) do + run_timed("\"#{@in_context || method}\" in: #{src_line}", obj) do obj.send(method, *args) end end - def _start + def _start(job_description) # clearing the selection avoids some nasty problems view = RBA::LayoutView::current view && view.cancel + @total_timer = RBA::Timer::new + @total_timer.start + + @drc_progress = RBA::AbstractProgress::new(job_description) + end def _flush @@ -2210,9 +2249,20 @@ CODE @netter = nil @netter_data = nil - if final && @log_file - @log_file.close - @log_file = nil + if final + + @total_timer.stop + if @verbose + mem = RBA::Timer::memory_size + if mem > 0 + info("Total elapsed: #{'%.3f'%(@total_timer.sys+@total_timer.user)}s Memory: #{'%.2f'%(mem/(1024*1024))}M") + else + info("Total elapsed: #{'%.3f'%(@total_timer.sys+@total_timer.user)}s") + end + end + + _cleanup + end # force garbage collection @@ -2222,6 +2272,23 @@ CODE end + def _cleanup + + if @log_file + @log_file.close + @log_file = nil + end + + # unlocks the UI + if @drc_progress + @drc_progress._destroy + @drc_progress = nil + end + + GC.start + + end + def _take_data if ! @netter @@ -2526,6 +2593,9 @@ CODE end end + + data + end def make_source(layout, cell = nil, path = nil) diff --git a/src/drc/drc/built-in-macros/_drc_layer.rb b/src/drc/drc/built-in-macros/_drc_layer.rb index b5fa7a3df..f13b8b9c6 100644 --- a/src/drc/drc/built-in-macros/_drc_layer.rb +++ b/src/drc/drc/built-in-macros/_drc_layer.rb @@ -983,8 +983,8 @@ CODE # @name corners # @brief Selects corners of polygons # @synopsis layer.corners([ options ]) - # @synopsis layer.corners(angle, [ options ]) - # @synopsis layer.corners(amin .. amax, [ options ]) + # @synopsis layer.corners(angle [, options ]) + # @synopsis layer.corners(amin .. amax [, options ]) # # This method produces markers on the corners of the polygons. An angle criterion can be given which # selects corners based on the angle of the connecting edges. Positive angles indicate a left turn @@ -1263,6 +1263,7 @@ CODE self.data.send(new_data.is_a?(RBA::EdgePairs) ? :each : :each_merged) do |object| block.call(object.transformed(t)) && new_data.insert(object) end + new_data end DRCLayer::new(@engine, new_data) @@ -1285,7 +1286,7 @@ CODE @engine._wrapper_context("each") do t = RBA::CplxTrans::new(@engine.dbu) - @engine.run_timed("\"select\" in: #{@engine.src_line}", self.data) do + @engine.run_timed("\"each\" in: #{@engine.src_line}", self.data) do self.data.send(self.data.is_a?(RBA::EdgePairs) ? :each : :each_merged) do |object| block.call(object.transformed(t)) end @@ -1368,10 +1369,11 @@ CODE t = RBA::CplxTrans::new(@engine.dbu) dbu_trans = RBA::VCplxTrans::new(1.0 / @engine.dbu) - @engine.run_timed("\\"select\\" in: " + @engine.src_line, self.data) do + @engine.run_timed("\\"#{f}\\" in: " + @engine.src_line, self.data) do self.data.send(new_data.is_a?(RBA::EdgePairs) ? :each : :each_merged) do |object| insert_object_into(new_data, block.call(object.transformed(t)), dbu_trans) end + new_data end DRCLayer::new(@engine, new_data) @@ -1660,6 +1662,7 @@ CODE @engine._context("andnot") do + check_is_layer(other) requires_region other.requires_region @@ -1773,6 +1776,21 @@ CODE # It returns a new layer containing the selected shapes. A version which modifies self # is \select_not_covering. + # %DRC% + # @name split_covering + # @brief Returns the results of \covering and \not_covering at the same time + # @synopsis (a, b) = layer.split_covering(other [, options ]) + # + # This method returns the polygons covering polygons from the other layer in + # one layer and all others in a second layer. This method is equivalent to calling + # \covering and \not_covering, but is faster than doing this in separate steps: + # + # @code + # (covering, not_covering) = l1.split_covering(l2) + # @/code + # + # The options of this method are the same than \covering. + # %DRC% # @name select_covering # @brief Selects shapes or regions of self which completely cover (enclose) one or more shapes from the other region @@ -1849,6 +1867,21 @@ CODE # It returns a new layer containing the selected shapes. A version which modifies self # is \select_not_overlapping. + # %DRC% + # @name split_overlapping + # @brief Returns the results of \overlapping and \not_overlapping at the same time + # @synopsis (a, b) = layer.split_overlapping(other [, options ]) + # + # This method returns the polygons overlapping polygons from the other layer in + # one layer and all others in a second layer. This method is equivalent to calling + # \overlapping and \not_overlapping, but is faster than doing this in separate steps: + # + # @code + # (overlapping, not_overlapping) = l1.split_overlapping(l2) + # @/code + # + # The options of this method are the same than \overlapping. + # %DRC% # @name select_overlapping # @brief Selects shapes or regions of self which overlap shapes from the other region @@ -1923,6 +1956,19 @@ CODE # @/tr # @/table + # %DRC% + # @name split_inside + # @brief Returns the results of \inside and \not_inside at the same time + # @synopsis (a, b) = layer.split_inside(other) + # + # This method returns the polygons inside of polygons from the other layer in + # one layer and all others in a second layer. This method is equivalent to calling + # \inside and \not_inside, but is faster than doing this in separate steps: + # + # @code + # (inside, not_inside) = l1.split_inside(l2) + # @/code + # %DRC% # @name select_inside # @brief Selects shapes or regions of self which are inside the other region @@ -1995,6 +2041,19 @@ CODE # @/tr # @/table + # %DRC% + # @name split_outside + # @brief Returns the results of \outside and \not_outside at the same time + # @synopsis (a, b) = layer.split_outside(other) + # + # This method returns the polygons outside of polygons from the other layer in + # one layer and all others in a second layer. This method is equivalent to calling + # \outside and \not_outside, but is faster than doing this in separate steps: + # + # @code + # (outside, not_outside) = l1.split_outside(l2) + # @/code + # %DRC% # @name select_outside # @brief Selects shapes or regions of self which are outside the other region @@ -2149,6 +2208,21 @@ CODE # @/tr # @/table + # %DRC% + # @name split_interacting + # @brief Returns the results of \interacting and \not_interacting at the same time + # @synopsis (a, b) = layer.split_interacting(other [, options ]) + # + # This method returns the polygons interacting with objects from the other container in + # one layer and all others in a second layer. This method is equivalent to calling + # \interacting and \not_interacting, but is faster than doing this in separate steps: + # + # @code + # (interacting, not_interacting) = l1.split_interacting(l2) + # @/code + # + # The options of this method are the same than \interacting. + # %DRC% # @name select_interacting # @brief Selects shapes or regions of self which touch or overlap shapes from the other region @@ -2192,7 +2266,7 @@ CODE # number of (different) shapes from the other layer. If a min and max count is given, shapes from # self are selected only if they interact with less than min_count or more than max_count different shapes # from the other layer. Two polygons overlapping or touching at two locations are counted as single interactions. - + # %DRC% # @name intersections # @brief Returns the intersection points of intersecting edge segments for two edge collections @@ -2285,6 +2359,7 @@ CODE @engine._context("#{f}") do + check_is_layer(other) if :#{f} != :pull_interacting requires_region other.requires_region @@ -2310,11 +2385,16 @@ CODE %w(| ^ inside not_inside outside not_outside in not_in).each do |f| eval <<"CODE" def #{f}(other) + @engine._context("#{f}") do + requires_same_type(other) requires_edges_or_region + DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data)) + end + end CODE end @@ -2325,12 +2405,14 @@ CODE @engine._context("#{f}") do + check_is_layer(other) other.requires_edges_texts_or_region if self.data.is_a?(RBA::Texts) other.requires_region else other.requires_edges_or_region end + DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data)) end @@ -2342,10 +2424,14 @@ CODE %w(+).each do |f| eval <<"CODE" def #{f}(other) + @engine._context("#{f}") do + requires_same_type(other) DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data)) + end + end CODE end @@ -2356,7 +2442,7 @@ CODE @engine._context("#{f}") do - other.requires_edges_texts_or_region + check_is_layer(other) if self.data.is_a?(RBA::Text) other.requires_region elsif self.data.is_a?(RBA::Region) @@ -2381,6 +2467,7 @@ CODE @engine._context("#{f}") do + check_is_layer(other) requires_edges_texts_or_region if self.data.is_a?(RBA::Text) other.requires_region @@ -2389,6 +2476,7 @@ CODE else other.requires_edges_or_region end + if @engine.is_tiled? self.data = @engine._tcmd(self.data, 0, self.data.class, :#{fi}, other.data, *minmax_count(*args)) DRCLayer::new(@engine, self.data) @@ -2402,14 +2490,39 @@ CODE CODE end - %w(overlapping not_overlapping covering not_covering).each do |f| + %w(split_interacting).each do |f| eval <<"CODE" def #{f}(other, *args) + @engine._context("#{f}") do + + check_is_layer(other) + requires_region + other.requires_edges_texts_or_region + + res = @engine._tcmd_a2(self.data, 0, self.data.class, self.data.class, :#{f}, other.data, *minmax_count(*args)) + [ DRCLayer::new(@engine, res[0]), DRCLayer::new(@engine, res[1]) ] + + end + + end +CODE + end + + %w(overlapping not_overlapping covering not_covering).each do |f| + eval <<"CODE" + + def #{f}(other, *args) + + @engine._context("#{f}") do + requires_same_type(other) requires_region + DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data, *minmax_count(*args))) + end + end CODE end @@ -2424,6 +2537,7 @@ CODE requires_region requires_same_type(other) + if @engine.is_tiled? self.data = @engine._tcmd(self.data, 0, self.data.class, :#{fi}, other.data, *minmax_count(*args)) DRCLayer::new(@engine, self.data) @@ -2437,6 +2551,24 @@ CODE CODE end + %w(split_overlapping split_covering).each do |f| + eval <<"CODE" + def #{f}(other, *args) + + @engine._context("#{f}") do + + requires_region + other.requires_region + + res = @engine._tcmd_a2(self.data, 0, self.data.class, self.data.class, :#{f}, other.data, *minmax_count(*args)) + [ DRCLayer::new(@engine, res[0]), DRCLayer::new(@engine, res[1]) ] + + end + + end +CODE + end + %w(inside not_inside outside not_outside).each do |fi| f = "select_" + fi # In tiled mode, there are no modifying versions. Emulate using the non-modifying one. @@ -2447,6 +2579,7 @@ CODE requires_region requires_same_type(other) + if @engine.is_tiled? self.data = @engine._tcmd(self.data, 0, self.data.class, :#{fi}, other.data) DRCLayer::new(@engine, self.data) @@ -2460,14 +2593,39 @@ CODE CODE end + %w(split_inside split_outside).each do |f| + eval <<"CODE" + def #{f}(other) + + @engine._context("#{f}") do + + check_is_layer(other) + requires_region + other.requires_region + + res = @engine._tcmd_a2(self.data, 0, self.data.class, self.data.class, :#{f}, other.data) + [ DRCLayer::new(@engine, res[0]), DRCLayer::new(@engine, res[1]) ] + + end + + end +CODE + end + %w(inside_part outside_part).each do |f| eval <<"CODE" def #{f}(other) + @engine._context("#{f}") do + + check_is_layer(other) other.requires_region requires_edges + DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data)) + end + end CODE end @@ -2475,11 +2633,17 @@ CODE %w(intersections).each do |f| eval <<"CODE" def #{f}(other) + @engine._context("#{f}") do + + check_is_layer(other) other.requires_edges requires_edges + DRCLayer::new(@engine, @engine._tcmd(self.data, 0, self.data.class, :#{f}, other.data)) + end + end CODE end @@ -3496,6 +3660,180 @@ CODE end CODE end + + # %DRC% + # @name with_density + # @brief Returns tiles whose density is within a given range + # @synopsis layer.with_density(min_value, max_value [, options ]) + # @synopsis layer.with_density(min_value .. max_value [, options ]) + # + # This method runs a tiled analysis over the current layout. It reports the tiles whose density + # is between "min_value" and "max_value". "min_value" and "max_value" are given in + # relative units, i.e. within the range of 0 to 1.0 corresponding to a density of 0 to 100%. + # + # "min_value" or "max_value" can be nil or omitted in the ".." range notation. + # In this case, they are taken as "0" and "100%". + # + # The tile size must be specified with the "tile_size" option: + # + # @code + # # reports areas where layer 1/0 density is below 10% on 20x20 um tiles + # low_density = input(1, 0).density(0.0 .. 0.1, tile_size(20.um)) + # @/code + # + # Anisotropic tiles can be specified by giving two values, like "tile_size(10.um, 20.um)". + # The first value is the horizontal tile dimension, the second value is the vertical tile + # dimension. + # + # A tile overlap can be specified using "tile_step". If the tile step is less than the + # tile size, the tiles will overlap. The layout window given by "tile_size" is moved + # in increments of the tile step: + # + # @code + # # reports areas where layer 1/0 density is below 10% on 30x30 um tiles + # # with a tile step of 20x20 um: + # low_density = input(1, 0).density(0.0 .. 0.1, tile_size(30.um), tile_step(20.um)) + # @/code + # + # For "tile_step", anisotropic values can be given as well by using two values: the first for the + # horizontal and the second for the vertical tile step. + # + # Another option is "tile_origin" which specifies the location of the first tile's position. + # This is the lower left tile's lower left corner. If no origin is given, the tiles are centered over the + # area investigated. + # + # By default, the tiles will cover the bounding box of the input layer. A separate layer + # can be used in addition. This way, the layout's dimensions can be derived from some + # drawn boundary layer. To specify a separate, additional layer included in the bounding box, use the "tile_boundary" option: + # + # @code + # # reports density of layer 1/0 below 10% on 20x20 um tiles. The layout's boundary is taken from + # # layer 0/0: + # cell_frame = input(0, 0) + # low_density = input(1, 0).density(0.0 .. 0.1, tile_size(20.um), tile_boundary(cell_frame)) + # @/code + # + # Note that the layer given in "tile_boundary" adds to the input layer for computing the bounding box. + # The computed area is at least the area of the input layer. + # + # Computation of the area can be skipped by explicitly giving a tile count in horizontal and vertical + # direction. With the "tile_origin" option this allows full control over the area covered: + # + # @code + # # reports density of layer 1/0 below 10% on 20x20 um tiles in the region 0,0 .. 2000,3000 + # # (100 and 150 tiles of 20 um each are used in horizontal and vertical direction): + # low_density = input(1, 0).density(0.0 .. 0.1, tile_size(20.um), tile_origin(0.0, 0.0), tile_count(100, 150)) + # @/code + # + # The complementary version of "with_density" is \without_density. + + # %DRC% + # @name without_density + # @brief Returns tiles whose density is not within a given range + # @synopsis layer.without_density(min_value, max_value [, options ]) + # @synopsis layer.without_density(min_value .. max_value [, options ]) + # + # For details about the operations and the operation see \with_density. This version will return the + # tiles where the density is not within the given range. + + def _with_density(method, inverse, *args) + + requires_region + + limits = [ nil, nil ] + nlimits = 0 + tile_size = nil + tile_step = nil + tile_origin = nil + tile_count = nil + tile_boundary = nil + + n = 1 + args.each do |a| + if a.is_a?(DRCTileSize) + tile_size = a.get + elsif a.is_a?(DRCTileStep) + tile_step = a.get + elsif a.is_a?(DRCTileOrigin) + tile_origin = a.get + elsif a.is_a?(DRCTileCount) + tile_count = a.get + elsif a.is_a?(DRCTileBoundary) + tile_boundary = a.get + elsif a.is_a?(Float) || a.is_a?(1.class) || a == nil + nlimits < 2 || raise("Too many values specified") + limits[nlimits] = @engine._make_numeric_value_with_nil(a) + nlimits += 1 + elsif a.is_a?(Range) + nlimits == 0 || raise("Either a range or two limits have to be specified, not both") + limits = [ @engine._make_numeric_value_with_nil(a.begin), @engine._make_numeric_value_with_nil(a.end) ] + nlimits = 2 + else + raise("Parameter #" + n.to_s + " does not have an expected type") + end + n += 1 + end + + tile_size || raise("At least the tile_size option needs to be present") + tile_step ||= tile_size + + tp = RBA::TilingProcessor::new + tp.dbu = @engine.dbu + tp.scale_to_dbu = false + tp.tile_size(*tile_step) + if tile_size != tile_step + xb = 0.5 * (tile_size[0] - tile_step[0]) + yb = 0.5 * (tile_size[1] - tile_step[1]) + tp.tile_border(xb, yb) + tp.var("xoverlap", xb / tp.dbu) + tp.var("yoverlap", yb / tp.dbu) + else + tp.var("xoverlap", 0) + tp.var("yoverlap", 0) + end + if tile_origin + tp.tile_origin(*tile_origin) + end + if tile_count + tp.tiles(*tile_count) + end + + res = RBA::Region.new + tp.output("res", res) + tp.input("input", self.data) + tp.threads = (@engine.threads || 1) + if tile_boundary + tp.input("boundary", tile_boundary.data) + end + + tp.var("vmin", limits[0] || 0.0) + tp.var("vmax", limits[1] || 1.0) + tp.var("inverse", inverse) + tp.queue(<<"TP_SCRIPT") + _tile && ( + var bx = _tile.bbox.enlarged(xoverlap, yoverlap); + var d = to_f(input.area(bx)) / to_f(bx.area); + ((d > vmin - 1e-10 && d < vmax + 1e-10) != inverse) && _output(res, bx, false) + ) +TP_SCRIPT + + @engine.run_timed("\"#{method}\" in: #{@engine.src_line}", self.data) do + tp.execute("Tiled \"#{method}\" in: #{@engine.src_line}") + res + end + + DRCLayer::new(@engine, res) + + end + + def with_density(*args) + self._with_density("with_density", false, *args) + end + + def without_density(*args) + self._with_density("without_density", true, *args) + end + # %DRC% # @name scaled @@ -3915,6 +4253,10 @@ CODE @data = d end + def check_is_layer(other) + other.is_a?(DRCLayer) || raise("Argument needs to be a DRC layer") + end + def requires_region self.data.is_a?(RBA::Region) || raise("Requires a polygon layer") end diff --git a/src/drc/drc/built-in-macros/_drc_tags.rb b/src/drc/drc/built-in-macros/_drc_tags.rb index fb9c051fc..c6070cef1 100644 --- a/src/drc/drc/built-in-macros/_drc_tags.rb +++ b/src/drc/drc/built-in-macros/_drc_tags.rb @@ -180,6 +180,56 @@ module DRC @value end end + + # A wrapper for the tile_size option + class DRCTileSize + def initialize(*args) + @xy = args + end + def get + @xy + end + end + + # A wrapper for the tile_step option + class DRCTileStep + def initialize(*args) + @xy = args + end + def get + @xy + end + end + + # A wrapper for the tile_origin option + class DRCTileOrigin + def initialize(*args) + @xy = args + end + def get + @xy + end + end + + # A wrapper for the tile_count option + class DRCTileCount + def initialize(*args) + @xy = args + end + def get + @xy + end + end + + # A wrapper for the tile_boundary option + class DRCTileBoundary + def initialize(layer) + @b = layer + end + def get + @b + end + end end diff --git a/src/drc/drc/built-in-macros/drc_interpreters.lym b/src/drc/drc/built-in-macros/drc_interpreters.lym index f1affc3d7..4a0108d44 100644 --- a/src/drc/drc/built-in-macros/drc_interpreters.lym +++ b/src/drc/drc/built-in-macros/drc_interpreters.lym @@ -17,44 +17,52 @@ module DRC - def DRC.execute_drc(macro, generator, rdb_index = nil) + class DRCExecutable < RBA::Executable - timer = RBA::Timer::new - timer.start - drc = DRCEngine::new - drc._rdb_index = rdb_index - drc._generator = generator + def initialize(macro, generator, rdb_index = nil) - drc_progress = RBA::AbstractProgress::new("DRC: " + macro.path) + @drc = DRCEngine::new + @drc._rdb_index = rdb_index + @drc._generator = generator - begin - - # Set a debugger scope so that our errors end up with the debugger set to the DRC's line - RBA::MacroExecutionContext::set_debugger_scope(macro.path) - # No verbosity set in drc engine - we cannot use the engine's logger - RBA::Logger::verbosity >= 10 && RBA::Logger::info("Running #{macro.path}") - drc.instance_eval(macro.text, macro.path) - # Remove the debugger scope - RBA::MacroExecutionContext::remove_debugger_scope - - rescue => ex - - drc.error("In #{macro.path}: #{ex.to_s}") - RBA::MacroExecutionContext::ignore_next_exception - raise ex - - ensure - - # cleans up and creates layout and report views - drc._finish - - # unlocks the UI - drc_progress._destroy + @macro = macro end - timer.stop - drc.info("Total run time: #{'%.3f'%(timer.sys+timer.user)}s") + def execute + + @drc._start("DRC: " + @macro.path) + + # Set a debugger scope so that our errors end up with the debugger set to the DRC's line + RBA::MacroExecutionContext::set_debugger_scope(@macro.path) + + begin + + # No verbosity set in drc engine - we cannot use the engine's logger + RBA::Logger::verbosity >= 10 && RBA::Logger::info("Running #{@macro.path}") + @drc.instance_eval(@macro.text, @macro.path) + + rescue => ex + + @drc.error("In #{@macro.path}: #{ex.to_s}") + RBA::MacroExecutionContext::ignore_next_exception + raise ex + + end + + nil + + end + + def cleanup + + # Remove the debugger scope + RBA::MacroExecutionContext::remove_debugger_scope + + # cleans up and creates layout and report views + @drc._finish + + end end @@ -79,11 +87,17 @@ module DRC # create a template for the macro editor: create_template(":/drc-templates/drc.lym") + # if available, create a menu branch + if RBA::Application::instance && RBA::Application::instance.main_window + mw = RBA::Application::instance.main_window + mw.menu.insert_menu("tools_menu.verification_group+", "drc", "DRC") + end + end # Implements the execute method - def execute(macro) - DRC::execute_drc(macro, @recipe.generator("script" => macro.path)) + def executable(macro) + DRCExecutable::new(macro, @recipe.generator("script" => macro.path)) end end @@ -109,20 +123,20 @@ module DRC end # Implements the execute method - def execute(macro) - DRC::execute_drc(macro, @recipe.generator("script" => macro.path)) + def executable(macro) + DRCExecutable::new(macro, @recipe.generator("script" => macro.path)) end end - # A recipe implementation allowing the LVS run to be redone + # A recipe implementation allowing the DRC run to be redone class DRCRecipe < RBA::Recipe def initialize super("drc", "DRC recipe") end - def execute(params) + def executable(params) script = params["script"] if ! script @@ -132,7 +146,7 @@ module DRC macro = RBA::Macro::macro_by_path(script) macro || raise("Can't find DRC script #{script} - unable to re-run") - DRC::execute_drc(macro, self.generator("script" => script), params["rdb_index"]) + DRCExecutable::new(macro, self.generator("script" => script), params["rdb_index"]) end diff --git a/src/drc/unit_tests/drcSimpleTests.cc b/src/drc/unit_tests/drcSimpleTests.cc index b3215743f..b1508b821 100644 --- a/src/drc/unit_tests/drcSimpleTests.cc +++ b/src/drc/unit_tests/drcSimpleTests.cc @@ -1163,3 +1163,8 @@ TEST(29d_holes) run_test (_this, "29", true); } +TEST(30_density) +{ + run_test (_this, "30", false); +} + diff --git a/src/gsi/gsi/gsiDeclTl.cc b/src/gsi/gsi/gsiDeclTl.cc index ccb800826..bdff15a96 100644 --- a/src/gsi/gsi/gsiDeclTl.cc +++ b/src/gsi/gsi/gsiDeclTl.cc @@ -629,6 +629,72 @@ Class decl_GlobPattern ("tl", "GlobPattern", "This class has been introduced in version 0.26." ); +class Executable_Impl + : public tl::Executable, public gsi::ObjectBase +{ +public: + Executable_Impl () + : tl::Executable () + { + // makes the object owned by the C++ side (registrar). This way we don't need to keep a + // singleton instance. + keep (); + } + + virtual tl::Variant execute () + { + if (execute_cb.can_issue ()) { + return execute_cb.issue (&tl::Executable::execute); + } else { + return tl::Variant (); + } + } + + virtual void cleanup () + { + if (cleanup_cb.can_issue ()) { + cleanup_cb.issue (&tl::Executable::cleanup); + } + } + + gsi::Callback execute_cb; + gsi::Callback cleanup_cb; +}; + +} + +namespace tl +{ + template <> struct type_traits : public type_traits { }; +} + +namespace gsi +{ + +Class decl_Executable ("tl", "ExecutableBase", + gsi::Methods (), + "@hide\n@alias Executable" +); + +Class decl_Executable_Impl (decl_Executable, "tl", "Executable", + gsi::callback ("execute", &Executable_Impl::execute, &Executable_Impl::execute_cb, + "@brief Reimplement this method to provide the functionality of the executable.\n" + "This method is supposed to execute the operation with the given parameters and return the desired output." + ) + + gsi::callback ("cleanup", &Executable_Impl::cleanup, &Executable_Impl::cleanup_cb, + "@brief Reimplement this method to provide post-mortem cleanup functionality.\n" + "This method is always called after execute terminated." + ), + "@brief A generic executable object\n" + "This object is a delegate for implementing the actual function of some generic executable function. " + "In addition to the plain execution, if offers a post-mortem cleanup callback which is always executed, even " + "if execute's implementation is cancelled in the debugger.\n" + "\n" + "Parameters are kept as a generic key/value map.\n" + "\n" + "This class has been introduced in version 0.27." +); + class Recipe_Impl : public tl::Recipe, public gsi::ObjectBase { @@ -641,16 +707,16 @@ public: keep (); } - virtual tl::Variant execute (const std::map ¶ms) const + virtual tl::Executable *executable (const std::map ¶ms) const { - if (execute_cb.can_issue ()) { - return execute_cb.issue &> (&tl::Recipe::execute, params); + if (executable_cb.can_issue ()) { + return executable_cb.issue &> (&tl::Recipe::executable, params); } else { - return tl::Variant (); + return 0; } } - gsi::Callback execute_cb; + gsi::Callback executable_cb; }; } @@ -688,10 +754,13 @@ Class decl_Recipe_Impl ("tl", "Recipe", "@brief Delivers the generator string from the given parameters.\n" "The generator string can be used with \\make to re-run the recipe." ) + - gsi::callback ("execute", &Recipe_Impl::execute, &Recipe_Impl::execute_cb, gsi::arg ("params"), - "@brief Reimplement this method to provide the functionality of the recipe.\n" - "This method is supposed to re-run the recipe with the given parameters and deliver the " - "the intended output object." + gsi::callback ("executable", &Recipe_Impl::executable, &Recipe_Impl::executable_cb, gsi::arg ("params"), + "@brief Reimplement this method to provide an executable object for the actual implementation.\n" + "The reasoning behind this architecture is to supply a cleanup callback. This is useful when the " + "actual function is executed as a script and the script terminates in the debugger. The cleanup callback " + "allows implementing any kind of post-mortem action despite being cancelled in the debugger.\n" + "\n" + "This method has been introduced in version 0.27 and replaces 'execute'." ), "@brief A facility for providing reproducable recipes\n" "The idea of this facility is to provide a service by which an object\n" diff --git a/src/lay/lay/doc/about/drc_ref_drc.xml b/src/lay/lay/doc/about/drc_ref_drc.xml index 16683f7cb..dc30e7fe4 100644 --- a/src/lay/lay/doc/about/drc_ref_drc.xml +++ b/src/lay/lay/doc/about/drc_ref_drc.xml @@ -72,6 +72,7 @@ The following global functions are relevant for the DRC expressions:
  • space
  • squares
  • width
  • +
  • with_holes
  • The following documentation will list the methods available for DRC expression objects. @@ -921,6 +922,22 @@ out = in.drc(primary.squares) # equivalent This method acts on edge expressions and delivers a specific part of each edge. See layer#start_segments for details about this functionality.

    +

    "with_holes" - Selects all input polygons with the specified number of holes

    + +

    Usage:

    +
      +
    • expression.with_holes (in condition)
    • +
    +

    +This operation can be used as a plain function in which case it acts on primary +shapes or can be used as method on another DRC expression. +The following example selects all polygons with more than 2 holes: +

    +

    +out = in.drc(with_holes > 2)
    +out = in.drc(primary.with_holes > 2)   # equivalent
    +
    +

    "|" - Boolean OR between the results of two expressions

    Usage:

    diff --git a/src/lay/lay/doc/about/drc_ref_global.xml b/src/lay/lay/doc/about/drc_ref_global.xml index 6cff08384..48877b955 100644 --- a/src/lay/lay/doc/about/drc_ref_global.xml +++ b/src/lay/lay/doc/about/drc_ref_global.xml @@ -738,7 +738,7 @@ This function will evaluate the conditions c1 to cn and return the current primary shape if all conditions renders an empty result. See
    if_all for an example how to use the if_... functions.

    -

    "info" - Outputs as message to the logger window

    +

    "info" - Outputs as message to the logger or progress window

    Usage:

    Prints the message to the log window in verbose mode. -In non-verbose more, nothing is printed. +In non-verbose more, nothing is printed but a statement is put into the progress window. log is a function that always prints a message.

    "input" - Fetches the shapes from the specified input from the default source

    @@ -1775,6 +1775,15 @@ In verbose mode, more output is generated in the log file

    In verbose mode, more output is generated in the log file

    +

    "warn" - Prints a warning

    + +

    Usage:

    +
      +
    • warn(message)
    • +
    +

    +Similar to log, but the message is printed formatted as a warning +

    "width" - Performs a width check

    Usage:

    @@ -1847,6 +1856,17 @@ shape.

    +

    "with_holes" - Selects all input polygons according to their number of holes in DRC expressions

    + +

    Usage:

    +
      +
    • with_holes (in condition)
    • +
    +

    +"with_holes" represents a polygon selector for +DRC expressions selecting polygons of the primary by their number of holes +(see Layer#drc and DRC#with_holes for more details). +

    "write_spice" - Defines SPICE output format (with options)

    Usage:

    diff --git a/src/lay/lay/doc/about/drc_ref_layer.xml b/src/lay/lay/doc/about/drc_ref_layer.xml index f0964154e..b0bfbca96 100644 --- a/src/lay/lay/doc/about/drc_ref_layer.xml +++ b/src/lay/lay/doc/about/drc_ref_layer.xml @@ -247,8 +247,8 @@ deliver objects that can be converted into polygons. Such objects are of class <

    Usage:

    • layer.corners([ options ])
    • -
    • layer.corners(angle, [ options ])
    • -
    • layer.corners(amin .. amax, [ options ])
    • +
    • layer.corners(angle [, options ])
    • +
    • layer.corners(amin .. amax [, options ])

    This method produces markers on the corners of the polygons. An angle criterion can be given which @@ -2659,6 +2659,87 @@ The following image shows the effect of the space check:

    +

    "split_covering" - Returns the results of covering and not_covering at the same time

    + +

    Usage:

    +
      +
    • (a, b) = layer.split_covering(other [, options ])
    • +
    +

    +This method returns the polygons covering polygons from the other layer in +one layer and all others in a second layer. This method is equivalent to calling +covering and not_covering, but is faster than doing this in separate steps: +

    +

    +(covering, not_covering) = l1.split_covering(l2)
    +
    +

    +The options of this method are the same than covering. +

    +

    "split_inside" - Returns the results of inside and not_inside at the same time

    + +

    Usage:

    +
      +
    • (a, b) = layer.split_inside(other)
    • +
    +

    +This method returns the polygons inside of polygons from the other layer in +one layer and all others in a second layer. This method is equivalent to calling +inside and not_inside, but is faster than doing this in separate steps: +

    +

    +(inside, not_inside) = l1.split_inside(l2)
    +
    +

    +

    "split_interacting" - Returns the results of interacting and not_interacting at the same time

    + +

    Usage:

    +
      +
    • (a, b) = layer.split_interacting(other [, options ])
    • +
    +

    +This method returns the polygons interacting with objects from the other container in +one layer and all others in a second layer. This method is equivalent to calling +interacting and not_interacting, but is faster than doing this in separate steps: +

    +

    +(interacting, not_interacting) = l1.split_interacting(l2)
    +
    +

    +The options of this method are the same than interacting. +

    +

    "split_outside" - Returns the results of outside and not_outside at the same time

    + +

    Usage:

    +
      +
    • (a, b) = layer.split_outside(other)
    • +
    +

    +This method returns the polygons outside of polygons from the other layer in +one layer and all others in a second layer. This method is equivalent to calling +outside and not_outside, but is faster than doing this in separate steps: +

    +

    +(outside, not_outside) = l1.split_outside(l2)
    +
    +

    +

    "split_overlapping" - Returns the results of overlapping and not_overlapping at the same time

    + +

    Usage:

    +
      +
    • (a, b) = layer.split_overlapping(other [, options ])
    • +
    +

    +This method returns the polygons overlapping polygons from the other layer in +one layer and all others in a second layer. This method is equivalent to calling +overlapping and not_overlapping, but is faster than doing this in separate steps: +

    +

    +(overlapping, not_overlapping) = l1.split_overlapping(l2)
    +
    +

    +The options of this method are the same than overlapping. +

    "squares" - Selects all squares from the input

    Usage:

    @@ -3074,6 +3155,86 @@ bounding box.

    This method is available for polygon layers only.

    +

    "with_density" - Returns tiles whose density is within a given range

    + +

    Usage:

    +
      +
    • layer.with_density(min_value, max_value [, options ])
    • +
    • layer.with_density(min_value .. max_value [, options ])
    • +
    +

    +This method runs a tiled analysis over the current layout. It reports the tiles whose density +is between "min_value" and "max_value". "min_value" and "max_value" are given in +relative units, i.e. within the range of 0 to 1.0 corresponding to a density of 0 to 100%. +

    +"min_value" or "max_value" can be nil or omitted in the ".." range notation. +In this case, they are taken as "0" and "100%". +

    +The tile size must be specified with the "tile_size" option: +

    +

    +# reports areas where layer 1/0 density is below 10% on 20x20 um tiles
    +low_density = input(1, 0).density(0.0 .. 0.1, tile_size(20.um))
    +
    +

    +Anisotropic tiles can be specified by giving two values, like "tile_size(10.um, 20.um)". +The first value is the horizontal tile dimension, the second value is the vertical tile +dimension. +

    +A tile overlap can be specified using "tile_step". If the tile step is less than the +tile size, the tiles will overlap. The layout window given by "tile_size" is moved +in increments of the tile step: +

    +

    +# reports areas where layer 1/0 density is below 10% on 30x30 um tiles
    +# with a tile step of 20x20 um:
    +low_density = input(1, 0).density(0.0 .. 0.1, tile_size(30.um), tile_step(20.um))
    +
    +

    +For "tile_step", anisotropic values can be given as well by using two values: the first for the +horizontal and the second for the vertical tile step. +

    +Another option is "tile_origin" which specifies the location of the first tile's position. +This is the lower left tile's lower left corner. If no origin is given, the tiles are centered over the +area investigated. +

    +By default, the tiles will cover the bounding box of the input layer. A separate layer +can be used in addition. This way, the layout's dimensions can be derived from some +drawn boundary layer. To specify a separate, additional layer included in the bounding box, use the "tile_boundary" option: +

    +

    +# reports density of layer 1/0 below 10% on 20x20 um tiles. The layout's boundary is taken from
    +# layer 0/0:
    +cell_frame = input(0, 0)
    +low_density = input(1, 0).density(0.0 .. 0.1, tile_size(20.um), tile_boundary(cell_frame))
    +
    +

    +Note that the layer given in "tile_boundary" adds to the input layer for computing the bounding box. +The computed area is at least the area of the input layer. +

    +Computation of the area can be skipped by explicitly giving a tile count in horizontal and vertical +direction. With the "tile_origin" option this allows full control over the area covered: +

    +

    +# reports density of layer 1/0 below 10% on 20x20 um tiles in the region 0,0 .. 2000,3000
    +# (100 and 150 tiles of 20 um each are used in horizontal and vertical direction):
    +low_density = input(1, 0).density(0.0 .. 0.1, tile_size(20.um), tile_origin(0.0, 0.0), tile_count(100, 150))
    +
    +

    +The complementary version of "with_density" is without_density. +

    +

    "with_holes" - Selects all polygons with the specified number of holes

    + +

    Usage:

    +
      +
    • layer.with_holes(count)
    • +
    • layer.with_holes(min_count, max_count)
    • +
    • layer.with_holes(min_count .. max_count)
    • +
    +

    +This method is available for polygon layers. It will select all polygons from the input layer +which have the specified number of holes. +

    "with_length" - Selects edges by their length

    Usage:

    @@ -3228,6 +3389,29 @@ bounding box.

    This method is available for polygon layers only.

    +

    "without_density" - Returns tiles whose density is not within a given range

    + +

    Usage:

    +
      +
    • layer.without_density(min_value, max_value [, options ])
    • +
    • layer.without_density(min_value .. max_value [, options ])
    • +
    +

    +For details about the operations and the operation see with_density. This version will return the +tiles where the density is not within the given range. +

    +

    "without_holes" - Selects all polygons with the specified number of holes

    + +

    Usage:

    +
      +
    • layer.without_holes(count)
    • +
    • layer.without_holes(min_count, max_count)
    • +
    • layer.without_holes(min_count .. max_count)
    • +
    +

    +This method is available for polygon layers. It will select all polygons from the input layer +which do not have the specified number of holes. +

    "without_length" - Selects edges by the their length

    Usage:

    diff --git a/src/lay/lay/doc/images/drc_and1.png b/src/lay/lay/doc/images/drc_and1.png index 8f480bfe7..d1f6d3fb9 100644 Binary files a/src/lay/lay/doc/images/drc_and1.png and b/src/lay/lay/doc/images/drc_and1.png differ diff --git a/src/lay/lay/doc/images/drc_and2.png b/src/lay/lay/doc/images/drc_and2.png index 5b8511d14..20592ffce 100644 Binary files a/src/lay/lay/doc/images/drc_and2.png and b/src/lay/lay/doc/images/drc_and2.png differ diff --git a/src/lay/lay/doc/images/drc_and3.png b/src/lay/lay/doc/images/drc_and3.png index 607deea18..81b678059 100644 Binary files a/src/lay/lay/doc/images/drc_and3.png and b/src/lay/lay/doc/images/drc_and3.png differ diff --git a/src/lay/lay/doc/images/drc_centers1.png b/src/lay/lay/doc/images/drc_centers1.png index 909553ab4..11980e56d 100644 Binary files a/src/lay/lay/doc/images/drc_centers1.png and b/src/lay/lay/doc/images/drc_centers1.png differ diff --git a/src/lay/lay/doc/images/drc_centers2.png b/src/lay/lay/doc/images/drc_centers2.png index 69c7ecb7f..e79d76598 100644 Binary files a/src/lay/lay/doc/images/drc_centers2.png and b/src/lay/lay/doc/images/drc_centers2.png differ diff --git a/src/lay/lay/doc/images/drc_corners1.png b/src/lay/lay/doc/images/drc_corners1.png index d1557f3a2..48adba3ca 100644 Binary files a/src/lay/lay/doc/images/drc_corners1.png and b/src/lay/lay/doc/images/drc_corners1.png differ diff --git a/src/lay/lay/doc/images/drc_corners2.png b/src/lay/lay/doc/images/drc_corners2.png index b595ea398..13fbbd89c 100644 Binary files a/src/lay/lay/doc/images/drc_corners2.png and b/src/lay/lay/doc/images/drc_corners2.png differ diff --git a/src/lay/lay/doc/images/drc_corners3.png b/src/lay/lay/doc/images/drc_corners3.png index 00b978bb3..55a909efd 100644 Binary files a/src/lay/lay/doc/images/drc_corners3.png and b/src/lay/lay/doc/images/drc_corners3.png differ diff --git a/src/lay/lay/doc/images/drc_covering.png b/src/lay/lay/doc/images/drc_covering.png index a96d88a7b..a149730c7 100644 Binary files a/src/lay/lay/doc/images/drc_covering.png and b/src/lay/lay/doc/images/drc_covering.png differ diff --git a/src/lay/lay/doc/images/drc_enc1.png b/src/lay/lay/doc/images/drc_enc1.png index 2bef4ab3c..69abadec6 100644 Binary files a/src/lay/lay/doc/images/drc_enc1.png and b/src/lay/lay/doc/images/drc_enc1.png differ diff --git a/src/lay/lay/doc/images/drc_enc1u.png b/src/lay/lay/doc/images/drc_enc1u.png index 5d6e58bb9..02f4d14b0 100644 Binary files a/src/lay/lay/doc/images/drc_enc1u.png and b/src/lay/lay/doc/images/drc_enc1u.png differ diff --git a/src/lay/lay/doc/images/drc_enc2.png b/src/lay/lay/doc/images/drc_enc2.png index df854246d..16bbda855 100644 Binary files a/src/lay/lay/doc/images/drc_enc2.png and b/src/lay/lay/doc/images/drc_enc2.png differ diff --git a/src/lay/lay/doc/images/drc_enc2u.png b/src/lay/lay/doc/images/drc_enc2u.png index 8a56c4e66..a7a70d48c 100644 Binary files a/src/lay/lay/doc/images/drc_enc2u.png and b/src/lay/lay/doc/images/drc_enc2u.png differ diff --git a/src/lay/lay/doc/images/drc_end_segments1.png b/src/lay/lay/doc/images/drc_end_segments1.png index 71fbae69e..d8ac09404 100644 Binary files a/src/lay/lay/doc/images/drc_end_segments1.png and b/src/lay/lay/doc/images/drc_end_segments1.png differ diff --git a/src/lay/lay/doc/images/drc_end_segments2.png b/src/lay/lay/doc/images/drc_end_segments2.png index 63f6feee9..666e81a31 100644 Binary files a/src/lay/lay/doc/images/drc_end_segments2.png and b/src/lay/lay/doc/images/drc_end_segments2.png differ diff --git a/src/lay/lay/doc/images/drc_extended1.png b/src/lay/lay/doc/images/drc_extended1.png index 3ff0f23f4..0acf06f9f 100644 Binary files a/src/lay/lay/doc/images/drc_extended1.png and b/src/lay/lay/doc/images/drc_extended1.png differ diff --git a/src/lay/lay/doc/images/drc_extended2.png b/src/lay/lay/doc/images/drc_extended2.png index 8860625aa..fe016af38 100644 Binary files a/src/lay/lay/doc/images/drc_extended2.png and b/src/lay/lay/doc/images/drc_extended2.png differ diff --git a/src/lay/lay/doc/images/drc_extended3.png b/src/lay/lay/doc/images/drc_extended3.png index a585d84c2..ce7e24be2 100644 Binary files a/src/lay/lay/doc/images/drc_extended3.png and b/src/lay/lay/doc/images/drc_extended3.png differ diff --git a/src/lay/lay/doc/images/drc_extended4.png b/src/lay/lay/doc/images/drc_extended4.png index 47a09728b..7d4bc6d9d 100644 Binary files a/src/lay/lay/doc/images/drc_extended4.png and b/src/lay/lay/doc/images/drc_extended4.png differ diff --git a/src/lay/lay/doc/images/drc_extent_refs1.png b/src/lay/lay/doc/images/drc_extent_refs1.png index d3c89b5f9..a0ce25631 100644 Binary files a/src/lay/lay/doc/images/drc_extent_refs1.png and b/src/lay/lay/doc/images/drc_extent_refs1.png differ diff --git a/src/lay/lay/doc/images/drc_extent_refs10.png b/src/lay/lay/doc/images/drc_extent_refs10.png index fd1785e21..4616764b0 100644 Binary files a/src/lay/lay/doc/images/drc_extent_refs10.png and b/src/lay/lay/doc/images/drc_extent_refs10.png differ diff --git a/src/lay/lay/doc/images/drc_extent_refs11.png b/src/lay/lay/doc/images/drc_extent_refs11.png index ba28f7c6f..06b354453 100644 Binary files a/src/lay/lay/doc/images/drc_extent_refs11.png and b/src/lay/lay/doc/images/drc_extent_refs11.png differ diff --git a/src/lay/lay/doc/images/drc_extent_refs12.png b/src/lay/lay/doc/images/drc_extent_refs12.png index ee0848fe8..84569ccad 100644 Binary files a/src/lay/lay/doc/images/drc_extent_refs12.png and b/src/lay/lay/doc/images/drc_extent_refs12.png differ diff --git a/src/lay/lay/doc/images/drc_extent_refs13.png b/src/lay/lay/doc/images/drc_extent_refs13.png index 90eb6e900..5234c4ccc 100644 Binary files a/src/lay/lay/doc/images/drc_extent_refs13.png and b/src/lay/lay/doc/images/drc_extent_refs13.png differ diff --git a/src/lay/lay/doc/images/drc_extent_refs20.png b/src/lay/lay/doc/images/drc_extent_refs20.png index c5c7384a8..6f2e21b15 100644 Binary files a/src/lay/lay/doc/images/drc_extent_refs20.png and b/src/lay/lay/doc/images/drc_extent_refs20.png differ diff --git a/src/lay/lay/doc/images/drc_extent_refs21.png b/src/lay/lay/doc/images/drc_extent_refs21.png index cd7ba9a21..e8a0efae4 100644 Binary files a/src/lay/lay/doc/images/drc_extent_refs21.png and b/src/lay/lay/doc/images/drc_extent_refs21.png differ diff --git a/src/lay/lay/doc/images/drc_extent_refs22.png b/src/lay/lay/doc/images/drc_extent_refs22.png index 5864bfd3f..cc53d2e58 100644 Binary files a/src/lay/lay/doc/images/drc_extent_refs22.png and b/src/lay/lay/doc/images/drc_extent_refs22.png differ diff --git a/src/lay/lay/doc/images/drc_extent_refs23.png b/src/lay/lay/doc/images/drc_extent_refs23.png index 753dfadcf..799244e8a 100644 Binary files a/src/lay/lay/doc/images/drc_extent_refs23.png and b/src/lay/lay/doc/images/drc_extent_refs23.png differ diff --git a/src/lay/lay/doc/images/drc_extent_refs24.png b/src/lay/lay/doc/images/drc_extent_refs24.png index dada72737..5e0fa248d 100644 Binary files a/src/lay/lay/doc/images/drc_extent_refs24.png and b/src/lay/lay/doc/images/drc_extent_refs24.png differ diff --git a/src/lay/lay/doc/images/drc_extent_refs25.png b/src/lay/lay/doc/images/drc_extent_refs25.png index 97a3e4ffe..e698483b7 100644 Binary files a/src/lay/lay/doc/images/drc_extent_refs25.png and b/src/lay/lay/doc/images/drc_extent_refs25.png differ diff --git a/src/lay/lay/doc/images/drc_extent_refs26.png b/src/lay/lay/doc/images/drc_extent_refs26.png index a281ba6ad..ffaac3ccc 100644 Binary files a/src/lay/lay/doc/images/drc_extent_refs26.png and b/src/lay/lay/doc/images/drc_extent_refs26.png differ diff --git a/src/lay/lay/doc/images/drc_extent_refs27.png b/src/lay/lay/doc/images/drc_extent_refs27.png index 580ee7363..0ffd732a0 100644 Binary files a/src/lay/lay/doc/images/drc_extent_refs27.png and b/src/lay/lay/doc/images/drc_extent_refs27.png differ diff --git a/src/lay/lay/doc/images/drc_extent_refs30.png b/src/lay/lay/doc/images/drc_extent_refs30.png index 8971fe0f2..f10836f89 100644 Binary files a/src/lay/lay/doc/images/drc_extent_refs30.png and b/src/lay/lay/doc/images/drc_extent_refs30.png differ diff --git a/src/lay/lay/doc/images/drc_extent_refs31.png b/src/lay/lay/doc/images/drc_extent_refs31.png index 0c1273866..2ecb4b3fc 100644 Binary files a/src/lay/lay/doc/images/drc_extent_refs31.png and b/src/lay/lay/doc/images/drc_extent_refs31.png differ diff --git a/src/lay/lay/doc/images/drc_extents1.png b/src/lay/lay/doc/images/drc_extents1.png index 494f98de6..4da7f777e 100644 Binary files a/src/lay/lay/doc/images/drc_extents1.png and b/src/lay/lay/doc/images/drc_extents1.png differ diff --git a/src/lay/lay/doc/images/drc_extents2.png b/src/lay/lay/doc/images/drc_extents2.png index 849ef4b8f..2d9c743be 100644 Binary files a/src/lay/lay/doc/images/drc_extents2.png and b/src/lay/lay/doc/images/drc_extents2.png differ diff --git a/src/lay/lay/doc/images/drc_holes.png b/src/lay/lay/doc/images/drc_holes.png index f8d0d5767..7234bdc9d 100644 Binary files a/src/lay/lay/doc/images/drc_holes.png and b/src/lay/lay/doc/images/drc_holes.png differ diff --git a/src/lay/lay/doc/images/drc_hulls.png b/src/lay/lay/doc/images/drc_hulls.png index a86927915..05294e60a 100644 Binary files a/src/lay/lay/doc/images/drc_hulls.png and b/src/lay/lay/doc/images/drc_hulls.png differ diff --git a/src/lay/lay/doc/images/drc_in.png b/src/lay/lay/doc/images/drc_in.png index d490a4a25..6abd1f525 100644 Binary files a/src/lay/lay/doc/images/drc_in.png and b/src/lay/lay/doc/images/drc_in.png differ diff --git a/src/lay/lay/doc/images/drc_inside.png b/src/lay/lay/doc/images/drc_inside.png index 61b9f0385..ad110260a 100644 Binary files a/src/lay/lay/doc/images/drc_inside.png and b/src/lay/lay/doc/images/drc_inside.png differ diff --git a/src/lay/lay/doc/images/drc_inside_part.png b/src/lay/lay/doc/images/drc_inside_part.png index 632836c75..4f60b0e88 100644 Binary files a/src/lay/lay/doc/images/drc_inside_part.png and b/src/lay/lay/doc/images/drc_inside_part.png differ diff --git a/src/lay/lay/doc/images/drc_interacting.png b/src/lay/lay/doc/images/drc_interacting.png index b0ca9711d..cf8ccb394 100644 Binary files a/src/lay/lay/doc/images/drc_interacting.png and b/src/lay/lay/doc/images/drc_interacting.png differ diff --git a/src/lay/lay/doc/images/drc_interacting2.png b/src/lay/lay/doc/images/drc_interacting2.png index c924a17d1..a67ed9efc 100644 Binary files a/src/lay/lay/doc/images/drc_interacting2.png and b/src/lay/lay/doc/images/drc_interacting2.png differ diff --git a/src/lay/lay/doc/images/drc_interacting3.png b/src/lay/lay/doc/images/drc_interacting3.png index 1ca5f6703..91daa8762 100644 Binary files a/src/lay/lay/doc/images/drc_interacting3.png and b/src/lay/lay/doc/images/drc_interacting3.png differ diff --git a/src/lay/lay/doc/images/drc_interacting4.png b/src/lay/lay/doc/images/drc_interacting4.png index 4eff34e8d..38a4fd033 100644 Binary files a/src/lay/lay/doc/images/drc_interacting4.png and b/src/lay/lay/doc/images/drc_interacting4.png differ diff --git a/src/lay/lay/doc/images/drc_interacting5.png b/src/lay/lay/doc/images/drc_interacting5.png index 63aa03f67..72b1316f7 100644 Binary files a/src/lay/lay/doc/images/drc_interacting5.png and b/src/lay/lay/doc/images/drc_interacting5.png differ diff --git a/src/lay/lay/doc/images/drc_join1.png b/src/lay/lay/doc/images/drc_join1.png index b5acb1b0a..d76202b20 100644 Binary files a/src/lay/lay/doc/images/drc_join1.png and b/src/lay/lay/doc/images/drc_join1.png differ diff --git a/src/lay/lay/doc/images/drc_join2.png b/src/lay/lay/doc/images/drc_join2.png index b3d66c286..f0e5afc18 100644 Binary files a/src/lay/lay/doc/images/drc_join2.png and b/src/lay/lay/doc/images/drc_join2.png differ diff --git a/src/lay/lay/doc/images/drc_merged1.png b/src/lay/lay/doc/images/drc_merged1.png index ff025981e..f8902eb65 100644 Binary files a/src/lay/lay/doc/images/drc_merged1.png and b/src/lay/lay/doc/images/drc_merged1.png differ diff --git a/src/lay/lay/doc/images/drc_merged2.png b/src/lay/lay/doc/images/drc_merged2.png index c66432764..6e8aee84f 100644 Binary files a/src/lay/lay/doc/images/drc_merged2.png and b/src/lay/lay/doc/images/drc_merged2.png differ diff --git a/src/lay/lay/doc/images/drc_merged3.png b/src/lay/lay/doc/images/drc_merged3.png index 24d14f99c..a6cc97752 100644 Binary files a/src/lay/lay/doc/images/drc_merged3.png and b/src/lay/lay/doc/images/drc_merged3.png differ diff --git a/src/lay/lay/doc/images/drc_merged4.png b/src/lay/lay/doc/images/drc_merged4.png index f66a7a02c..fcdd01725 100644 Binary files a/src/lay/lay/doc/images/drc_merged4.png and b/src/lay/lay/doc/images/drc_merged4.png differ diff --git a/src/lay/lay/doc/images/drc_middle1.png b/src/lay/lay/doc/images/drc_middle1.png index 109ee09ad..ba9dca0d2 100644 Binary files a/src/lay/lay/doc/images/drc_middle1.png and b/src/lay/lay/doc/images/drc_middle1.png differ diff --git a/src/lay/lay/doc/images/drc_moved1.png b/src/lay/lay/doc/images/drc_moved1.png index 9fbd96ea1..f7f0d3235 100644 Binary files a/src/lay/lay/doc/images/drc_moved1.png and b/src/lay/lay/doc/images/drc_moved1.png differ diff --git a/src/lay/lay/doc/images/drc_not1.png b/src/lay/lay/doc/images/drc_not1.png index c44c4d55e..b222eed5d 100644 Binary files a/src/lay/lay/doc/images/drc_not1.png and b/src/lay/lay/doc/images/drc_not1.png differ diff --git a/src/lay/lay/doc/images/drc_not2.png b/src/lay/lay/doc/images/drc_not2.png index 2e4c3784f..17e258276 100644 Binary files a/src/lay/lay/doc/images/drc_not2.png and b/src/lay/lay/doc/images/drc_not2.png differ diff --git a/src/lay/lay/doc/images/drc_not3.png b/src/lay/lay/doc/images/drc_not3.png index 3a51db056..a558b73eb 100644 Binary files a/src/lay/lay/doc/images/drc_not3.png and b/src/lay/lay/doc/images/drc_not3.png differ diff --git a/src/lay/lay/doc/images/drc_not_covering.png b/src/lay/lay/doc/images/drc_not_covering.png index a192aecd3..4a89f993a 100644 Binary files a/src/lay/lay/doc/images/drc_not_covering.png and b/src/lay/lay/doc/images/drc_not_covering.png differ diff --git a/src/lay/lay/doc/images/drc_not_in.png b/src/lay/lay/doc/images/drc_not_in.png index 784aab798..588a5ddec 100644 Binary files a/src/lay/lay/doc/images/drc_not_in.png and b/src/lay/lay/doc/images/drc_not_in.png differ diff --git a/src/lay/lay/doc/images/drc_not_inside.png b/src/lay/lay/doc/images/drc_not_inside.png index 16146f7aa..069afb6b3 100644 Binary files a/src/lay/lay/doc/images/drc_not_inside.png and b/src/lay/lay/doc/images/drc_not_inside.png differ diff --git a/src/lay/lay/doc/images/drc_not_interacting.png b/src/lay/lay/doc/images/drc_not_interacting.png index 66f1d8478..e1124a818 100644 Binary files a/src/lay/lay/doc/images/drc_not_interacting.png and b/src/lay/lay/doc/images/drc_not_interacting.png differ diff --git a/src/lay/lay/doc/images/drc_not_interacting2.png b/src/lay/lay/doc/images/drc_not_interacting2.png index cb6ec6d38..d6105f972 100644 Binary files a/src/lay/lay/doc/images/drc_not_interacting2.png and b/src/lay/lay/doc/images/drc_not_interacting2.png differ diff --git a/src/lay/lay/doc/images/drc_not_interacting3.png b/src/lay/lay/doc/images/drc_not_interacting3.png index 069e09508..32604950c 100644 Binary files a/src/lay/lay/doc/images/drc_not_interacting3.png and b/src/lay/lay/doc/images/drc_not_interacting3.png differ diff --git a/src/lay/lay/doc/images/drc_not_interacting4.png b/src/lay/lay/doc/images/drc_not_interacting4.png index d78b0219e..6a02f22cc 100644 Binary files a/src/lay/lay/doc/images/drc_not_interacting4.png and b/src/lay/lay/doc/images/drc_not_interacting4.png differ diff --git a/src/lay/lay/doc/images/drc_not_interacting5.png b/src/lay/lay/doc/images/drc_not_interacting5.png index ee77c5bdd..a7a81e180 100644 Binary files a/src/lay/lay/doc/images/drc_not_interacting5.png and b/src/lay/lay/doc/images/drc_not_interacting5.png differ diff --git a/src/lay/lay/doc/images/drc_not_outside.png b/src/lay/lay/doc/images/drc_not_outside.png index f2519219a..00e0104f5 100644 Binary files a/src/lay/lay/doc/images/drc_not_outside.png and b/src/lay/lay/doc/images/drc_not_outside.png differ diff --git a/src/lay/lay/doc/images/drc_not_overlapping.png b/src/lay/lay/doc/images/drc_not_overlapping.png index 9909a7f36..40661ce0e 100644 Binary files a/src/lay/lay/doc/images/drc_not_overlapping.png and b/src/lay/lay/doc/images/drc_not_overlapping.png differ diff --git a/src/lay/lay/doc/images/drc_or1.png b/src/lay/lay/doc/images/drc_or1.png index 7357a705c..0763b79d2 100644 Binary files a/src/lay/lay/doc/images/drc_or1.png and b/src/lay/lay/doc/images/drc_or1.png differ diff --git a/src/lay/lay/doc/images/drc_or2.png b/src/lay/lay/doc/images/drc_or2.png index 0aa51b9fa..fdd7cab47 100644 Binary files a/src/lay/lay/doc/images/drc_or2.png and b/src/lay/lay/doc/images/drc_or2.png differ diff --git a/src/lay/lay/doc/images/drc_outside.png b/src/lay/lay/doc/images/drc_outside.png index 0345e4258..a3913d379 100644 Binary files a/src/lay/lay/doc/images/drc_outside.png and b/src/lay/lay/doc/images/drc_outside.png differ diff --git a/src/lay/lay/doc/images/drc_outside_part.png b/src/lay/lay/doc/images/drc_outside_part.png index 34cc504d2..213f7a15e 100644 Binary files a/src/lay/lay/doc/images/drc_outside_part.png and b/src/lay/lay/doc/images/drc_outside_part.png differ diff --git a/src/lay/lay/doc/images/drc_overlap1.png b/src/lay/lay/doc/images/drc_overlap1.png index f58070e79..e4bd2d325 100644 Binary files a/src/lay/lay/doc/images/drc_overlap1.png and b/src/lay/lay/doc/images/drc_overlap1.png differ diff --git a/src/lay/lay/doc/images/drc_overlap1u.png b/src/lay/lay/doc/images/drc_overlap1u.png index 72401d229..4fa168ee3 100644 Binary files a/src/lay/lay/doc/images/drc_overlap1u.png and b/src/lay/lay/doc/images/drc_overlap1u.png differ diff --git a/src/lay/lay/doc/images/drc_overlap2.png b/src/lay/lay/doc/images/drc_overlap2.png index 4da4a00ab..108b48822 100644 Binary files a/src/lay/lay/doc/images/drc_overlap2.png and b/src/lay/lay/doc/images/drc_overlap2.png differ diff --git a/src/lay/lay/doc/images/drc_overlap2u.png b/src/lay/lay/doc/images/drc_overlap2u.png index 6b4666f18..9c246f0e8 100644 Binary files a/src/lay/lay/doc/images/drc_overlap2u.png and b/src/lay/lay/doc/images/drc_overlap2u.png differ diff --git a/src/lay/lay/doc/images/drc_overlapping.png b/src/lay/lay/doc/images/drc_overlapping.png index d3f803281..c066614e0 100644 Binary files a/src/lay/lay/doc/images/drc_overlapping.png and b/src/lay/lay/doc/images/drc_overlapping.png differ diff --git a/src/lay/lay/doc/images/drc_raw1.png b/src/lay/lay/doc/images/drc_raw1.png index 81d56369b..38490f5c1 100644 Binary files a/src/lay/lay/doc/images/drc_raw1.png and b/src/lay/lay/doc/images/drc_raw1.png differ diff --git a/src/lay/lay/doc/images/drc_raw2.png b/src/lay/lay/doc/images/drc_raw2.png index 2803f371f..e788362dc 100644 Binary files a/src/lay/lay/doc/images/drc_raw2.png and b/src/lay/lay/doc/images/drc_raw2.png differ diff --git a/src/lay/lay/doc/images/drc_raw3.png b/src/lay/lay/doc/images/drc_raw3.png index f335740ad..dffd596e6 100644 Binary files a/src/lay/lay/doc/images/drc_raw3.png and b/src/lay/lay/doc/images/drc_raw3.png differ diff --git a/src/lay/lay/doc/images/drc_rotated1.png b/src/lay/lay/doc/images/drc_rotated1.png index 10f561f25..f16aaf3d3 100644 Binary files a/src/lay/lay/doc/images/drc_rotated1.png and b/src/lay/lay/doc/images/drc_rotated1.png differ diff --git a/src/lay/lay/doc/images/drc_rounded_corners.png b/src/lay/lay/doc/images/drc_rounded_corners.png index 49dfb4495..984f71ae2 100644 Binary files a/src/lay/lay/doc/images/drc_rounded_corners.png and b/src/lay/lay/doc/images/drc_rounded_corners.png differ diff --git a/src/lay/lay/doc/images/drc_scaled1.png b/src/lay/lay/doc/images/drc_scaled1.png index 10595dfee..a0ae3fdbc 100644 Binary files a/src/lay/lay/doc/images/drc_scaled1.png and b/src/lay/lay/doc/images/drc_scaled1.png differ diff --git a/src/lay/lay/doc/images/drc_separation1.png b/src/lay/lay/doc/images/drc_separation1.png index 1dfa0e9f3..e982d2871 100644 Binary files a/src/lay/lay/doc/images/drc_separation1.png and b/src/lay/lay/doc/images/drc_separation1.png differ diff --git a/src/lay/lay/doc/images/drc_separation10.png b/src/lay/lay/doc/images/drc_separation10.png index 041e66910..af8fdeac7 100644 Binary files a/src/lay/lay/doc/images/drc_separation10.png and b/src/lay/lay/doc/images/drc_separation10.png differ diff --git a/src/lay/lay/doc/images/drc_separation11.png b/src/lay/lay/doc/images/drc_separation11.png index bfa3d688f..de975994c 100644 Binary files a/src/lay/lay/doc/images/drc_separation11.png and b/src/lay/lay/doc/images/drc_separation11.png differ diff --git a/src/lay/lay/doc/images/drc_separation1u.png b/src/lay/lay/doc/images/drc_separation1u.png index c3bbe1416..1f0db1ee8 100644 Binary files a/src/lay/lay/doc/images/drc_separation1u.png and b/src/lay/lay/doc/images/drc_separation1u.png differ diff --git a/src/lay/lay/doc/images/drc_separation2.png b/src/lay/lay/doc/images/drc_separation2.png index 9859e8e4b..9878580aa 100644 Binary files a/src/lay/lay/doc/images/drc_separation2.png and b/src/lay/lay/doc/images/drc_separation2.png differ diff --git a/src/lay/lay/doc/images/drc_separation3.png b/src/lay/lay/doc/images/drc_separation3.png index cfdd7f26b..54425378d 100644 Binary files a/src/lay/lay/doc/images/drc_separation3.png and b/src/lay/lay/doc/images/drc_separation3.png differ diff --git a/src/lay/lay/doc/images/drc_separation4.png b/src/lay/lay/doc/images/drc_separation4.png index 7c3d58d68..818d2ef7d 100644 Binary files a/src/lay/lay/doc/images/drc_separation4.png and b/src/lay/lay/doc/images/drc_separation4.png differ diff --git a/src/lay/lay/doc/images/drc_separation5.png b/src/lay/lay/doc/images/drc_separation5.png index 7087dfe60..dea235507 100644 Binary files a/src/lay/lay/doc/images/drc_separation5.png and b/src/lay/lay/doc/images/drc_separation5.png differ diff --git a/src/lay/lay/doc/images/drc_separation6.png b/src/lay/lay/doc/images/drc_separation6.png index dfa38c475..f21d778a8 100644 Binary files a/src/lay/lay/doc/images/drc_separation6.png and b/src/lay/lay/doc/images/drc_separation6.png differ diff --git a/src/lay/lay/doc/images/drc_separation7.png b/src/lay/lay/doc/images/drc_separation7.png index 95006d6af..0a76ec4de 100644 Binary files a/src/lay/lay/doc/images/drc_separation7.png and b/src/lay/lay/doc/images/drc_separation7.png differ diff --git a/src/lay/lay/doc/images/drc_separation8.png b/src/lay/lay/doc/images/drc_separation8.png index 1dc539958..638722f9b 100644 Binary files a/src/lay/lay/doc/images/drc_separation8.png and b/src/lay/lay/doc/images/drc_separation8.png differ diff --git a/src/lay/lay/doc/images/drc_separation9.png b/src/lay/lay/doc/images/drc_separation9.png index a6da75eaa..c6a675e18 100644 Binary files a/src/lay/lay/doc/images/drc_separation9.png and b/src/lay/lay/doc/images/drc_separation9.png differ diff --git a/src/lay/lay/doc/images/drc_shielded1.png b/src/lay/lay/doc/images/drc_shielded1.png index 22b98c231..aa788f104 100644 Binary files a/src/lay/lay/doc/images/drc_shielded1.png and b/src/lay/lay/doc/images/drc_shielded1.png differ diff --git a/src/lay/lay/doc/images/drc_shielded2.png b/src/lay/lay/doc/images/drc_shielded2.png index 0116e6229..1ee78bb0e 100644 Binary files a/src/lay/lay/doc/images/drc_shielded2.png and b/src/lay/lay/doc/images/drc_shielded2.png differ diff --git a/src/lay/lay/doc/images/drc_shielded3.png b/src/lay/lay/doc/images/drc_shielded3.png index d7c3abf0b..ba1ab8312 100644 Binary files a/src/lay/lay/doc/images/drc_shielded3.png and b/src/lay/lay/doc/images/drc_shielded3.png differ diff --git a/src/lay/lay/doc/images/drc_shielded4.png b/src/lay/lay/doc/images/drc_shielded4.png index f7fbc75fc..c1644a2ec 100644 Binary files a/src/lay/lay/doc/images/drc_shielded4.png and b/src/lay/lay/doc/images/drc_shielded4.png differ diff --git a/src/lay/lay/doc/images/drc_sized1.png b/src/lay/lay/doc/images/drc_sized1.png index 445a60538..daae1b5ec 100644 Binary files a/src/lay/lay/doc/images/drc_sized1.png and b/src/lay/lay/doc/images/drc_sized1.png differ diff --git a/src/lay/lay/doc/images/drc_sized2.png b/src/lay/lay/doc/images/drc_sized2.png index db23995c6..1e5f2514d 100644 Binary files a/src/lay/lay/doc/images/drc_sized2.png and b/src/lay/lay/doc/images/drc_sized2.png differ diff --git a/src/lay/lay/doc/images/drc_sized3.png b/src/lay/lay/doc/images/drc_sized3.png index 247bda8b2..63946cc16 100644 Binary files a/src/lay/lay/doc/images/drc_sized3.png and b/src/lay/lay/doc/images/drc_sized3.png differ diff --git a/src/lay/lay/doc/images/drc_sized4.png b/src/lay/lay/doc/images/drc_sized4.png index 5e180f7d2..c4d470f98 100644 Binary files a/src/lay/lay/doc/images/drc_sized4.png and b/src/lay/lay/doc/images/drc_sized4.png differ diff --git a/src/lay/lay/doc/images/drc_sized5.png b/src/lay/lay/doc/images/drc_sized5.png index 7caace4de..4426443b4 100644 Binary files a/src/lay/lay/doc/images/drc_sized5.png and b/src/lay/lay/doc/images/drc_sized5.png differ diff --git a/src/lay/lay/doc/images/drc_sized6.png b/src/lay/lay/doc/images/drc_sized6.png index 83677eef9..0849455da 100644 Binary files a/src/lay/lay/doc/images/drc_sized6.png and b/src/lay/lay/doc/images/drc_sized6.png differ diff --git a/src/lay/lay/doc/images/drc_space1.png b/src/lay/lay/doc/images/drc_space1.png index 96caf65c2..a4d6a8877 100644 Binary files a/src/lay/lay/doc/images/drc_space1.png and b/src/lay/lay/doc/images/drc_space1.png differ diff --git a/src/lay/lay/doc/images/drc_space1u.png b/src/lay/lay/doc/images/drc_space1u.png index c3fc2f8a1..617e6af62 100644 Binary files a/src/lay/lay/doc/images/drc_space1u.png and b/src/lay/lay/doc/images/drc_space1u.png differ diff --git a/src/lay/lay/doc/images/drc_space2.png b/src/lay/lay/doc/images/drc_space2.png index 5b7b015c6..713378517 100644 Binary files a/src/lay/lay/doc/images/drc_space2.png and b/src/lay/lay/doc/images/drc_space2.png differ diff --git a/src/lay/lay/doc/images/drc_space2u.png b/src/lay/lay/doc/images/drc_space2u.png index 0f3303314..d223d9663 100644 Binary files a/src/lay/lay/doc/images/drc_space2u.png and b/src/lay/lay/doc/images/drc_space2u.png differ diff --git a/src/lay/lay/doc/images/drc_space3.png b/src/lay/lay/doc/images/drc_space3.png index 9273739f0..a9ddcd213 100644 Binary files a/src/lay/lay/doc/images/drc_space3.png and b/src/lay/lay/doc/images/drc_space3.png differ diff --git a/src/lay/lay/doc/images/drc_space3u.png b/src/lay/lay/doc/images/drc_space3u.png index 2d304de7c..41b7853de 100644 Binary files a/src/lay/lay/doc/images/drc_space3u.png and b/src/lay/lay/doc/images/drc_space3u.png differ diff --git a/src/lay/lay/doc/images/drc_start_segments1.png b/src/lay/lay/doc/images/drc_start_segments1.png index 377a6ac57..bdd7c7051 100644 Binary files a/src/lay/lay/doc/images/drc_start_segments1.png and b/src/lay/lay/doc/images/drc_start_segments1.png differ diff --git a/src/lay/lay/doc/images/drc_start_segments2.png b/src/lay/lay/doc/images/drc_start_segments2.png index ad269e32d..8c23e1c0b 100644 Binary files a/src/lay/lay/doc/images/drc_start_segments2.png and b/src/lay/lay/doc/images/drc_start_segments2.png differ diff --git a/src/lay/lay/doc/images/drc_textpoly1.png b/src/lay/lay/doc/images/drc_textpoly1.png index 487cfcc9c..d43240264 100644 Binary files a/src/lay/lay/doc/images/drc_textpoly1.png and b/src/lay/lay/doc/images/drc_textpoly1.png differ diff --git a/src/lay/lay/doc/images/drc_textpoly2.png b/src/lay/lay/doc/images/drc_textpoly2.png index e6eec02b4..ff84fb7b0 100644 Binary files a/src/lay/lay/doc/images/drc_textpoly2.png and b/src/lay/lay/doc/images/drc_textpoly2.png differ diff --git a/src/lay/lay/doc/images/drc_texts1.png b/src/lay/lay/doc/images/drc_texts1.png index a3c5eabf2..44e30c5bb 100644 Binary files a/src/lay/lay/doc/images/drc_texts1.png and b/src/lay/lay/doc/images/drc_texts1.png differ diff --git a/src/lay/lay/doc/images/drc_texts2.png b/src/lay/lay/doc/images/drc_texts2.png index 2e672d4ce..010c0abca 100644 Binary files a/src/lay/lay/doc/images/drc_texts2.png and b/src/lay/lay/doc/images/drc_texts2.png differ diff --git a/src/lay/lay/doc/images/drc_transformed1.png b/src/lay/lay/doc/images/drc_transformed1.png index 1c8f240f0..3fbbc5af2 100644 Binary files a/src/lay/lay/doc/images/drc_transformed1.png and b/src/lay/lay/doc/images/drc_transformed1.png differ diff --git a/src/lay/lay/doc/images/drc_width1.png b/src/lay/lay/doc/images/drc_width1.png index e603ea2ec..afc906e51 100644 Binary files a/src/lay/lay/doc/images/drc_width1.png and b/src/lay/lay/doc/images/drc_width1.png differ diff --git a/src/lay/lay/doc/images/drc_width1u.png b/src/lay/lay/doc/images/drc_width1u.png index 0620c9f52..dfdc2267f 100644 Binary files a/src/lay/lay/doc/images/drc_width1u.png and b/src/lay/lay/doc/images/drc_width1u.png differ diff --git a/src/lay/lay/doc/images/drc_width2.png b/src/lay/lay/doc/images/drc_width2.png index adbd23e3e..e27d018ef 100644 Binary files a/src/lay/lay/doc/images/drc_width2.png and b/src/lay/lay/doc/images/drc_width2.png differ diff --git a/src/lay/lay/doc/images/drc_width2u.png b/src/lay/lay/doc/images/drc_width2u.png index 72059ed49..da04841dd 100644 Binary files a/src/lay/lay/doc/images/drc_width2u.png and b/src/lay/lay/doc/images/drc_width2u.png differ diff --git a/src/lay/lay/doc/images/drc_width3.png b/src/lay/lay/doc/images/drc_width3.png index b6e4f245d..47a5c108f 100644 Binary files a/src/lay/lay/doc/images/drc_width3.png and b/src/lay/lay/doc/images/drc_width3.png differ diff --git a/src/lay/lay/doc/images/drc_width3u.png b/src/lay/lay/doc/images/drc_width3u.png index d8b9975fa..3766720b1 100644 Binary files a/src/lay/lay/doc/images/drc_width3u.png and b/src/lay/lay/doc/images/drc_width3u.png differ diff --git a/src/lay/lay/doc/images/drc_width4.png b/src/lay/lay/doc/images/drc_width4.png index 10024dbfd..afef4849c 100644 Binary files a/src/lay/lay/doc/images/drc_width4.png and b/src/lay/lay/doc/images/drc_width4.png differ diff --git a/src/lay/lay/doc/images/drc_width4u.png b/src/lay/lay/doc/images/drc_width4u.png index 481c252f2..6434c0e14 100644 Binary files a/src/lay/lay/doc/images/drc_width4u.png and b/src/lay/lay/doc/images/drc_width4u.png differ diff --git a/src/lay/lay/doc/images/drc_width5u.png b/src/lay/lay/doc/images/drc_width5u.png index df054f8b5..9bcd5eadf 100644 Binary files a/src/lay/lay/doc/images/drc_width5u.png and b/src/lay/lay/doc/images/drc_width5u.png differ diff --git a/src/lay/lay/doc/images/drc_width6u.png b/src/lay/lay/doc/images/drc_width6u.png index 5c25d49a4..664e44a3e 100644 Binary files a/src/lay/lay/doc/images/drc_width6u.png and b/src/lay/lay/doc/images/drc_width6u.png differ diff --git a/src/lay/lay/doc/images/drc_with_angle1.png b/src/lay/lay/doc/images/drc_with_angle1.png index 77e234653..ec941dbbb 100644 Binary files a/src/lay/lay/doc/images/drc_with_angle1.png and b/src/lay/lay/doc/images/drc_with_angle1.png differ diff --git a/src/lay/lay/doc/images/drc_with_angle2.png b/src/lay/lay/doc/images/drc_with_angle2.png index c122a281b..7deb564f0 100644 Binary files a/src/lay/lay/doc/images/drc_with_angle2.png and b/src/lay/lay/doc/images/drc_with_angle2.png differ diff --git a/src/lay/lay/doc/images/drc_with_angle3.png b/src/lay/lay/doc/images/drc_with_angle3.png index 1e04a839b..98df2c5f8 100644 Binary files a/src/lay/lay/doc/images/drc_with_angle3.png and b/src/lay/lay/doc/images/drc_with_angle3.png differ diff --git a/src/lay/lay/doc/images/drc_with_angle4.png b/src/lay/lay/doc/images/drc_with_angle4.png index 2fc74b3c7..605b45d14 100644 Binary files a/src/lay/lay/doc/images/drc_with_angle4.png and b/src/lay/lay/doc/images/drc_with_angle4.png differ diff --git a/src/lay/lay/doc/images/drc_xor1.png b/src/lay/lay/doc/images/drc_xor1.png index d33f65b84..9e7b24970 100644 Binary files a/src/lay/lay/doc/images/drc_xor1.png and b/src/lay/lay/doc/images/drc_xor1.png differ diff --git a/src/lay/lay/doc/images/drc_xor2.png b/src/lay/lay/doc/images/drc_xor2.png index ec9da5c2b..246364a18 100644 Binary files a/src/lay/lay/doc/images/drc_xor2.png and b/src/lay/lay/doc/images/drc_xor2.png differ diff --git a/src/lay/lay/layGSIHelpProvider.cc b/src/lay/lay/layGSIHelpProvider.cc index ee7e14b20..69cdc9145 100644 --- a/src/lay/lay/layGSIHelpProvider.cc +++ b/src/lay/lay/layGSIHelpProvider.cc @@ -732,6 +732,8 @@ type_to_s (const gsi::ArgType &a, bool linked, bool for_return) s += "float"; break; case gsi::T_string: s += "string"; break; + case gsi::T_byte_array: + s += "bytes"; break; case gsi::T_var: s += "variant"; break; case gsi::T_object: diff --git a/src/lay/lay/layHelpSource.cc b/src/lay/lay/layHelpSource.cc index d87714774..4b6f236f1 100644 --- a/src/lay/lay/layHelpSource.cc +++ b/src/lay/lay/layHelpSource.cc @@ -326,8 +326,7 @@ HelpSource::produce_index_file (const std::string &path) m_title_map.clear (); m_parent_of.clear (); - tl::AbsoluteProgress progress (tl::to_string (QObject::tr ("Initializing help index")), 1); - progress.can_cancel (false); + tl::AbsoluteProgress progress (tl::to_string (QObject::tr ("Initializing help index")), 1, false /*can't cancel*/); scan ("/index.xml", progress); try { diff --git a/src/lay/lay/layLogViewerDialog.cc b/src/lay/lay/layLogViewerDialog.cc index e0ca83912..b0b4f3b23 100644 --- a/src/lay/lay/layLogViewerDialog.cc +++ b/src/lay/lay/layLogViewerDialog.cc @@ -22,12 +22,15 @@ #include "layLogViewerDialog.h" +#include "layApplication.h" #include #include #include #include #include +#include +#include #include @@ -101,7 +104,7 @@ LogReceiver::begin () LogFile::LogFile (size_t max_entries, bool register_global) : m_error_receiver (this, 0, &LogFile::add_error), m_warn_receiver (this, 0, &LogFile::add_warn), - m_log_receiver (this, 10, &LogFile::add_info), + m_log_receiver (this, 0, &LogFile::add_info), m_info_receiver (this, 0, &LogFile::add_info), m_max_entries (max_entries), m_generation_id (0), @@ -221,25 +224,39 @@ LogFile::max_entries () const void LogFile::add (LogFileEntry::mode_type mode, const std::string &msg, bool continued) { - QMutexLocker locker (&m_lock); + bool can_yield = false; - if (m_max_entries == 0) { - return; + { + QMutexLocker locker (&m_lock); + + if (m_max_entries == 0) { + return; + } + + if (m_messages.size () >= m_max_entries) { + m_messages.pop_front (); + } + + if (mode == LogFileEntry::Warning || mode == LogFileEntry::WarningContinued) { + m_has_warnings = true; + } else if (mode == LogFileEntry::Error || mode == LogFileEntry::ErrorContinued) { + m_has_errors = true; + } + + m_messages.push_back (LogFileEntry (mode, msg, continued)); + + ++m_generation_id; + + if (lay::ApplicationBase::instance ()->qapp_gui () && QThread::currentThread () == lay::ApplicationBase::instance ()->qapp_gui ()->thread () && (tl::Clock::current () - m_last_yield).seconds () > 0.1) { + m_last_yield = tl::Clock::current (); + can_yield = true; + } } - if (m_messages.size () >= m_max_entries) { - m_messages.pop_front (); + // use this opportunity to process events + if (can_yield) { + lay::ApplicationBase::instance ()->process_events (QEventLoop::AllEvents); } - - if (mode == LogFileEntry::Warning || mode == LogFileEntry::WarningContinued) { - m_has_warnings = true; - } else if (mode == LogFileEntry::Error || mode == LogFileEntry::ErrorContinued) { - m_has_errors = true; - } - - m_messages.push_back (LogFileEntry (mode, msg, continued)); - - ++m_generation_id; } int diff --git a/src/lay/lay/layLogViewerDialog.h b/src/lay/lay/layLogViewerDialog.h index c9da714a3..340b28ed0 100644 --- a/src/lay/lay/layLogViewerDialog.h +++ b/src/lay/lay/layLogViewerDialog.h @@ -26,6 +26,7 @@ #include "ui_LogViewerDialog.h" #include "tlLog.h" +#include "tlTimer.h" #include "layCommon.h" #include @@ -227,6 +228,7 @@ private: size_t m_last_generation_id; bool m_has_errors, m_has_warnings; bool m_last_attn; + tl::Clock m_last_yield; /** * @brief Adds an error diff --git a/src/lay/lay/layMacroEditorDialog.cc b/src/lay/lay/layMacroEditorDialog.cc index a5acce812..ad71ce15a 100644 --- a/src/lay/lay/layMacroEditorDialog.cc +++ b/src/lay/lay/layMacroEditorDialog.cc @@ -3003,6 +3003,11 @@ MacroEditorDialog::translate_pseudo_id (size_t &file_id, int &line) } } +static void exit_from_macro () +{ + throw tl::ExitException (); +} + void MacroEditorDialog::exception_thrown (gsi::Interpreter *interpreter, size_t file_id, int line, const std::string &eclass, const std::string &emsg, const gsi::StackTraceProvider *stack_trace_provider) { @@ -3012,7 +3017,7 @@ MacroEditorDialog::exception_thrown (gsi::Interpreter *interpreter, size_t file_ } if (!m_in_exec) { - throw tl::ExitException (); + exit_from_macro (); } // avoid recursive breakpoints and exception catches from the console while in a breakpoint or exception stop @@ -3098,7 +3103,7 @@ MacroEditorDialog::exception_thrown (gsi::Interpreter *interpreter, size_t file_ } if (! m_in_exec) { - throw tl::ExitException (); + exit_from_macro (); } } @@ -3106,7 +3111,7 @@ void MacroEditorDialog::trace (gsi::Interpreter *interpreter, size_t file_id, int line, const gsi::StackTraceProvider *stack_trace_provider) { if (!m_in_exec) { - throw tl::ExitException (); + exit_from_macro (); } // avoid recursive breakpoints and exception catches from the console while in a breakpoint or exception stop @@ -3157,7 +3162,7 @@ MacroEditorDialog::trace (gsi::Interpreter *interpreter, size_t file_id, int lin } if (! m_in_exec) { - throw tl::ExitException (); + exit_from_macro (); } } else if (++m_trace_count == 20) { @@ -3175,7 +3180,7 @@ MacroEditorDialog::trace (gsi::Interpreter *interpreter, size_t file_id, int lin m_process_events_interval = std::max (0.05, std::min (2.0, (m_last_process_events - start).seconds () * 5.0)); if (!m_in_exec) { - throw tl::ExitException (); + exit_from_macro (); } } @@ -3590,6 +3595,9 @@ MacroEditorDialog::run (int stop_stack_depth, lym::Macro *macro) } catch (tl::ExitException &) { m_stop_stack_depth = -1; // .. ignore exit exceptions .. + } catch (tl::BreakException &) { + m_stop_stack_depth = -1; + // .. ignore break exceptions .. } catch (tl::ScriptError &re) { m_stop_stack_depth = -1; handle_error (re); diff --git a/src/lay/lay/layProgress.cc b/src/lay/lay/layProgress.cc index 36624f20d..46da70895 100644 --- a/src/lay/lay/layProgress.cc +++ b/src/lay/lay/layProgress.cc @@ -57,8 +57,10 @@ static bool is_marked_alive (QObject *obj) // -------------------------------------------------------------------- +const double visibility_delay = 1.0; + ProgressReporter::ProgressReporter () - : m_start_time (), mp_pb (0), m_pw_visible (false) + : mp_pb (0), m_pw_visible (false) { // .. nothing yet .. } @@ -94,22 +96,21 @@ ProgressReporter::register_object (tl::Progress *progress) tl::ProgressAdaptor::register_object (progress); - if (m_start_time == tl::Clock () && ! m_pw_visible) { - m_start_time = tl::Clock::current (); - } - - // make dialog visible after some time has passed - if (! m_pw_visible && (tl::Clock::current () - m_start_time).seconds () > 1.0) { - set_visible (true); - } - if (progress->is_abstract ()) { + + m_active.insert (progress); + + if (! m_pw_visible) { + set_visible (true); + } + if (mp_pb) { mp_pb->update_progress (progress); } process_events (); + } else { - update_and_yield (); + m_queued.insert (std::make_pair (progress, tl::Clock::current ())); } } @@ -121,46 +122,64 @@ ProgressReporter::unregister_object (tl::Progress *progress) // close or refresh window if (begin () == end ()) { + m_queued.clear (); + m_active.clear (); + if (m_pw_visible) { set_visible (false); } - m_start_time = tl::Clock (); - if (mp_pb) { mp_pb->update_progress (0); } - process_events (); QApplication::instance ()->removeEventFilter (this); } else { - update_and_yield (); + + m_queued.erase (progress); + + std::set::iterator a = m_active.find (progress); + if (a != m_active.end ()) { + m_active.erase (a); + update_and_yield (); + } + } } void -ProgressReporter::trigger (tl::Progress * /*progress*/) +ProgressReporter::trigger (tl::Progress *progress) { - if (begin () != end ()) { - // make dialog visible after some time has passed - if (! m_pw_visible && (tl::Clock::current () - m_start_time).seconds () > 1.0) { + std::map::iterator q = m_queued.find (progress); + if (q != m_queued.end () && (tl::Clock::current () - q->second).seconds () > visibility_delay) { + if (! m_pw_visible) { set_visible (true); } + m_active.insert (progress); + m_queued.erase (q); + } + + if (m_active.find (progress) != m_active.end ()) { update_and_yield (); } } void -ProgressReporter::yield (tl::Progress * /*progress*/) +ProgressReporter::yield (tl::Progress *progress) { - // make dialog visible after some time has passed - if (! m_pw_visible && (tl::Clock::current () - m_start_time).seconds () > 1.0) { - set_visible (true); + std::map::iterator q = m_queued.find (progress); + if (q != m_queued.end () && (tl::Clock::current () - q->second).seconds () > visibility_delay) { + if (! m_pw_visible) { + set_visible (true); + } + m_active.insert (progress); + m_queued.erase (q); update_and_yield (); - } else if (m_pw_visible) { - // process events if necessary + } + + if (m_active.find (progress) != m_active.end ()) { process_events (); } } @@ -172,11 +191,17 @@ ProgressReporter::update_and_yield () return; } - if (mp_pb && first ()) { - mp_pb->update_progress (first ()); - QWidget *w = mp_pb->progress_get_widget (); - if (w) { - first ()->render_progress (w); + if (mp_pb) { + if (first ()) { + mp_pb->update_progress (first ()); + QWidget *w = mp_pb->progress_get_widget (); + if (w) { + first ()->render_progress (w); + } + } else if (begin () != end ()) { + mp_pb->update_progress (begin ().operator-> ()); + } else { + mp_pb->update_progress (0); } } diff --git a/src/lay/lay/layProgress.h b/src/lay/lay/layProgress.h index 7bb7023c0..de0634fe4 100644 --- a/src/lay/lay/layProgress.h +++ b/src/lay/lay/layProgress.h @@ -28,6 +28,8 @@ #include #include +#include +#include #include "tlProgress.h" #include "tlObject.h" @@ -71,9 +73,10 @@ public: void set_progress_bar (lay::ProgressBar *pb); private: - tl::Clock m_start_time; lay::ProgressBar *mp_pb; bool m_pw_visible; + std::map m_queued; + std::set m_active; void process_events (); void update_and_yield (); diff --git a/src/lay/lay/layProgressWidget.cc b/src/lay/lay/layProgressWidget.cc index 3c4cfe670..bd0f711f4 100644 --- a/src/lay/lay/layProgressWidget.cc +++ b/src/lay/lay/layProgressWidget.cc @@ -90,13 +90,13 @@ QSize ProgressBarWidget::sizeHint () const { QFontMetrics fm (font ()); - return QSize (m_width, fm.height () + 2); + return QSize (fm.width (QString::fromUtf8("100%")) * 4, fm.height () + 2); } QSize ProgressBarWidget::minimumSizeHint () const { - return QSize (m_width, 1); + return QSize (50, 1); } void @@ -149,6 +149,11 @@ ProgressWidget::ProgressWidget (ProgressReporter *pr, QWidget *parent, bool fw) QVBoxLayout *log_layout = new QVBoxLayout (mp_log_frame); + mp_log_label = new QLabel (mp_log_frame); + mp_log_label->setText (QString ()); + mp_log_label->setSizePolicy (QSizePolicy (QSizePolicy::Ignored, QSizePolicy::Preferred)); + log_layout->addWidget (mp_log_label); + QListView *log_view = new QListView (this); log_view->setModel (&m_log_file); log_view->setUniformItemSizes (true); @@ -200,22 +205,22 @@ ProgressWidget::ProgressWidget (ProgressReporter *pr, QWidget *parent, bool fw) layout->addItem (new QSpacerItem (8, 8, QSizePolicy::Fixed, QSizePolicy::Fixed), 0, col++, 1, 1); - QFrame *progress_bar_frame = new QFrame (bar_frame); - progress_bar_frame->setFrameStyle (QFrame::Box | QFrame::Plain); - progress_bar_frame->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding); - layout->addWidget (progress_bar_frame, 0, col, 1, 1); + mp_progress_bar_frame = new QFrame (bar_frame); + mp_progress_bar_frame->setFrameStyle (QFrame::Box | QFrame::Plain); + mp_progress_bar_frame->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Expanding); + layout->addWidget (mp_progress_bar_frame, 0, col, 1, 1); - QGridLayout *pbf_layout = new QGridLayout (progress_bar_frame); - progress_bar_frame->setLayout (pbf_layout); + QGridLayout *pbf_layout = new QGridLayout (mp_progress_bar_frame); + mp_progress_bar_frame->setLayout (pbf_layout); pbf_layout->setMargin (0); pbf_layout->setSpacing (0); - mp_progress_bar1 = new ProgressBarWidget (progress_bar_frame); - pbf_layout->addWidget (mp_progress_bar1, 0, 0, 1, 1); - mp_progress_bar2 = new ProgressBarWidget (progress_bar_frame); - pbf_layout->addWidget (mp_progress_bar2, 1, 0, 1, 1); - mp_progress_bar3 = new ProgressBarWidget (progress_bar_frame); - pbf_layout->addWidget (mp_progress_bar3, 2, 0, 1, 1); + mp_progress_bar1 = new ProgressBarWidget (mp_progress_bar_frame); + pbf_layout->addWidget (mp_progress_bar1, 0, 2, 1, 1); + mp_progress_bar2 = new ProgressBarWidget (mp_progress_bar_frame); + pbf_layout->addWidget (mp_progress_bar2, 0, 1, 1, 1); + mp_progress_bar3 = new ProgressBarWidget (mp_progress_bar_frame); + pbf_layout->addWidget (mp_progress_bar3, 0, 0, 1, 1); layout->addItem (new QSpacerItem (8, 8, QSizePolicy::Fixed, QSizePolicy::Fixed), 0, col++, 1, 1); @@ -236,11 +241,12 @@ ProgressWidget::ProgressWidget (ProgressReporter *pr, QWidget *parent, bool fw) } void -ProgressWidget::set_log_visible (bool f) +ProgressWidget::set_log_visible (tl::Progress *progress) { - if (f != m_log_visible) { - m_log_visible = f; - mp_log_frame->setVisible (f); + if ((progress != 0) != m_log_visible) { + m_log_visible = (progress != 0); + mp_log_frame->setVisible (m_log_visible); + mp_log_label->setText (progress ? tl::to_qstring (progress->desc ()) : QString ()); set_full_width (m_full_width); } } @@ -290,11 +296,23 @@ ProgressWidget::remove_widget () void ProgressWidget::set_progress (tl::Progress *progress) { + lay::ProgressBarWidget *progress_bars[] = { mp_progress_bar1, mp_progress_bar2, mp_progress_bar3 }; + if (! progress || progress->is_abstract ()) { - m_log_file.clear (); + + if (! progress) { + m_log_file.clear (); + } m_log_file.set_max_entries (progress ? 1000 : 0); - set_log_visible (progress != 0); + + set_log_visible (progress); + + mp_progress_bar_frame->hide (); + mp_cancel_button->setEnabled (true); + mp_label->setText (QString ()); + return; + } bool can_cancel = false; @@ -308,8 +326,6 @@ ProgressWidget::set_progress (tl::Progress *progress) mp_cancel_button->setEnabled (can_cancel); mp_label->setText (tl::to_qstring (text)); - lay::ProgressBarWidget *progress_bars[] = { mp_progress_bar1, mp_progress_bar2, mp_progress_bar3 }; - for (size_t i = 0; i < sizeof (progress_bars) / sizeof (progress_bars[0]); ++i) { lay::ProgressBarWidget *pb = progress_bars[i]; @@ -330,6 +346,8 @@ ProgressWidget::set_progress (tl::Progress *progress) } + mp_progress_bar_frame->show (); + // according to the doc this should not be required, but without, the progress bar does not resize mp_progress_bar1->parentWidget ()->updateGeometry (); } diff --git a/src/lay/lay/layProgressWidget.h b/src/lay/lay/layProgressWidget.h index 0600f7e5d..ff9702956 100644 --- a/src/lay/lay/layProgressWidget.h +++ b/src/lay/lay/layProgressWidget.h @@ -72,6 +72,7 @@ public slots: private: QLabel *mp_label; + QFrame *mp_progress_bar_frame; ProgressBarWidget *mp_progress_bar1, *mp_progress_bar2, *mp_progress_bar3; QWidget *mp_widget; int m_widget_col; @@ -79,12 +80,13 @@ private: QToolButton *mp_cancel_button; ProgressReporter *mp_pr; lay::LogFile m_log_file; + QLabel *mp_log_label; QFrame *mp_log_frame; bool m_full_width; int m_left_col, m_right_col; bool m_log_visible; - void set_log_visible (bool f); + void set_log_visible (tl::Progress *progress); }; } diff --git a/src/laybasic/laybasic/layIndexedNetlistModel.cc b/src/laybasic/laybasic/layIndexedNetlistModel.cc index 9f17f70aa..66a2c85f3 100644 --- a/src/laybasic/laybasic/layIndexedNetlistModel.cc +++ b/src/laybasic/laybasic/layIndexedNetlistModel.cc @@ -305,32 +305,28 @@ SingleIndexedNetlistModel::parent_of (const subcircuit_pair &subcircuits) const return std::make_pair (subcircuits.first ? subcircuits.first->circuit () : 0, (const db::Circuit *) 0); } -std::pair -SingleIndexedNetlistModel::top_circuit_from_index (size_t index) const +std::pair > SingleIndexedNetlistModel::top_circuit_from_index(size_t index) const { db::Netlist::const_top_down_circuit_iterator none; - return std::make_pair (attr_by_object_and_index (std::make_pair ((const db::Circuit *) 0, (const db::Circuit *) 0), index, mp_netlist->begin_top_down (), mp_netlist->begin_top_down () + mp_netlist->top_circuit_count (), none, none, m_child_circuit_by_circuit_and_index, sort_by_name ()), db::NetlistCrossReference::None); + return std::make_pair (attr_by_object_and_index (std::make_pair ((const db::Circuit *) 0, (const db::Circuit *) 0), index, mp_netlist->begin_top_down (), mp_netlist->begin_top_down () + mp_netlist->top_circuit_count (), none, none, m_child_circuit_by_circuit_and_index, sort_by_name ()), std::make_pair (db::NetlistCrossReference::None, std::string ())); } -std::pair -SingleIndexedNetlistModel::child_circuit_from_index (const circuit_pair &circuits, size_t index) const +std::pair > SingleIndexedNetlistModel::child_circuit_from_index(const circuit_pair &circuits, size_t index) const { db::Circuit::const_child_circuit_iterator none; - return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_children (), circuits.first->end_children (), none, none, m_child_circuit_by_circuit_and_index, sort_by_name ()), db::NetlistCrossReference::None); + return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_children (), circuits.first->end_children (), none, none, m_child_circuit_by_circuit_and_index, sort_by_name ()), std::make_pair (db::NetlistCrossReference::None, std::string ())); } -std::pair -SingleIndexedNetlistModel::circuit_from_index (size_t index) const +std::pair > SingleIndexedNetlistModel::circuit_from_index(size_t index) const { db::Netlist::const_circuit_iterator none; - return std::make_pair (attr_by_object_and_index (std::make_pair (mp_netlist, (const db::Netlist *) 0), index, mp_netlist->begin_circuits (), mp_netlist->end_circuits (), none, none, m_circuit_by_index, sort_by_name ()), db::NetlistCrossReference::None); + return std::make_pair (attr_by_object_and_index (std::make_pair (mp_netlist, (const db::Netlist *) 0), index, mp_netlist->begin_circuits (), mp_netlist->end_circuits (), none, none, m_circuit_by_index, sort_by_name ()), std::make_pair (db::NetlistCrossReference::None, std::string ())); } -std::pair -SingleIndexedNetlistModel::net_from_index (const circuit_pair &circuits, size_t index) const +std::pair > SingleIndexedNetlistModel::net_from_index(const circuit_pair &circuits, size_t index) const { db::Circuit::const_net_iterator none; - return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_nets (), circuits.first->end_nets (), none, none, m_net_by_circuit_and_index, sort_by_expanded_name ()), db::NetlistCrossReference::None); + return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_nets (), circuits.first->end_nets (), none, none, m_net_by_circuit_and_index, sort_by_expanded_name ()), std::make_pair (db::NetlistCrossReference::None, std::string ())); } const db::Net * @@ -394,25 +390,22 @@ SingleIndexedNetlistModel::net_pinref_from_index (const net_pair &nets, size_t i return attr_by_object_and_index (nets, index, nets.first->begin_pins (), nets.first->end_pins (), none, none, m_pinref_by_net_and_index, sort_by_pin_name ()); } -std::pair -SingleIndexedNetlistModel::device_from_index (const circuit_pair &circuits, size_t index) const +std::pair > SingleIndexedNetlistModel::device_from_index(const circuit_pair &circuits, size_t index) const { db::Circuit::const_device_iterator none; - return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_devices (), circuits.first->end_devices (), none, none, m_device_by_circuit_and_index, sort_by_expanded_name ()), db::NetlistCrossReference::None); + return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_devices (), circuits.first->end_devices (), none, none, m_device_by_circuit_and_index, sort_by_expanded_name ()), std::make_pair (db::NetlistCrossReference::None, std::string ())); } -std::pair -SingleIndexedNetlistModel::pin_from_index (const circuit_pair &circuits, size_t index) const +std::pair > SingleIndexedNetlistModel::pin_from_index(const circuit_pair &circuits, size_t index) const { db::Circuit::const_pin_iterator none; - return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_pins (), circuits.first->end_pins (), none, none, m_pin_by_circuit_and_index, Unsorted ()), db::NetlistCrossReference::None); + return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_pins (), circuits.first->end_pins (), none, none, m_pin_by_circuit_and_index, Unsorted ()), std::make_pair (db::NetlistCrossReference::None, std::string ())); } -std::pair -SingleIndexedNetlistModel::subcircuit_from_index (const circuit_pair &circuits, size_t index) const +std::pair > SingleIndexedNetlistModel::subcircuit_from_index(const circuit_pair &circuits, size_t index) const { db::Circuit::const_subcircuit_iterator none; - return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_subcircuits (), circuits.first->end_subcircuits (), none, none, m_subcircuit_by_circuit_and_index, sort_by_expanded_name ()), db::NetlistCrossReference::None); + return std::make_pair (attr_by_object_and_index (circuits, index, circuits.first->begin_subcircuits (), circuits.first->end_subcircuits (), none, none, m_subcircuit_by_circuit_and_index, sort_by_expanded_name ()), std::make_pair (db::NetlistCrossReference::None, std::string ())); } size_t diff --git a/src/laybasic/laybasic/layIndexedNetlistModel.h b/src/laybasic/laybasic/layIndexedNetlistModel.h index 73e868158..e73aac63a 100644 --- a/src/laybasic/laybasic/layIndexedNetlistModel.h +++ b/src/laybasic/laybasic/layIndexedNetlistModel.h @@ -89,24 +89,24 @@ public: virtual circuit_pair parent_of (const device_pair &device_pair) const = 0; virtual circuit_pair parent_of (const subcircuit_pair &subcircuit_pair) const = 0; - virtual std::pair top_circuit_from_index (size_t index) const = 0; - virtual std::pair child_circuit_from_index (const circuit_pair &circuits, size_t index) const = 0; - virtual std::pair circuit_from_index (size_t index) const = 0; - virtual std::pair net_from_index (const circuit_pair &circuits, size_t index) const = 0; + virtual std::pair > top_circuit_from_index (size_t index) const = 0; + virtual std::pair > child_circuit_from_index (const circuit_pair &circuits, size_t index) const = 0; + virtual std::pair > circuit_from_index (size_t index) const = 0; + virtual std::pair > net_from_index (const circuit_pair &circuits, size_t index) const = 0; virtual const db::Net *second_net_for (const db::Net *first) const = 0; virtual const db::Circuit *second_circuit_for (const db::Circuit *first) const = 0; virtual net_subcircuit_pin_pair net_subcircuit_pinref_from_index (const net_pair &nets, size_t index) const = 0; virtual net_subcircuit_pin_pair subcircuit_pinref_from_index (const subcircuit_pair &subcircuits, size_t index) const = 0; virtual net_terminal_pair net_terminalref_from_index (const net_pair &nets, size_t index) const = 0; virtual net_pin_pair net_pinref_from_index (const net_pair &nets, size_t index) const = 0; - virtual std::pair device_from_index (const circuit_pair &circuits, size_t index) const = 0; - virtual std::pair pin_from_index (const circuit_pair &circuits, size_t index) const = 0; - virtual std::pair subcircuit_from_index (const circuit_pair &circuits, size_t index) const = 0; + virtual std::pair > device_from_index (const circuit_pair &circuits, size_t index) const = 0; + virtual std::pair > pin_from_index (const circuit_pair &circuits, size_t index) const = 0; + virtual std::pair > subcircuit_from_index (const circuit_pair &circuits, size_t index) const = 0; virtual std::string top_circuit_status_hint (size_t /*index*/) const { return std::string (); } virtual std::string circuit_status_hint (size_t /*index*/) const { return std::string (); } virtual std::string child_circuit_status_hint (const circuit_pair &/*circuits*/, size_t /*index*/) const { return std::string (); } - virtual std::string circuit_pair_status_hint (const std::pair & /*cp*/) const { return std::string (); } + virtual std::string circuit_pair_status_hint (const std::pair > & /*cp*/) const { return std::string (); } virtual std::string net_status_hint (const circuit_pair &/*circuits*/, size_t /*index*/) const { return std::string (); } virtual std::string device_status_hint (const circuit_pair &/*circuits*/, size_t /*index*/) const { return std::string (); } virtual std::string pin_status_hint (const circuit_pair &/*circuits*/, size_t /*index*/) const { return std::string (); } @@ -159,19 +159,19 @@ public: virtual circuit_pair parent_of (const device_pair &devices) const; virtual circuit_pair parent_of (const subcircuit_pair &subcircuits) const; - virtual std::pair top_circuit_from_index (size_t index) const; - virtual std::pair circuit_from_index (size_t index) const; - virtual std::pair child_circuit_from_index (const circuit_pair &circuits, size_t index) const; - virtual std::pair net_from_index (const circuit_pair &circuits, size_t index) const; + virtual std::pair > top_circuit_from_index (size_t index) const; + virtual std::pair > circuit_from_index (size_t index) const; + virtual std::pair > child_circuit_from_index (const circuit_pair &circuits, size_t index) const; + virtual std::pair > net_from_index (const circuit_pair &circuits, size_t index) const; virtual const db::Net *second_net_for (const db::Net *first) const; virtual const db::Circuit *second_circuit_for (const db::Circuit *first) const; virtual net_subcircuit_pin_pair net_subcircuit_pinref_from_index (const net_pair &nets, size_t index) const; virtual net_subcircuit_pin_pair subcircuit_pinref_from_index (const subcircuit_pair &subcircuits, size_t index) const; virtual net_terminal_pair net_terminalref_from_index (const net_pair &nets, size_t index) const; virtual net_pin_pair net_pinref_from_index (const net_pair &nets, size_t index) const; - virtual std::pair device_from_index (const circuit_pair &circuits, size_t index) const; - virtual std::pair pin_from_index (const circuit_pair &circuits, size_t index) const; - virtual std::pair subcircuit_from_index (const circuit_pair &circuits, size_t index) const; + virtual std::pair > device_from_index (const circuit_pair &circuits, size_t index) const; + virtual std::pair > pin_from_index (const circuit_pair &circuits, size_t index) const; + virtual std::pair > subcircuit_from_index (const circuit_pair &circuits, size_t index) const; virtual size_t circuit_index (const circuit_pair &circuits) const; virtual size_t net_index (const net_pair &nets) const; diff --git a/src/laybasic/laybasic/layNetlistBrowserDialog.cc b/src/laybasic/laybasic/layNetlistBrowserDialog.cc index 1bb06b7c0..111c16d63 100644 --- a/src/laybasic/laybasic/layNetlistBrowserDialog.cc +++ b/src/laybasic/laybasic/layNetlistBrowserDialog.cc @@ -772,10 +772,7 @@ NetlistBrowserDialog::update_content () m_reload_action->setEnabled (l2ndb != 0); browser_page->enable_updates (false); // Avoid building the internal lists several times ... - if (browser_page->db () != l2ndb) { - db_changed = true; - browser_page->set_db (l2ndb); - } + db_changed = browser_page->set_db (l2ndb); browser_page->set_max_shape_count (m_max_shape_count); browser_page->set_highlight_style (m_marker_color, m_marker_line_width, m_marker_vertex_size, m_marker_halo, m_marker_dither_pattern, m_marker_intensity, m_use_original_colors, m_auto_color_enabled ? &m_auto_colors : 0); browser_page->set_window (m_window, m_window_dim); diff --git a/src/laybasic/laybasic/layNetlistBrowserModel.cc b/src/laybasic/laybasic/layNetlistBrowserModel.cc index 686f4058b..1115f95ad 100644 --- a/src/laybasic/laybasic/layNetlistBrowserModel.cc +++ b/src/laybasic/laybasic/layNetlistBrowserModel.cc @@ -1598,7 +1598,7 @@ db::NetlistCrossReference::Status CircuitItemData::status (NetlistBrowserModel *model) { size_t index = model->indexer ()->circuit_index (m_cp); - return model->indexer ()->circuit_from_index (index).second; + return model->indexer ()->circuit_from_index (index).second.first; } CircuitNetItemData * @@ -1938,7 +1938,7 @@ CircuitNetItemData::status (NetlistBrowserModel *model) { if (m_np.first || m_np.second) { size_t index = model->indexer ()->net_index (m_np); - return model->indexer ()->net_from_index (circuits (), index).second; + return model->indexer ()->net_from_index (circuits (), index).second.first; } else { return db::NetlistCrossReference::None; } @@ -2016,7 +2016,7 @@ CircuitNetDeviceTerminalItemData::tooltip (NetlistBrowserModel *model) db::NetlistCrossReference::Status CircuitNetDeviceTerminalItemData::status (NetlistBrowserModel *model) { - return model->indexer ()->device_from_index (circuits (), model->indexer ()->device_index (dp ())).second; + return model->indexer ()->device_from_index (circuits (), model->indexer ()->device_index (dp ())).second.first; } // ---------------------------------------------------------------------------------- @@ -2113,7 +2113,7 @@ CircuitNetSubCircuitPinItemData::tooltip (NetlistBrowserModel *model) db::NetlistCrossReference::Status CircuitNetSubCircuitPinItemData::status (NetlistBrowserModel *model) { - return model->indexer ()->subcircuit_from_index (parent ()->circuits (), model->indexer ()->subcircuit_index (subcircuits ())).second; + return model->indexer ()->subcircuit_from_index (parent ()->circuits (), model->indexer ()->subcircuit_index (subcircuits ())).second.first; } // ---------------------------------------------------------------------------------- @@ -2272,7 +2272,7 @@ db::NetlistCrossReference::Status CircuitSubCircuitItemData::status (NetlistBrowserModel *model) { size_t index = model->indexer ()->subcircuit_index (sp ()); - return model->indexer ()->subcircuit_from_index (circuits (), index).second; + return model->indexer ()->subcircuit_from_index (circuits (), index).second.first; } // ---------------------------------------------------------------------------------- @@ -2371,7 +2371,7 @@ db::NetlistCrossReference::Status CircuitDeviceItemData::status (NetlistBrowserModel *model) { size_t index = model->indexer ()->device_index (m_dp); - return model->indexer ()->device_from_index (circuits (), index).second; + return model->indexer ()->device_from_index (circuits (), index).second.first; } // ---------------------------------------------------------------------------------- diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.cc b/src/laybasic/laybasic/layNetlistBrowserPage.cc index 429066d79..c63bcade2 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.cc +++ b/src/laybasic/laybasic/layNetlistBrowserPage.cc @@ -118,6 +118,7 @@ NetlistBrowserPage::NetlistBrowserPage (QWidget * /*parent*/) mp_view (0), m_cv_index (0), mp_plugin_root (0), + mp_last_db (0), m_history_ptr (0), m_signals_enabled (true), m_enable_updates (true), @@ -606,7 +607,7 @@ NetlistBrowserPage::rerun_macro () { BEGIN_PROTECTED - if (! mp_database->generator ().empty ()) { + if (mp_database.get () && ! mp_database->generator ().empty ()) { std::map add_pars; @@ -764,12 +765,14 @@ NetlistBrowserPage::show_all (bool f) } } -void +bool NetlistBrowserPage::set_db (db::LayoutToNetlist *l2ndb) { - if (l2ndb == mp_database.get ()) { + // NOTE: mp_last_db mirrors mp_database, but does not automatically fall back to 0 when the DB is deleted. This way we can call + // set_db(0) with the correct behavior after the DB has been destroyed. + if (l2ndb == mp_last_db) { // not change - return; + return false; } if (mp_info_dialog) { @@ -779,6 +782,7 @@ NetlistBrowserPage::set_db (db::LayoutToNetlist *l2ndb) db::LayoutVsSchematic *lvsdb = dynamic_cast (l2ndb); mp_database.reset (l2ndb); + mp_last_db = l2ndb; rerun_button->setEnabled (mp_database.get () && ! mp_database->generator ().empty ()); if (rerun_button->isEnabled ()) { @@ -800,13 +804,15 @@ NetlistBrowserPage::set_db (db::LayoutToNetlist *l2ndb) show_xref->setChecked (lvsdb != 0); m_signals_enabled = se; - clear_markers (); + clear_highlights (); m_cell_context_cache = db::ContextCache (mp_database.get () ? mp_database->internal_layout () : 0); setup_trees (); selection_changed_event (); + + return true; } void @@ -892,6 +898,15 @@ NetlistBrowserPage::setup_trees () find_text->setText (QString ()); } +void +NetlistBrowserPage::clear_highlights () +{ + m_current_path = lay::NetlistObjectsPath (); + m_selected_paths.clear (); + + update_highlights (); +} + void NetlistBrowserPage::highlight (const NetlistObjectsPath ¤t_path, const std::vector &selected_paths) { @@ -900,9 +915,8 @@ NetlistBrowserPage::highlight (const NetlistObjectsPath ¤t_path, const std m_current_path = current_path; m_selected_paths = selected_paths; - clear_markers (); - adjust_view (); update_highlights (); + adjust_view (); } } diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.h b/src/laybasic/laybasic/layNetlistBrowserPage.h index 20766e7cc..59475d788 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.h +++ b/src/laybasic/laybasic/layNetlistBrowserPage.h @@ -91,7 +91,7 @@ public: /** * @brief Attaches the page to a L2N DB */ - void set_db (db::LayoutToNetlist *database); + bool set_db(db::LayoutToNetlist *database); /** * @brief Gets the database the page is connected to @@ -228,6 +228,7 @@ private: unsigned int m_cv_index; lay::Dispatcher *mp_plugin_root; tl::weak_ptr mp_database; + db::LayoutToNetlist *mp_last_db; std::vector m_history; size_t m_history_ptr; bool m_signals_enabled; @@ -247,6 +248,7 @@ private: void adjust_view (); void clear_markers (); void highlight (const NetlistObjectsPath ¤t_path, const std::vector &selected_paths); + void clear_highlights (); std::vector selected_nets (); std::vector selected_devices (); std::vector selected_subcircuits (); diff --git a/src/laybasic/laybasic/layNetlistBrowserTreeModel.cc b/src/laybasic/laybasic/layNetlistBrowserTreeModel.cc index 50f72883f..d3839fa0e 100644 --- a/src/laybasic/laybasic/layNetlistBrowserTreeModel.cc +++ b/src/laybasic/laybasic/layNetlistBrowserTreeModel.cc @@ -204,10 +204,10 @@ NetlistBrowserTreeModel::search_text (const QModelIndex &index) const return tl::to_qstring (search_string_from_names (circuits)); } -std::pair, db::NetlistCrossReference::Status> +std::pair, std::pair > NetlistBrowserTreeModel::cp_status_from_index (const QModelIndex &index, size_t &nprod, size_t &nlast, size_t &nnlast) const { - typedef std::pair, db::NetlistCrossReference::Status> cp_status; + typedef std::pair, std::pair > cp_status; void *id = index.internalPointer (); tl_assert (id != 0); @@ -251,7 +251,7 @@ NetlistBrowserTreeModel::build_circuits_to_index (size_t nprod, const std::pair< size_t child_nprod = nprod * (count + 1); for (size_t n = count; n > 0; ) { - std::pair, IndexedNetlistModel::Status> cp = mp_indexer->child_circuit_from_index (circuits, n - 1); + std::pair, std::pair > cp = mp_indexer->child_circuit_from_index (circuits, n - 1); QModelIndex child_index = createIndex (int (n - 1), 0, reinterpret_cast (size_t (index.internalPointer ()) + nprod * n)); build_circuits_to_index (child_nprod, cp.first, model, child_index, map); --n; @@ -304,7 +304,7 @@ NetlistBrowserTreeModel::index_from_circuits (const std::pairtop_circuit_count (); for (size_t n = count; n > 0; ) { - std::pair, IndexedNetlistModel::Status> cp = mp_indexer->top_circuit_from_index (n - 1); + std::pair, std::pair > cp = mp_indexer->top_circuit_from_index (n - 1); build_circuits_to_index (count + 1, cp.first, mp_indexer.get (), createIndex (int (n - 1), 0, reinterpret_cast (n)), m_circuits_to_index); --n; } @@ -324,13 +324,13 @@ db::NetlistCrossReference::Status NetlistBrowserTreeModel::status (const QModelIndex &index) const { size_t nprod = 0, nlast = 0, nnlast = 0; - return cp_status_from_index (index, nprod, nlast, nnlast).second; + return cp_status_from_index (index, nprod, nlast, nnlast).second.first; } QVariant NetlistBrowserTreeModel::tooltip (const QModelIndex &index) const { - typedef std::pair, db::NetlistCrossReference::Status> cp_status; + typedef std::pair, std::pair > cp_status; size_t nlast = 0; std::string hint; diff --git a/src/laybasic/laybasic/layNetlistBrowserTreeModel.h b/src/laybasic/laybasic/layNetlistBrowserTreeModel.h index dfbc08d53..6bac31e60 100644 --- a/src/laybasic/laybasic/layNetlistBrowserTreeModel.h +++ b/src/laybasic/laybasic/layNetlistBrowserTreeModel.h @@ -88,7 +88,7 @@ private: QVariant tooltip (const QModelIndex &index) const; QString search_text (const QModelIndex &index) const; db::NetlistCrossReference::Status status (const QModelIndex &index) const; - std::pair, db::NetlistCrossReference::Status> cp_status_from_index (const QModelIndex &index, size_t &nprod, size_t &nlast, size_t &nnlast) const; + std::pair, std::pair > cp_status_from_index(const QModelIndex &index, size_t &nprod, size_t &nlast, size_t &nnlast) const; void build_circuits_to_index (size_t nprod, const std::pair &circuits, IndexedNetlistModel *model, const QModelIndex &index, std::map, QModelIndex> &map) const; db::LayoutToNetlist *mp_l2ndb; diff --git a/src/laybasic/laybasic/layNetlistCrossReferenceModel.cc b/src/laybasic/laybasic/layNetlistCrossReferenceModel.cc index a86958ce2..e458388c7 100644 --- a/src/laybasic/laybasic/layNetlistCrossReferenceModel.cc +++ b/src/laybasic/laybasic/layNetlistCrossReferenceModel.cc @@ -263,39 +263,39 @@ IndexedNetlistModel::circuit_pair NetlistCrossReferenceModel::parent_of (const I return get_parent_of (subcircuit_pair, mp_cross_ref.get (), m_parents_of_subcircuits); } -std::pair NetlistCrossReferenceModel::top_circuit_from_index (size_t index) const +std::pair > NetlistCrossReferenceModel::top_circuit_from_index (size_t index) const { build_top_circuit_list (mp_cross_ref.get (), m_top_level_circuits); IndexedNetlistModel::circuit_pair cp = m_top_level_circuits [index]; const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (cp); tl_assert (data != 0); - return std::make_pair (cp, data->status); + return std::make_pair (cp, std::make_pair (data->status, data->msg)); } -std::pair NetlistCrossReferenceModel::child_circuit_from_index (const circuit_pair &circuits, size_t index) const +std::pair > NetlistCrossReferenceModel::child_circuit_from_index (const circuit_pair &circuits, size_t index) const { build_child_circuit_map (mp_cross_ref.get (), m_child_circuits); IndexedNetlistModel::circuit_pair cp = m_child_circuits [circuits][index]; const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (cp); tl_assert (data != 0); - return std::make_pair (cp, data->status); + return std::make_pair (cp, std::make_pair (data->status, data->msg)); } -std::pair NetlistCrossReferenceModel::circuit_from_index (size_t index) const +std::pair > NetlistCrossReferenceModel::circuit_from_index (size_t index) const { IndexedNetlistModel::circuit_pair cp = mp_cross_ref->begin_circuits () [index]; const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (cp); tl_assert (data != 0); - return std::make_pair (cp, data->status); + return std::make_pair (cp, std::make_pair (data->status, data->msg)); } -std::pair NetlistCrossReferenceModel::net_from_index (const circuit_pair &circuits, size_t index) const +std::pair > NetlistCrossReferenceModel::net_from_index (const circuit_pair &circuits, size_t index) const { const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits); tl_assert (data != 0); - return std::make_pair (data->nets [index].pair, data->nets [index].status); + return std::make_pair (data->nets [index].pair, std::make_pair (data->nets [index].status, data->nets [index].msg)); } const db::Net *NetlistCrossReferenceModel::second_net_for (const db::Net *first) const @@ -484,25 +484,25 @@ IndexedNetlistModel::net_pin_pair NetlistCrossReferenceModel::net_pinref_from_in return data->pins [index]; } -std::pair NetlistCrossReferenceModel::device_from_index (const circuit_pair &circuits, size_t index) const +std::pair > NetlistCrossReferenceModel::device_from_index (const circuit_pair &circuits, size_t index) const { const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits); tl_assert (data != 0); - return std::make_pair (data->devices [index].pair, data->devices [index].status); + return std::make_pair (data->devices [index].pair, std::make_pair (data->devices [index].status, data->devices [index].msg)); } -std::pair NetlistCrossReferenceModel::pin_from_index (const circuit_pair &circuits, size_t index) const +std::pair > NetlistCrossReferenceModel::pin_from_index (const circuit_pair &circuits, size_t index) const { const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits); tl_assert (data != 0); - return std::make_pair (data->pins [index].pair, data->pins [index].status); + return std::make_pair (data->pins [index].pair, std::make_pair (data->pins [index].status, data->pins [index].msg)); } -std::pair NetlistCrossReferenceModel::subcircuit_from_index (const circuit_pair &circuits, size_t index) const +std::pair > NetlistCrossReferenceModel::subcircuit_from_index (const circuit_pair &circuits, size_t index) const { const db::NetlistCrossReference::PerCircuitData *data = mp_cross_ref->per_circuit_data_for (circuits); tl_assert (data != 0); - return std::make_pair (data->subcircuits [index].pair, data->subcircuits [index].status); + return std::make_pair (data->subcircuits [index].pair, std::make_pair (data->subcircuits [index].status, data->subcircuits [index].msg)); } template @@ -609,27 +609,37 @@ size_t NetlistCrossReferenceModel::subcircuit_index (const subcircuit_pair &subc return get_index_of (subcircuits, org_data->subcircuits.begin (), org_data->subcircuits.end (), data->index_of_subcircuits); } -std::string NetlistCrossReferenceModel::circuit_pair_status_hint (const std::pair &cps) const +std::string NetlistCrossReferenceModel::circuit_pair_status_hint (const std::pair > &cps) const { - if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) { + std::string msg; + + if (cps.second.first == db::NetlistCrossReference::Mismatch || cps.second.first == db::NetlistCrossReference::NoMatch) { if (! cps.first.first || ! cps.first.second) { - return tl::to_string (tr ("No matching circuit found in the other netlist.\n" - "By default, circuits are identified by their name.\n" - "A missing circuit probably means there is no circuit in the other netlist with this name.\n" - "If circuits with different names need to be associated, use 'same_circuits' in the\n" - "LVS script to establish such an association.")); + msg = tl::to_string (tr ("No matching circuit found in the other netlist.\n" + "By default, circuits are identified by their name.\n" + "A missing circuit probably means there is no circuit in the other netlist with this name.\n" + "If circuits with different names need to be associated, use 'same_circuits' in the\n" + "LVS script to establish such an association.")); } else { - return tl::to_string (tr ("Circuits could be paired, but there is a mismatch inside.\n" - "Browse the circuit's component list to identify the mismatching elements.")); + msg = tl::to_string (tr ("Circuits could be paired, but there is a mismatch inside.\n" + "Browse the circuit's component list to identify the mismatching elements.")); } - } else if (cps.second == db::NetlistCrossReference::Skipped) { - return tl::to_string (tr ("Circuits can only be matched if their child circuits have a known counterpart and a\n" - "pin-to-pin correspondence could be established for each child circuit.\n" - "This is not the case here. Browse the child circuits to identify the blockers.\n" - "Potential blockers are subcircuits without a corresponding other circuit or circuits\n" - "where some pins could not be mapped to pins from the corresponding other circuit.")); + } else if (cps.second.first == db::NetlistCrossReference::Skipped) { + msg = tl::to_string (tr ("Circuits can only be matched if their child circuits have a known counterpart and a\n" + "pin-to-pin correspondence could be established for each child circuit.\n" + "This is not the case here. Browse the child circuits to identify the blockers.\n" + "Potential blockers are subcircuits without a corresponding other circuit or circuits\n" + "where some pins could not be mapped to pins from the corresponding other circuit.")); } - return std::string (); + + if (! cps.second.second.empty ()) { + if (! msg.empty ()) { + msg += "\n\n"; + } + msg += cps.second.second; + } + + return msg; } std::string NetlistCrossReferenceModel::top_circuit_status_hint (size_t index) const @@ -644,94 +654,149 @@ std::string NetlistCrossReferenceModel::circuit_status_hint (size_t index) const std::string NetlistCrossReferenceModel::child_circuit_status_hint (const circuit_pair &circuits, size_t index) const { - std::pair cps = child_circuit_from_index (circuits, index); - if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) { + std::string msg; + + std::pair > cps = child_circuit_from_index (circuits, index); + + if (cps.second.first == db::NetlistCrossReference::Mismatch || cps.second.first == db::NetlistCrossReference::NoMatch) { if (!cps.first.first || !cps.first.second) { - return tl::to_string (tr ("No matching subcircuit was found in the other netlist - this is likely because pin\n" - "assignment could not be derived from the nets connected to the pins.\n" - "Check, if the pins are attached properly. If pins need to be swappable, consider using\n" - "'equivalent_pins' in the LVS script.")); + msg = tl::to_string (tr ("No matching subcircuit was found in the other netlist - this is likely because pin\n" + "assignment could not be derived from the nets connected to the pins.\n" + "Check, if the pins are attached properly. If pins need to be swappable, consider using\n" + "'equivalent_pins' in the LVS script.")); } else { - return tl::to_string (tr ("Two different subcircuits fit here in the same way, but they are not\n" - "originating from equivalent circuits.\n" - "If the circuits behind the subcircuits are identical, using 'same_circuits'\n" - "in the LVS script will associate them.")); + msg = tl::to_string (tr ("Two different subcircuits fit here in the same way, but they are not\n" + "originating from equivalent circuits.\n" + "If the circuits behind the subcircuits are identical, using 'same_circuits'\n" + "in the LVS script will associate them.")); } } - return std::string (); + + if (! cps.second.second.empty ()) { + if (! msg.empty ()) { + msg += "\n\n"; + } + msg += cps.second.second; + } + + return msg; } std::string NetlistCrossReferenceModel::net_status_hint (const circuit_pair &circuits, size_t index) const { - std::pair cps = net_from_index (circuits, index); - if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) { - return tl::to_string (tr ("Nets don't match. Nets match, if connected subcircuit pins and device terminals match to a\n" - "counterpart in the other netlist (component-wise and pin/terminal-wise).\n" - "If there already is a net candidate from the other netlist, scan the net members for\n" - "mismatching items (with errors or warnings) and fix these issues.\n" - "Otherwise, look for the corresponding other net.\n" - "Net items not found in the reference netlist indicate additional connections.\n" - "Net items only found in the reference netlist indicate missing connections.")); - } else if (cps.second == db::NetlistCrossReference::MatchWithWarning) { - return tl::to_string (tr ("Nets match, but the choice was ambiguous. This may lead to mismatching nets in other places.\n")); + std::string msg; + + std::pair > cps = net_from_index (circuits, index); + + if (cps.second.first == db::NetlistCrossReference::Mismatch || cps.second.first == db::NetlistCrossReference::NoMatch) { + msg = tl::to_string (tr ("Nets don't match. Nets match, if connected subcircuit pins and device terminals match to a\n" + "counterpart in the other netlist (component-wise and pin/terminal-wise).\n" + "If there already is a net candidate from the other netlist, scan the net members for\n" + "mismatching items (with errors or warnings) and fix these issues.\n" + "Otherwise, look for the corresponding other net.\n" + "Net items not found in the reference netlist indicate additional connections.\n" + "Net items only found in the reference netlist indicate missing connections.")); + } else if (cps.second.first == db::NetlistCrossReference::MatchWithWarning) { + msg = tl::to_string (tr ("Nets match, but the choice was ambiguous. This may lead to mismatching nets in other places.\n")); } - return std::string (); + + if (! cps.second.second.empty ()) { + if (! msg.empty ()) { + msg += "\n\n"; + } + msg += cps.second.second; + } + + return msg; } std::string NetlistCrossReferenceModel::device_status_hint (const circuit_pair &circuits, size_t index) const { - std::pair cps = device_from_index (circuits, index); - if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) { + std::string msg; + + std::pair > cps = device_from_index (circuits, index); + + if (cps.second.first == db::NetlistCrossReference::Mismatch || cps.second.first == db::NetlistCrossReference::NoMatch) { if (!cps.first.first || !cps.first.second) { - return tl::to_string (tr ("No matching device was found in the other netlist.\n" - "Devices are identified by the nets they are attached to. Unmatched devices mean that\n" - "at least one terminal net isn't matched with a corresponding net from the other netlist.\n" - "Make all terminal nets match and the devices will match too.")); + msg = tl::to_string (tr ("No matching device was found in the other netlist.\n" + "Devices are identified by the nets they are attached to. Unmatched devices mean that\n" + "at least one terminal net isn't matched with a corresponding net from the other netlist.\n" + "Make all terminal nets match and the devices will match too.")); } else { - return tl::to_string (tr ("Devices don't match topologically.\n" - "Check the terminal connections to identify the terminals not being connected to\n" - "corresponding nets. Either the devices are not connected correctly or the nets\n" - "need to be fixed before the devices will match too.")); + msg = tl::to_string (tr ("Devices don't match topologically.\n" + "Check the terminal connections to identify the terminals not being connected to\n" + "corresponding nets. Either the devices are not connected correctly or the nets\n" + "need to be fixed before the devices will match too.")); } - } else if (cps.second == db::NetlistCrossReference::MatchWithWarning) { - return tl::to_string (tr ("Topologically matching devices are found here but either the parameters or the\n" - "device classes don't match.\n" - "If the device class is different but should be considered the same, using\n" - "'same_device_classed' in the LVS script will solve this issue.")); + } else if (cps.second.first == db::NetlistCrossReference::MatchWithWarning) { + msg = tl::to_string (tr ("Topologically matching devices are found here but either the parameters or the\n" + "device classes don't match.\n" + "If the device class is different but should be considered the same, using\n" + "'same_device_classed' in the LVS script will solve this issue.")); } - return std::string (); + + if (! cps.second.second.empty ()) { + if (! msg.empty ()) { + msg += "\n\n"; + } + msg += cps.second.second; + } + + return msg; } std::string NetlistCrossReferenceModel::pin_status_hint (const circuit_pair &circuits, size_t index) const { - std::pair cps = pin_from_index (circuits, index); - if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) { + std::string msg; + + std::pair > cps = pin_from_index (circuits, index); + + if (cps.second.first == db::NetlistCrossReference::Mismatch || cps.second.first == db::NetlistCrossReference::NoMatch) { if (!cps.first.first || !cps.first.second) { - return tl::to_string (tr ("No matching pin was found in the other netlist.\n" - "Pins are identified by the nets they are attached to - pins on equivalent nets are also\n" - "equivalent. Making the nets match will make the pins match too.")); + msg = tl::to_string (tr ("No matching pin was found in the other netlist.\n" + "Pins are identified by the nets they are attached to - pins on equivalent nets are also\n" + "equivalent. Making the nets match will make the pins match too.")); } } - return std::string (); + + if (! cps.second.second.empty ()) { + if (! msg.empty ()) { + msg += "\n\n"; + } + msg += cps.second.second; + } + + return msg; } std::string NetlistCrossReferenceModel::subcircuit_status_hint (const circuit_pair &circuits, size_t index) const { - std::pair cps = subcircuit_from_index (circuits, index); - if (cps.second == db::NetlistCrossReference::Mismatch || cps.second == db::NetlistCrossReference::NoMatch) { + std::string msg; + + std::pair > cps = subcircuit_from_index (circuits, index); + + if (cps.second.first == db::NetlistCrossReference::Mismatch || cps.second.first == db::NetlistCrossReference::NoMatch) { if (!cps.first.first || !cps.first.second) { - return tl::to_string (tr ("No matching subcircuit was found in the other netlist - this is likely because pin assignment\n" - "could not be derived from the nets connected to the pins.\n" - "Check, if the pins are attached properly. If pins need to be swappable, consider using\n" - "'equivalent_pins' in the LVS script.")); + msg = tl::to_string (tr ("No matching subcircuit was found in the other netlist - this is likely because pin assignment\n" + "could not be derived from the nets connected to the pins.\n" + "Check, if the pins are attached properly. If pins need to be swappable, consider using\n" + "'equivalent_pins' in the LVS script.")); } else { - return tl::to_string (tr ("Two different subcircuits fit here in the same way, but they are not originating from\n" - "equivalent circuits.\n" - "If the circuits behind the subcircuits are identical, using 'same_circuits' in the LVS script\n" - "will associate them.")); + msg = tl::to_string (tr ("Two different subcircuits fit here in the same way, but they are not originating from\n" + "equivalent circuits.\n" + "If the circuits behind the subcircuits are identical, using 'same_circuits' in the LVS script\n" + "will associate them.")); } } - return std::string (); + + if (! cps.second.second.empty ()) { + if (! msg.empty ()) { + msg += "\n\n"; + } + msg += cps.second.second; + } + + return msg; } } diff --git a/src/laybasic/laybasic/layNetlistCrossReferenceModel.h b/src/laybasic/laybasic/layNetlistCrossReferenceModel.h index 6f9c4e325..cc1115f4e 100644 --- a/src/laybasic/laybasic/layNetlistCrossReferenceModel.h +++ b/src/laybasic/laybasic/layNetlistCrossReferenceModel.h @@ -59,24 +59,24 @@ public: virtual circuit_pair parent_of (const device_pair &device_pair) const; virtual circuit_pair parent_of (const subcircuit_pair &subcircuit_pair) const; - virtual std::pair top_circuit_from_index (size_t index) const; - virtual std::pair circuit_from_index (size_t index) const; - virtual std::pair child_circuit_from_index (const circuit_pair &circuits, size_t index) const; - virtual std::pair net_from_index (const circuit_pair &circuits, size_t index) const; + virtual std::pair > top_circuit_from_index(size_t index) const; + virtual std::pair > circuit_from_index (size_t index) const; + virtual std::pair > child_circuit_from_index(const circuit_pair &circuits, size_t index) const; + virtual std::pair > net_from_index (const circuit_pair &circuits, size_t index) const; virtual const db::Net *second_net_for (const db::Net *first) const; virtual const db::Circuit *second_circuit_for (const db::Circuit *first) const; virtual net_subcircuit_pin_pair net_subcircuit_pinref_from_index (const net_pair &nets, size_t index) const; virtual net_subcircuit_pin_pair subcircuit_pinref_from_index (const subcircuit_pair &nets, size_t index) const; virtual net_terminal_pair net_terminalref_from_index (const net_pair &nets, size_t index) const; virtual net_pin_pair net_pinref_from_index (const net_pair &nets, size_t index) const; - virtual std::pair device_from_index (const circuit_pair &circuits, size_t index) const; - virtual std::pair pin_from_index (const circuit_pair &circuits, size_t index) const; - virtual std::pair subcircuit_from_index (const circuit_pair &circuits, size_t index) const; + virtual std::pair > device_from_index (const circuit_pair &circuits, size_t index) const; + virtual std::pair > pin_from_index (const circuit_pair &circuits, size_t index) const; + virtual std::pair > subcircuit_from_index (const circuit_pair &circuits, size_t index) const; virtual std::string top_circuit_status_hint (size_t index) const; virtual std::string circuit_status_hint (size_t index) const; virtual std::string child_circuit_status_hint (const circuit_pair &circuits, size_t index) const; - virtual std::string circuit_pair_status_hint (const std::pair &cp) const; + virtual std::string circuit_pair_status_hint (const std::pair > &cp) const; virtual std::string net_status_hint (const circuit_pair &circuits, size_t index) const; virtual std::string device_status_hint (const circuit_pair &circuits, size_t index) const; virtual std::string pin_status_hint (const circuit_pair &circuits, size_t index) const; diff --git a/src/lvs/lvs/built-in-macros/lvs_interpreters.lym b/src/lvs/lvs/built-in-macros/lvs_interpreters.lym index 5c6e36eca..f9f9863f8 100644 --- a/src/lvs/lvs/built-in-macros/lvs_interpreters.lym +++ b/src/lvs/lvs/built-in-macros/lvs_interpreters.lym @@ -17,39 +17,52 @@ module LVS - def self.execute_lvs(macro, generator, l2ndb_index = nil) + class LVSExecutable < RBA::Executable - timer = RBA::Timer::new - timer.start - lvs = LVSEngine::new - lvs._l2ndb_index = l2ndb_index - lvs._generator = generator + def initialize(macro, generator, l2ndb_index = nil) - begin + @lvs = LVSEngine::new + @lvs._l2ndb_index = l2ndb_index + @lvs._generator = generator - # Set a debugger scope so that our errors end up with the debugger set to the LVS's line - RBA::MacroExecutionContext::set_debugger_scope(macro.path) - # No verbosity set in lvs engine - we cannot use the engine's logger - RBA::Logger::verbosity >= 10 && RBA::Logger::info("Running #{macro.path}") - lvs.instance_eval(macro.text, macro.path) - # Remove the debugger scope - RBA::MacroExecutionContext::remove_debugger_scope - - rescue => ex - - lvs.error("In #{macro.path}: #{ex.to_s}") - RBA::MacroExecutionContext::ignore_next_exception - raise ex - - ensure - - # cleans up and creates layout and report views - lvs._finish + @macro = macro end - timer.stop - lvs.info("Total run time: #{'%.3f'%(timer.sys+timer.user)}s") + def execute + + @lvs._start("LVS: " + @macro.path) + + # Set a debugger scope so that our errors end up with the debugger set to the LVS's line + RBA::MacroExecutionContext::set_debugger_scope(@macro.path) + + begin + + # No verbosity set in lvs engine - we cannot use the engine's logger + RBA::Logger::verbosity >= 10 && RBA::Logger::info("Running #{@macro.path}") + @lvs.instance_eval(@macro.text, @macro.path) + + rescue => ex + + @lvs.error("In #{@macro.path}: #{ex.to_s}") + RBA::MacroExecutionContext::ignore_next_exception + raise ex + + end + + nil + + end + + def cleanup + + # Remove the debugger scope + RBA::MacroExecutionContext::remove_debugger_scope + + # cleans up and creates layout and report views + @lvs._finish + + end end @@ -83,8 +96,8 @@ module LVS end # Implements the execute method - def execute(macro) - LVS::execute_lvs(macro, @recipe.generator("script" => macro.path)) + def executable(macro) + LVSExecutable::new(macro, @recipe.generator("script" => macro.path)) end end @@ -110,8 +123,8 @@ module LVS end # Implements the execute method - def execute(macro) - LVS::execute_lvs(macro, @recipe.generator("script" => macro.path)) + def executable(macro) + LVSExecutable::new(macro, @recipe.generator("script" => macro.path)) end end @@ -123,7 +136,7 @@ module LVS super("lvs", "LVS recipe") end - def execute(params) + def executable(params) script = params["script"] if ! script @@ -133,7 +146,7 @@ module LVS macro = RBA::Macro::macro_by_path(script) macro || raise("Can't find LVS script #{script} - unable to re-run") - LVS::execute_lvs(macro, self.generator("script" => script), params["l2ndb_index"]) + LVSExecutable::new(macro, self.generator("script" => script), params["l2ndb_index"]) end diff --git a/src/lvs/unit_tests/lvsTests.cc b/src/lvs/unit_tests/lvsTests.cc index f6e5c6314..b4aa56f4e 100644 --- a/src/lvs/unit_tests/lvsTests.cc +++ b/src/lvs/unit_tests/lvsTests.cc @@ -30,7 +30,7 @@ #include "lymMacro.h" #include "tlFileUtils.h" -void run_test (tl::TestBase *_this, const std::string &lvs_rs, const std::string &au_netlist, const std::string &layout, bool priv = false) +void run_test (tl::TestBase *_this, const std::string &lvs_rs, const std::string &au_netlist, const std::string &layout, bool priv = false, const std::string &au_lvsdb_name = std::string ()) { std::string testsrc = priv ? tl::testsrc_private () : tl::testsrc (); testsrc = tl::combine_path (tl::combine_path (testsrc, "testdata"), "lvs"); @@ -88,6 +88,11 @@ void run_test (tl::TestBase *_this, const std::string &lvs_rs, const std::string tl::info << " golden: " << au_cir; } EXPECT_EQ (res, true); + + if (! au_lvsdb_name.empty ()) { + std::string au_lvsdb = tl::combine_path (testsrc, au_lvsdb_name); + _this->compare_text_files (output_lvsdb, au_lvsdb); + } } TEST(1_full) @@ -143,3 +148,9 @@ TEST(16_private) // test_is_long_runner (); run_test (_this, "test_16.lvs", "test_16.cir.gz", "test_16.gds.gz", true); } + +TEST(17_private) +{ + test_is_long_runner (); + run_test (_this, "test_17.lylvs", "test_17.cir.gz", "test_17.gds.gz", true, "test_17.lvsdb"); +} diff --git a/src/lym/lym/gsiDeclLymMacro.cc b/src/lym/lym/gsiDeclLymMacro.cc index dd97463e1..db8d67517 100644 --- a/src/lym/lym/gsiDeclLymMacro.cc +++ b/src/lym/lym/gsiDeclLymMacro.cc @@ -142,10 +142,12 @@ public: m_name = name; } - virtual void execute (const lym::Macro *macro) const + virtual tl::Executable *executable (const lym::Macro *macro) const { - if (f_execute.can_issue ()) { - f_execute.issue (&MacroInterpreter::execute, macro); + if (f_executable.can_issue ()) { + return f_executable.issue (&MacroInterpreter::executable, macro); + } else { + return 0; } } @@ -240,7 +242,7 @@ public: } } - gsi::Callback f_execute; + gsi::Callback f_executable; private: tl::RegisteredClass *mp_registration; @@ -307,7 +309,7 @@ Class decl_MacroInterpreter ("lay", "MacroInterpreter", ) + gsi::method ("create_template", &MacroInterpreter::create_template, gsi::arg ("url"), "@brief Creates a new macro template\n" - "@url The template will be initialized from that URL.\n" + "@param url The template will be initialized from that URL.\n" "\n" "This method will create a register a new macro template. It returns a \\Macro object which " "can be modified in order to adjust the template (for example to set description, add a content, " @@ -378,13 +380,15 @@ Class decl_MacroInterpreter ("lay", "MacroInterpreter", "Before version 0.25 this attribute was a reimplementable method. It has been turned into an attribute for " "performance reasons in version 0.25.\n" ) + - gsi::callback ("execute", &gsi::MacroInterpreter::execute, &gsi::MacroInterpreter::f_execute, gsi::arg ("macro"), - "@brief Gets called to execute a macro\n" - "This method must be reimplemented to execute the macro. " - "The system will call this script when a macro with interpreter type 'dsl' and the " - "name of this interpreter is run." + gsi::callback ("executable", &gsi::MacroInterpreter::executable, &gsi::MacroInterpreter::f_executable, gsi::arg ("macro"), + "@brief Returns the executable object which implements the macro execution\n" + "This method must be reimplemented to return an \\Executable object for the actual implementation. " + "The system will use this function to execute the script when a macro with interpreter type 'dsl' and the " + "name of this interpreter is run.\n" "\n" "@param macro The macro to execute\n" + "\n" + "This method has been introduced in version 0.27 and replaces the 'execute' method.\n" ), "@brief A custom interpreter for a DSL (domain specific language)\n" "\n" @@ -413,6 +417,21 @@ Class decl_MacroInterpreter ("lay", "MacroInterpreter", "just evaluates the script text:\n" "\n" "@code\n" + "class SimpleExecutable < RBA::Excutable\n" + "\n" + " # Constructor\n" + " def initialize(macro)\n" + " \\@macro = macro\n" + " end\n" + " \n" + " # Implements the execute method\n" + " def execute\n" + " eval(\\@macro.text, nil, \\@macro.path)\n" + " nil\n" + " end\n" + "\n" + "end\n" + "\n" "class SimpleInterpreter < RBA::MacroInterpreter\n" "\n" " # Constructor\n" @@ -427,9 +446,9 @@ Class decl_MacroInterpreter ("lay", "MacroInterpreter", " mt.description = \"Special;;Simple interpreter macro\"\n" " end\n" " \n" - " # Implements the execute method\n" - " def execute(macro)\n" - " eval(macro.text, nil, macro.path)\n" + " # Creates the executable delegate\n" + " def executable(macro)\n" + " SimpleExecutable::new(macro)\n" " end\n" "\n" "end\n" @@ -447,7 +466,7 @@ Class decl_MacroInterpreter ("lay", "MacroInterpreter", "\n" "In order to make the above code effective, store the code in an macro, set \"early auto-run\" and restart KLayout.\n" "\n" - "This class has been introduced in version 0.23.\n" + "This class has been introduced in version 0.23 and modified in 0.27.\n" ); static lym::Macro *macro_by_path (const std::string &path) diff --git a/src/lym/lym/lymMacroInterpreter.cc b/src/lym/lym/lymMacroInterpreter.cc index bfad060fe..01819d6c4 100644 --- a/src/lym/lym/lymMacroInterpreter.cc +++ b/src/lym/lym/lymMacroInterpreter.cc @@ -32,10 +32,10 @@ namespace lym { -void -MacroInterpreter::execute (const lym::Macro *) const +tl::Executable * +MacroInterpreter::executable (const lym::Macro *) const { - throw tl::Exception (tl::to_string (QObject::tr ("execute() implementation missing for DSL interpreter"))); + throw tl::Exception (tl::to_string (QObject::tr ("executable() implementation missing for DSL interpreter"))); } bool @@ -107,7 +107,10 @@ MacroInterpreter::execute_macro (const lym::Macro *macro) std::pair et = cls->include_expansion (macro); if (et.first.empty () || et.first == macro->path ()) { - cls->execute (macro); + std::unique_ptr eo (cls->executable (macro)); + if (eo.get ()) { + eo->do_execute (); + } } else { @@ -116,7 +119,10 @@ MacroInterpreter::execute_macro (const lym::Macro *macro) tmp_macro.assign (*macro); tmp_macro.set_text (et.second); tmp_macro.set_file_path (et.first); - cls->execute (&tmp_macro); + std::unique_ptr eo (cls->executable (&tmp_macro)); + if (eo.get ()) { + eo->do_execute (); + } } diff --git a/src/lym/lym/lymMacroInterpreter.h b/src/lym/lym/lymMacroInterpreter.h index 3de6e6448..17435e9a8 100644 --- a/src/lym/lym/lymMacroInterpreter.h +++ b/src/lym/lym/lymMacroInterpreter.h @@ -26,6 +26,7 @@ #include "lymCommon.h" +#include "tlRecipe.h" #include "gsiObject.h" #include "tlClassRegistry.h" @@ -63,11 +64,11 @@ public: } /** - * @brief Executes the macro + * @brief Creates the executable for a macro * - * This method must be reimplemented to provide the actual execution of the macro. + * The caller will delete the returned object. */ - virtual void execute (const lym::Macro *macro) const; + virtual tl::Executable *executable (const lym::Macro *macro) const; /** * @brief Returns the storage scheme diff --git a/src/tl/tl/tlProgress.cc b/src/tl/tl/tlProgress.cc index 88d7e4ee0..1315ad65e 100644 --- a/src/tl/tl/tlProgress.cc +++ b/src/tl/tl/tlProgress.cc @@ -49,7 +49,11 @@ ProgressAdaptor::~ProgressAdaptor () void ProgressAdaptor::register_object (Progress *progress) { + bool cancelled = ! mp_objects.empty () && mp_objects.first ()->break_scheduled (); mp_objects.push_back (progress); // this keeps the outmost one visible. push_front would make the latest one visible. + if (cancelled) { + progress->signal_break (); + } } void @@ -130,15 +134,19 @@ ProgressGarbageCollector::~ProgressGarbageCollector () // store a pointer but a pointer to a pointer. static tl::ThreadStorage s_thread_data; -Progress::Progress (const std::string &desc, size_t yield_interval) +const double yield_timeout = 0.3; +const size_t default_yield_interval = 1000; + +Progress::Progress (const std::string &desc, size_t yield_interval, bool can_cancel) : m_desc (desc), m_title (desc), m_interval_count (0), - m_yield_interval (yield_interval), + m_yield_interval (yield_interval == 0 ? default_yield_interval : yield_interval), m_last_value (-1.0), - m_can_cancel (true), - m_cancelled (false) + m_can_cancel (can_cancel), + m_cancelled (false), + m_registered (false) { - // .. nothing yet .. + m_last_yield = tl::Clock::current (); } Progress::~Progress () @@ -149,9 +157,19 @@ Progress::~Progress () void Progress::initialize () { + // The abstract progress does not get test() calls so we need to register it now. ProgressAdaptor *a = adaptor (); if (a) { + a->register_object (this); + m_registered = true; + + // A pending cancel request may immediately kill the operation - "register_object" will set the cancelled flag then. + if (m_cancelled) { + m_cancelled = false; + throw tl::BreakException (); + } + } } @@ -159,7 +177,7 @@ void Progress::shutdown () { ProgressAdaptor *a = adaptor (); - if (a) { + if (a && m_registered) { a->unregister_object (this); } } @@ -192,29 +210,27 @@ Progress::adaptor () void Progress::signal_break () { - m_cancelled = true; + if (m_can_cancel) { + m_cancelled = true; + } } void Progress::set_desc (const std::string &d) { - ProgressAdaptor *a = adaptor (); - if (a && d != m_desc) { - + if (d != m_desc) { m_desc = d; - a->trigger (this); - a->yield (this); - - if (m_cancelled) { - m_cancelled = false; - throw tl::BreakException (); - } - + test (true); } } -bool Progress::test(bool force_yield) +bool Progress::test (bool force_yield) { + if (m_cancelled) { + m_cancelled = false; + throw tl::BreakException (); + } + if (++m_interval_count >= m_yield_interval || force_yield) { ProgressAdaptor *a = adaptor (); @@ -226,22 +242,28 @@ bool Progress::test(bool force_yield) needs_trigger = true; } + if (m_desc != m_last_desc) { + m_last_desc = m_desc; + needs_trigger = true; + } + m_interval_count = 0; if (a) { + tl::Clock now = tl::Clock::current (); - if ((now - m_last_yield).seconds () > 0.1) { + if ((now - m_last_yield).seconds () > yield_timeout) { + m_last_yield = now; + if (needs_trigger) { a->trigger (this); } - a->yield (this); - } - } - if (m_cancelled) { - m_cancelled = false; - throw tl::BreakException (); + a->yield (this); + + } + } return true; @@ -268,8 +290,8 @@ AbstractProgress::~AbstractProgress () // --------------------------------------------------------------------------------------------- // RelativeProgress implementation -RelativeProgress::RelativeProgress (const std::string &desc, size_t max_count, size_t yield_interval) - : Progress (desc, yield_interval) +RelativeProgress::RelativeProgress (const std::string &desc, size_t max_count, size_t yield_interval, bool can_cancel) + : Progress (desc, yield_interval, can_cancel) { m_format = "%.0f%%"; m_unit = double (max_count) / 100.0; @@ -313,8 +335,8 @@ RelativeProgress::set (size_t count, bool force_yield) // --------------------------------------------------------------------------------------------- // Progress implementation -AbsoluteProgress::AbsoluteProgress (const std::string &desc, size_t yield_interval) - : Progress (desc, yield_interval) +AbsoluteProgress::AbsoluteProgress (const std::string &desc, size_t yield_interval, bool can_cancel) + : Progress (desc, yield_interval, can_cancel) { m_format = "%.0f"; m_unit = 1.0; diff --git a/src/tl/tl/tlProgress.h b/src/tl/tl/tlProgress.h index e0001cd28..13dce6791 100644 --- a/src/tl/tl/tlProgress.h +++ b/src/tl/tl/tlProgress.h @@ -185,8 +185,9 @@ public: * * @param desc The description and title string * @param yield_interval See above. + * @param can_cancel If set to true, the progress may be cancelled which results in a BreakException begin raised */ - Progress (const std::string &desc, size_t yield_interval = 1000); + Progress (const std::string &desc, size_t yield_interval = 0, bool can_cancel = true); /** * @brief The destructor @@ -228,17 +229,6 @@ public: */ virtual void render_progress (QWidget * /*widget*/) const { } - /** - * @brief Set a value indicating whether the operation can be cancelled - * - * The progress object will throw a BreakException is cancelled and this - * flag is set to true. The default is "true". - */ - void can_cancel (bool f) - { - m_can_cancel = f; - } - /** * @brief Gets a value indicating whether the operation can be cancelled */ @@ -273,6 +263,14 @@ public: */ void signal_break (); + /** + * @brief Returns true, if a break is scheduled + */ + bool break_scheduled () const + { + return m_cancelled; + } + protected: /** * @brief Indicates that a new value has arrived @@ -296,13 +294,14 @@ private: friend class ProgressAdaptor; friend class ProgressGarbageCollector; - std::string m_desc; + std::string m_desc, m_last_desc; std::string m_title; size_t m_interval_count; size_t m_yield_interval; double m_last_value; bool m_can_cancel; bool m_cancelled; + bool m_registered; tl::Clock m_last_yield; static tl::ProgressAdaptor *adaptor (); @@ -365,8 +364,9 @@ public: * @param desc The description and title string * @param max_count The limit "max" value. 0 for absolute display of values. * @param yield_interval See above. + * @param can_cancel If set to true, the progress may be cancelled which results in a BreakException begin raised */ - RelativeProgress (const std::string &desc, size_t max_count = 0, size_t yield_interval = 1000); + RelativeProgress (const std::string &desc, size_t max_count = 0, size_t yield_interval = 0, bool can_cancel = true); ~RelativeProgress (); @@ -442,7 +442,7 @@ public: * @param desc The description and title string * @param yield_interval See above. */ - AbsoluteProgress (const std::string &desc, size_t yield_interval = 1000); + AbsoluteProgress (const std::string &desc, size_t yield_interval = 0, bool can_cancel = true); /** * @brief Destructor diff --git a/src/tl/tl/tlRecipe.cc b/src/tl/tl/tlRecipe.cc index 72d8e5d48..f3bda5fcd 100644 --- a/src/tl/tl/tlRecipe.cc +++ b/src/tl/tl/tlRecipe.cc @@ -22,10 +22,73 @@ #include "tlRecipe.h" #include "tlString.h" +#include "tlLog.h" +#include "tlException.h" + +#include namespace tl { +// -------------------------------------------------------------------------------------- +// Executable implementation + +Executable::Executable () +{ + // .. nothing yet .. +} + +Executable::~Executable () +{ + // .. nothing yet .. +} + +tl::Variant +Executable::do_execute () +{ + tl::Variant res; + + try { + res = execute (); + do_cleanup (); + } catch (...) { + do_cleanup (); + throw; + } + + return res; +} + +void +Executable::do_cleanup () +{ + try { + cleanup (); + } catch (tl::Exception &ex) { + tl::error << ex.msg (); + } catch (std::runtime_error &ex) { + tl::error << ex.what (); + } catch (...) { + // ignore exceptions here + } +} + +tl::Variant +Executable::execute () +{ + // .. the default implementation does nothing .. + return tl::Variant (); +} + +void +Executable::cleanup () +{ + // .. the default implementation does nothing .. +} + +// -------------------------------------------------------------------------------------- +// Recipe implementation + Recipe::Recipe (const std::string &name, const std::string &description) : tl::RegisteredClass (this, 0, name.c_str (), false) { @@ -83,9 +146,14 @@ tl::Variant Recipe::make (const std::string &generator, const std::mapexecute (params); } + + std::unique_ptr eo (recipe_obj->executable (params)); + if (! eo.get ()) { + return tl::Variant (); + } + + return eo->do_execute (); } } // namespace tl diff --git a/src/tl/tl/tlRecipe.h b/src/tl/tl/tlRecipe.h index 6e502d471..298d6601c 100644 --- a/src/tl/tl/tlRecipe.h +++ b/src/tl/tl/tlRecipe.h @@ -32,6 +32,80 @@ namespace tl { +/** + * @brief A base class for an executable item + * + * This is a little more than just a function: it also provides a post-mortem + * action (cleanup). This is useful for script-based applications: as the + * main thread can be terminated in the debugger through ExitException unconditionally, + * cleanup() provides a way to implement actions after such an event. + */ + +class TL_PUBLIC Executable +{ +public: + Executable (); + virtual ~Executable (); + + /** + * @brief Runs the function with error handling and cleanup + */ + tl::Variant do_execute (); + + /** + * @brief Runs the specific job + */ + virtual tl::Variant execute (); + + /** + * @brief Called after the job terminated + */ + virtual void cleanup (); + +private: + void do_cleanup (); +}; + +/** + * @brief Provides a convenience class for an executable with parameters + */ +class TL_PUBLIC ExecutableWithParameters + : public Executable +{ +public: + ExecutableWithParameters (const std::map ¶ms) + : m_params (params) + { } + + /** + * @brief An utility function to get a parameter + */ + template + static T get_value (const std::map ¶ms, const std::string &pname, const T &def_value) + { + std::map::const_iterator p = params.find (pname); + if (p != params.end ()) { + const tl::Variant &v = p->second; + return v.to (); + } else { + return def_value; + } + } + + /** + * @brief Gets the parameters + */ + const std::map ¶meters () const + { + return m_params; + } + +private: + std::map m_params; + + void do_cleanup (); +}; + /** * @brief A facility for providing reproducable recipes * @@ -80,21 +154,6 @@ public: return m_description; } - /** - * @brief An utility function to get a parameters - */ - template - static T get_value (const std::map ¶ms, const std::string &pname, const T &def_value) - { - std::map::const_iterator p = params.find (pname); - if (p != params.end ()) { - const tl::Variant &v = p->second; - return v.to (); - } else { - return def_value; - } - } - /** * @brief Serializes the given recipe */ @@ -110,9 +169,11 @@ public: static tl::Variant make (const std::string &generator, const std::map ¶ms = std::map ()); /** - * @brief Recipe interface: executes the recipe with the given parameters + * @brief Returns the executable object which actually implements the action to take + * + * The returned object is deleted by the caller. */ - virtual tl::Variant execute (const std::map ¶ms) const = 0; + virtual Executable *executable (const std::map ¶ms) const = 0; private: Recipe (const Recipe &) : tl::RegisteredClass (this) { } diff --git a/src/tl/unit_tests/tlRecipeTests.cc b/src/tl/unit_tests/tlRecipeTests.cc index 714cad84d..8a555b9ee 100644 --- a/src/tl/unit_tests/tlRecipeTests.cc +++ b/src/tl/unit_tests/tlRecipeTests.cc @@ -27,18 +27,40 @@ namespace { + class MyExecutable : public tl::ExecutableWithParameters + { + public: + static bool cleanup_called; + + MyExecutable (const std::map ¶ms) + : tl::ExecutableWithParameters (params) + { } + + tl::Variant execute () + { + int a = get_value (parameters (), "A", 0); + double b = get_value (parameters (), "B", 0.0); + double c = get_value (parameters (), "C", 1.0); + bool crash = get_value (parameters (), "X", false); + if (crash) { + throw tl::Exception ("crashed"); + } + return tl::Variant (b * a * c); + } + + void cleanup () + { + cleanup_called = true; + } + }; + + bool MyExecutable::cleanup_called = false; + class MyRecipe : public tl::Recipe { public: MyRecipe () : tl::Recipe ("test_recipe", "description") { } - - tl::Variant execute (const std::map ¶ms) const - { - int a = get_value (params, "A", 0); - double b = get_value (params, "B", 0.0); - double c = get_value (params, "C", 1.0); - return tl::Variant (b * a * c); - } + tl::Executable *executable (const std::map ¶ms) const { return new MyExecutable (params); } }; static MyRecipe my_recipe; @@ -54,11 +76,24 @@ TEST(1) std::string g = my_recipe.generator (params); EXPECT_EQ (g, "test_recipe: A=#7,B=##6"); + MyExecutable::cleanup_called = false; tl::Variant res = tl::Recipe::make (g); EXPECT_EQ (res.to_double (), 42.0); + EXPECT_EQ (MyExecutable::cleanup_called, true); std::map padd; padd["C"] = tl::Variant(1.5); res = tl::Recipe::make (g, padd); EXPECT_EQ (res.to_double (), 63.0); + + MyExecutable::cleanup_called = false; + padd.clear (); + padd["X"] = tl::Variant(true); + try { + res = tl::Recipe::make (g, padd); + EXPECT_EQ (1, 0); + } catch (tl::Exception &ex) { + EXPECT_EQ (ex.msg (), "crashed"); + } + EXPECT_EQ (MyExecutable::cleanup_called, true); } diff --git a/testdata/drc/drcSimpleTests_20.drc b/testdata/drc/drcSimpleTests_20.drc index 5468d4f58..36eb31718 100644 --- a/testdata/drc/drcSimpleTests_20.drc +++ b/testdata/drc/drcSimpleTests_20.drc @@ -12,6 +12,18 @@ l2 = input(2, 0) l1.output(1, 0) l2.output(2, 0) +def split_vs_normal(r, f1, f2, *args) + d1 = r.send(f1, *args)[0].data + d2 = r.send(f2, *args).data + d1.to_s == d2.to_s || raise("#{f1.to_s} vs. #{f2.to_s} check failed: #{d1.to_s} != #{d2.to_s}") +end + +def splitn_vs_normal(r, f1, f2, *args) + d1 = r.send(f1, *args)[1].data + d2 = r.send(f2, *args).data + d1.to_s == d2.to_s || raise("#{f1.to_s} vs. #{f2.to_s} check failed: #{d1.to_s} != #{d2.to_s}") +end + l1.interacting(l2, 1).output(100, 0) l1.interacting(l2, 2).output(101, 0) l1.interacting(l2, 1..2).output(102, 0) @@ -22,6 +34,11 @@ else end l1.interacting(l2, 1, 2).output(104, 0) +split_vs_normal(l1, :split_interacting, :interacting, l2, 1) +split_vs_normal(l1, :split_interacting, :interacting, l2, 2) +split_vs_normal(l1, :split_interacting, :interacting, l2, 1..2) +split_vs_normal(l1, :split_interacting, :interacting, l2, 1, 2) + l1.overlapping(l2, 1).output(110, 0) l1.overlapping(l2, 2).output(111, 0) l1.overlapping(l2, 1..2).output(112, 0) @@ -32,6 +49,11 @@ else end l1.overlapping(l2, 1, 2).output(114, 0) +split_vs_normal(l1, :split_overlapping, :overlapping, l2, 1) +split_vs_normal(l1, :split_overlapping, :overlapping, l2, 2) +split_vs_normal(l1, :split_overlapping, :overlapping, l2, 1..2) +split_vs_normal(l1, :split_overlapping, :overlapping, l2, 1, 2) + l = l1.dup l.select_interacting(l2, 1) l.output(200, 0) @@ -82,6 +104,11 @@ else end l1.not_interacting(l2, 1, 2).output(304, 0) +splitn_vs_normal(l1, :split_interacting, :not_interacting, l2, 1) +splitn_vs_normal(l1, :split_interacting, :not_interacting, l2, 2) +splitn_vs_normal(l1, :split_interacting, :not_interacting, l2, 1..2) +splitn_vs_normal(l1, :split_interacting, :not_interacting, l2, 1, 2) + l1.not_overlapping(l2, 1).output(310, 0) l1.not_overlapping(l2, 2).output(311, 0) l1.not_overlapping(l2, 1..2).output(312, 0) @@ -92,6 +119,11 @@ else end l1.not_overlapping(l2, 1, 2).output(314, 0) +splitn_vs_normal(l1, :split_overlapping, :not_overlapping, l2, 1) +splitn_vs_normal(l1, :split_overlapping, :not_overlapping, l2, 2) +splitn_vs_normal(l1, :split_overlapping, :not_overlapping, l2, 1..2) +splitn_vs_normal(l1, :split_overlapping, :not_overlapping, l2, 1, 2) + l = l1.dup l.select_not_interacting(l2, 1) l.output(400, 0) diff --git a/testdata/drc/drcSimpleTests_24.drc b/testdata/drc/drcSimpleTests_24.drc index 3b594e534..ad689e56f 100644 --- a/testdata/drc/drcSimpleTests_24.drc +++ b/testdata/drc/drcSimpleTests_24.drc @@ -10,11 +10,33 @@ b = input(2, 0) a.output(1, 0) b.output(2, 0) +def split_vs_normal(r, f1, f2, *args) + d1 = r.send(f1, *args)[0].data + d2 = r.send(f2, *args).data + d1.each.collect(&:to_s).sort == d2.each.collect(&:to_s).sort || raise("#{f1.to_s} vs. #{f2.to_s} check failed: #{d1.to_s} != #{d2.to_s}") +end + +def splitn_vs_normal(r, f1, f2, *args) + d1 = r.send(f1, *args)[1].data + d2 = r.send(f2, *args).data + d1.each.collect(&:to_s).sort == d2.each.collect(&:to_s).sort || raise("#{f1.to_s} vs. #{f2.to_s} check failed: #{d1.to_s} != #{d2.to_s}") +end + a.covering(b).output(100, 0) a.covering(b, 1..1).output(101, 0) a.covering(b, 2..2).output(102, 0) a.covering(b, 3..3).output(103, 0) b.inside(a).output(110, 0) +a.not_covering(b).output(120, 0) +b.not_inside(a).output(130, 0) + +split_vs_normal(a, :split_covering, :covering, b) +split_vs_normal(a, :split_covering, :covering, b, 1..1) +split_vs_normal(a, :split_covering, :covering, b, 2..2) +split_vs_normal(a, :split_covering, :covering, b, 3..3) +split_vs_normal(b, :split_inside, :inside, a) +splitn_vs_normal(a, :split_covering, :not_covering, b) +splitn_vs_normal(b, :split_inside, :not_inside, a) deep @@ -26,4 +48,14 @@ a.covering(b, 1..1).output(201, 0) a.covering(b, 2..2).output(202, 0) a.covering(b, 3..3).output(203, 0) b.inside(a).output(210, 0) +a.not_covering(b).output(220, 0) +b.not_inside(a).output(230, 0) + +split_vs_normal(a, :split_covering, :covering, b) +split_vs_normal(a, :split_covering, :covering, b, 1..1) +split_vs_normal(a, :split_covering, :covering, b, 2..2) +split_vs_normal(a, :split_covering, :covering, b, 3..3) +split_vs_normal(b, :split_inside, :inside, a) +splitn_vs_normal(a, :split_covering, :not_covering, b) +splitn_vs_normal(b, :split_inside, :not_inside, a) diff --git a/testdata/drc/drcSimpleTests_30.drc b/testdata/drc/drcSimpleTests_30.drc new file mode 100644 index 000000000..de3b78fee --- /dev/null +++ b/testdata/drc/drcSimpleTests_30.drc @@ -0,0 +1,18 @@ + +source $drc_test_source +target $drc_test_target + +b = input(0, 0) +a = input(1, 0) + +b.output(0, 0) +a.output(1, 0) + +a.with_density(0..0.1, tile_size(10.um), tile_boundary(b)).output(100, 0) +a.without_density(0..0.1, tile_size(10.um)).output(101, 0) +a.with_density(0.1, nil, tile_size(10.um), tile_origin(25.um, 10.um)).output(102, 0) +a.with_density(0.1, nil, tile_size(10.um, 20.um)).output(103, 0) +a.with_density(0.1, 1.0, tile_size(10.um), tile_step(10.um, 20.um)).output(104, 0) +a.with_density(0.1, nil, tile_size(10.um), tile_origin(25.um, 10.um), tile_count(10, 15)).output(105, 0) +a.with_density(0..0.1, tile_size(100.um), tile_step(10.um)).output(110, 0) + diff --git a/testdata/drc/drcSimpleTests_30.gds b/testdata/drc/drcSimpleTests_30.gds new file mode 100644 index 000000000..14b2f86b8 Binary files /dev/null and b/testdata/drc/drcSimpleTests_30.gds differ diff --git a/testdata/drc/drcSimpleTests_au24.gds b/testdata/drc/drcSimpleTests_au24.gds index 8ca7815d2..e650d083b 100644 Binary files a/testdata/drc/drcSimpleTests_au24.gds and b/testdata/drc/drcSimpleTests_au24.gds differ diff --git a/testdata/drc/drcSimpleTests_au30.gds b/testdata/drc/drcSimpleTests_au30.gds new file mode 100644 index 000000000..f09ab94b3 Binary files /dev/null and b/testdata/drc/drcSimpleTests_au30.gds differ diff --git a/testdata/drc/drcSuiteTests.drc b/testdata/drc/drcSuiteTests.drc index 9574e8e96..35615d564 100644 --- a/testdata/drc/drcSuiteTests.drc +++ b/testdata/drc/drcSuiteTests.drc @@ -148,6 +148,7 @@ def run_testsuite(dm, ic, tiled = false, hier = false) b.not_interacting(a).output(lb, dm + 1) b.interacting(empty).output(lb, dm + 2) b.not_interacting(empty).output(lb, dm + 3) + b.interacting(a).in(b).output(lb + 1, dm) (b|a).not_in(b).output(lb + 2, dm) x.in(b).output(lb + 3, dm) @@ -160,18 +161,42 @@ def run_testsuite(dm, ic, tiled = false, hier = false) b.not_inside(c).output(lb, dm + 1) b.inside(empty).output(lb, dm + 2) b.not_inside(empty).output(lb, dm + 3) + (p, m) = b.split_inside(c) + p.output(lb, dm + 10) + m.output(lb, dm + 11) + + b.covering(c).output(lb, dm + 100) + b.not_covering(c).output(lb, dm + 101) + b.covering(empty).output(lb, dm + 102) + b.not_covering(empty).output(lb, dm + 103) + (p, m) = b.split_covering(c) + p.output(lb, dm + 110) + m.output(lb, dm + 111) + b.outside(c).output(lb + 1, dm) b.not_outside(c).output(lb + 1, dm + 1) b.outside(empty).output(lb + 1, dm + 2) b.not_outside(empty).output(lb + 1, dm + 3) + (p, m) = b.split_outside(c) + p.output(lb + 1, dm + 10) + m.output(lb + 1, dm + 11) + b.overlapping(c).output(lb + 2, dm) b.not_overlapping(c).output(lb + 2, dm + 1) b.overlapping(empty).output(lb + 2, dm + 2) b.not_overlapping(empty).output(lb + 2, dm + 3) + (p, m) = b.split_overlapping(c) + p.output(lb + 2, dm + 10) + m.output(lb + 2, dm + 11) + b.interacting(c).output(lb + 3, dm) b.not_interacting(c).output(lb + 3, dm + 1) b.interacting(empty).output(lb + 3, dm + 2) b.not_interacting(empty).output(lb + 3, dm + 3) + (p, m) = b.split_interacting(c) + p.output(lb + 3, dm + 10) + m.output(lb + 3, dm + 11) + bdup = b.dup bdup.select_inside(c) bdup.xor(b.inside(c)).output(lb + 4, dm) diff --git a/testdata/drc/drcSuiteTests_au1.oas b/testdata/drc/drcSuiteTests_au1.oas index ef395210f..0dd5c6851 100644 Binary files a/testdata/drc/drcSuiteTests_au1.oas and b/testdata/drc/drcSuiteTests_au1.oas differ diff --git a/testdata/drc/drcSuiteTests_au2.oas b/testdata/drc/drcSuiteTests_au2.oas index 8a5528975..6ccbca614 100644 Binary files a/testdata/drc/drcSuiteTests_au2.oas and b/testdata/drc/drcSuiteTests_au2.oas differ diff --git a/testdata/drc/drcSuiteTests_au3.oas b/testdata/drc/drcSuiteTests_au3.oas index 4f5221a28..c42f0b098 100644 Binary files a/testdata/drc/drcSuiteTests_au3.oas and b/testdata/drc/drcSuiteTests_au3.oas differ diff --git a/testdata/drc/drcSuiteTests_au4.oas b/testdata/drc/drcSuiteTests_au4.oas index bff2c5694..1b2dc47b6 100644 Binary files a/testdata/drc/drcSuiteTests_au4.oas and b/testdata/drc/drcSuiteTests_au4.oas differ diff --git a/testdata/drc/drcSuiteTests_au5.oas b/testdata/drc/drcSuiteTests_au5.oas index c5ea03d11..ccb803594 100644 Binary files a/testdata/drc/drcSuiteTests_au5.oas and b/testdata/drc/drcSuiteTests_au5.oas differ diff --git a/testdata/drc/drcSuiteTests_au6.oas b/testdata/drc/drcSuiteTests_au6.oas index e1017d058..e9a693a4d 100644 Binary files a/testdata/drc/drcSuiteTests_au6.oas and b/testdata/drc/drcSuiteTests_au6.oas differ diff --git a/testdata/lvs/ringo_simple_with_tol.lvsdb.1 b/testdata/lvs/ringo_simple_with_tol.lvsdb.1 index 9521ed1cb..51c6fe9e2 100644 --- a/testdata/lvs/ringo_simple_with_tol.lvsdb.1 +++ b/testdata/lvs/ringo_simple_with_tol.lvsdb.1 @@ -848,13 +848,13 @@ xref( ) circuit(ND2X1 ND2X1 match xref( - net(8 8 mismatch) + net(8 8 match) net(4 4 match) net(6 6 match) net(5 5 match) - net(2 2 mismatch) - net(7 7 mismatch) - net(1 1 mismatch) + net(2 2 match) + net(7 7 match) + net(1 1 match) net(3 3 match) pin(3 3 match) pin(5 5 match) diff --git a/testdata/lvs/ringo_simple_with_tol.lvsdb.2 b/testdata/lvs/ringo_simple_with_tol.lvsdb.2 index 27ca272d4..372bf323d 100644 --- a/testdata/lvs/ringo_simple_with_tol.lvsdb.2 +++ b/testdata/lvs/ringo_simple_with_tol.lvsdb.2 @@ -848,13 +848,13 @@ xref( ) circuit(ND2X1 ND2X1 match xref( - net(8 8 mismatch) + net(8 8 match) net(4 4 match) net(6 6 match) net(5 5 match) - net(2 2 mismatch) - net(7 7 mismatch) - net(1 1 mismatch) + net(2 2 match) + net(7 7 match) + net(1 1 match) net(3 3 match) pin(3 3 match) pin(5 5 match) diff --git a/testdata/ruby/dbNetlistCompare.rb b/testdata/ruby/dbNetlistCompare.rb index e95a62a07..58b3339ca 100644 --- a/testdata/ruby/dbNetlistCompare.rb +++ b/testdata/ruby/dbNetlistCompare.rb @@ -33,7 +33,7 @@ class NetlistCompareTestLogger < RBA::GenericNetlistCompareLogger @texts << text end - def device_class_mismatch(a, b) + def device_class_mismatch(a, b, msg) out("device_class_mismatch " + dc2str(a) + " " + dc2str(b)) end @@ -41,15 +41,15 @@ class NetlistCompareTestLogger < RBA::GenericNetlistCompareLogger out("begin_circuit " + circuit2str(a) + " " + circuit2str(b)) end - def end_circuit(a, b, matching) + def end_circuit(a, b, matching, msg) out("end_circuit " + circuit2str(a) + " " + circuit2str(b) + " " + (matching ? "MATCH" : "NOMATCH")) end - def circuit_skipped(a, b) + def circuit_skipped(a, b, msg) out("circuit_skipped " + circuit2str(a) + " " + circuit2str(b)) end - def circuit_mismatch(a, b) + def circuit_mismatch(a, b, msg) out("circuit_mismatch " + circuit2str(a) + " " + circuit2str(b)) end @@ -57,11 +57,11 @@ class NetlistCompareTestLogger < RBA::GenericNetlistCompareLogger out("match_nets " + net2str(a) + " " + net2str(b)) end - def match_ambiguous_nets(a, b) + def match_ambiguous_nets(a, b, msg) out("match_ambiguous_nets " + net2str(a) + " " + net2str(b)) end - def net_mismatch(a, b) + def net_mismatch(a, b, msg) out("net_mismatch " + net2str(a) + " " + net2str(b)) end @@ -69,7 +69,7 @@ class NetlistCompareTestLogger < RBA::GenericNetlistCompareLogger out("match_devices " + device2str(a) + " " + device2str(b)) end - def device_mismatch(a, b) + def device_mismatch(a, b, msg) out("device_mismatch " + device2str(a) + " " + device2str(b)) end @@ -85,7 +85,7 @@ class NetlistCompareTestLogger < RBA::GenericNetlistCompareLogger out("match_pins " + pin2str(a) + " " + pin2str(b)) end - def pin_mismatch(a, b) + def pin_mismatch(a, b, msg) out("pin_mismatch " + pin2str(a) + " " + pin2str(b)) end @@ -93,7 +93,7 @@ class NetlistCompareTestLogger < RBA::GenericNetlistCompareLogger out("match_subcircuits " + subcircuit2str(a) + " " + subcircuit2str(b)) end - def subcircuit_mismatch(a, b) + def subcircuit_mismatch(a, b, msg) out("subcircuit_mismatch " + subcircuit2str(a) + " " + subcircuit2str(b)) end @@ -482,7 +482,7 @@ END logger.clear eqp = RBA::EqualDeviceParameters::new(RBA::DeviceClassMOS3Transistor::PARAM_L, 0.2, 0.0) - nl2.device_class_by_name("NMOS").equal_parameters = eqp + nl1.device_class_by_name("NMOS").equal_parameters = eqp good = comp.compare(nl1, nl2) assert_equal(logger.text, <<"END") @@ -509,8 +509,8 @@ END assert_equal(good, true) logger.clear - nl2.device_class_by_name("NMOS").equal_parameters = nil - assert_equal(nl2.device_class_by_name("NMOS").equal_parameters == nil, true) + nl1.device_class_by_name("NMOS").equal_parameters = nil + assert_equal(nl1.device_class_by_name("NMOS").equal_parameters == nil, true) good = comp.compare(nl1, nl2) assert_equal(logger.text, <<"END") @@ -539,8 +539,8 @@ END logger.clear eqp = RBA::EqualDeviceParameters::new(RBA::DeviceClassMOS3Transistor::PARAM_W, 0.01, 0.0) eqp = eqp + RBA::EqualDeviceParameters::new(RBA::DeviceClassMOS3Transistor::PARAM_L, 0.2, 0.0) - nl2.device_class_by_name("NMOS").equal_parameters = eqp - assert_equal(nl2.device_class_by_name("NMOS").equal_parameters == nil, false) + nl1.device_class_by_name("NMOS").equal_parameters = eqp + assert_equal(nl1.device_class_by_name("NMOS").equal_parameters == nil, false) good = comp.compare(nl1, nl2) assert_equal(logger.text, <<"END") @@ -567,7 +567,7 @@ END assert_equal(good, true) logger.clear - dc = nl2.device_class_by_name("NMOS") + dc = nl1.device_class_by_name("NMOS") dc.equal_parameters = RBA::EqualDeviceParameters::new(RBA::DeviceClassMOS3Transistor::PARAM_W, 0.01, 0.0) dc.equal_parameters += RBA::EqualDeviceParameters::new(RBA::DeviceClassMOS3Transistor::PARAM_L, 0.2, 0.0) good = comp.compare(nl1, nl2) diff --git a/testdata/ruby/dbRegionTest.rb b/testdata/ruby/dbRegionTest.rb index 27cd9b257..79985b676 100644 --- a/testdata/ruby/dbRegionTest.rb +++ b/testdata/ruby/dbRegionTest.rb @@ -525,34 +525,49 @@ class DBRegion_TestClass < TestBase r1 = RBA::Region::new r1.insert(RBA::Box::new(10, 20, 100, 200)) + r11 = r1.dup r1.insert(RBA::Box::new(50, 70, 150, 270)) r1.insert(RBA::Box::new(100, 70, 250, 270)) r2 = RBA::Region::new(RBA::Box::new(-10, -20, 100, 200)) r3 = RBA::Region::new(RBA::Box::new(150, 270, 160, 280)) r3 += r2 + r21 = r2.dup + r21 += RBA::Region::new(RBA::Box::new(110, -20, 200, 200)) assert_equal(r1.merged_semantics?, true) r1.merged_semantics = false assert_equal(r1.merged_semantics?, false) assert_equal(r1.inside(r2).to_s, "(10,20;10,200;100,200;100,20)") + assert_equal(r1.split_inside(r2)[0].to_s, "(10,20;10,200;100,200;100,20)") assert_equal(csort(r1.not_inside(r2).to_s), csort("(50,70;50,270;150,270;150,70);(100,70;100,270;250,270;250,70)")) + assert_equal(csort(r1.split_inside(r2)[1].to_s), csort("(50,70;50,270;150,270;150,70);(100,70;100,270;250,270;250,70)")) + assert_equal(r21.covering(r11).to_s, "(-10,-20;-10,200;100,200;100,-20)") + assert_equal(r21.split_covering(r11)[0].to_s, "(-10,-20;-10,200;100,200;100,-20)") + assert_equal(csort(r21.not_covering(r11).to_s), csort("(110,-20;110,200;200,200;200,-20)")) + assert_equal(csort(r21.split_covering(r11)[1].to_s), csort("(110,-20;110,200;200,200;200,-20)")) assert_equal(csort(r1.interacting(r2).to_s), csort("(10,20;10,200;100,200;100,20);(50,70;50,270;150,270;150,70);(100,70;100,270;250,270;250,70)")) assert_equal(csort(r1.interacting(r3, 1).to_s), csort("(10,20;10,200;100,200;100,20);(50,70;50,270;150,270;150,70);(100,70;100,270;250,270;250,70)")) assert_equal(csort(r1.interacting(r3, 2).to_s), csort("(50,70;50,270;150,270;150,70);(100,70;100,270;250,270;250,70)")) + assert_equal(csort(r1.split_interacting(r3, 2)[0].to_s), csort("(50,70;50,270;150,270;150,70);(100,70;100,270;250,270;250,70)")) assert_equal(r1.interacting(r3, 3).to_s, "") assert_equal(r1.interacting(r3, 1, 1).to_s, "(10,20;10,200;100,200;100,20)") assert_equal(csort(r1.interacting(r3, 2, 2).to_s), csort("(50,70;50,270;150,270;150,70);(100,70;100,270;250,270;250,70)")) assert_equal(r1.not_interacting(r2).to_s, "") assert_equal(r1.not_interacting(r3, 1).to_s, "") assert_equal(r1.not_interacting(r3, 2).to_s, "(10,20;10,200;100,200;100,20)") + assert_equal(r1.split_interacting(r3, 2)[1].to_s, "(10,20;10,200;100,200;100,20)") assert_equal(csort(r1.not_interacting(r3, 3).to_s), csort("(10,20;10,200;100,200;100,20);(50,70;50,270;150,270;150,70);(100,70;100,270;250,270;250,70)")) assert_equal(csort(r1.not_interacting(r3, 1, 1).to_s), csort("(50,70;50,270;150,270;150,70);(100,70;100,270;250,270;250,70)")) assert_equal(r1.not_interacting(r3, 2, 2).to_s, "(10,20;10,200;100,200;100,20)") assert_equal(csort(r1.overlapping(r2).to_s), csort("(10,20;10,200;100,200;100,20);(50,70;50,270;150,270;150,70)")) + assert_equal(csort(r1.split_overlapping(r2)[0].to_s), csort("(10,20;10,200;100,200;100,20);(50,70;50,270;150,270;150,70)")) assert_equal(r1.not_overlapping(r2).to_s, "(100,70;100,270;250,270;250,70)") + assert_equal(r1.split_overlapping(r2)[1].to_s, "(100,70;100,270;250,270;250,70)") assert_equal(r1.outside(r2).to_s, "(100,70;100,270;250,270;250,70)") + assert_equal(r1.split_outside(r2)[0].to_s, "(100,70;100,270;250,270;250,70)") assert_equal(csort(r1.not_outside(r2).to_s), csort("(10,20;10,200;100,200;100,20);(50,70;50,270;150,270;150,70)")) + assert_equal(csort(r1.split_outside(r2)[1].to_s), csort("(10,20;10,200;100,200;100,20);(50,70;50,270;150,270;150,70)")) e2 = RBA::Edges::new(RBA::Edge::new(-10, -20, 100, 200)) e3 = RBA::Edges::new(RBA::Edge::new(150, 270, 160, 280)) @@ -561,12 +576,14 @@ class DBRegion_TestClass < TestBase assert_equal(csort(r1.interacting(e2).to_s), csort("(100,70;100,270;250,270;250,70);(50,70;50,270;150,270;150,70);(10,20;10,200;100,200;100,20)")) assert_equal(csort(r1.interacting(e3, 1).to_s), csort("(100,70;100,270;250,270;250,70);(50,70;50,270;150,270;150,70);(10,20;10,200;100,200;100,20)")) assert_equal(csort(r1.interacting(e3, 2).to_s), csort("(100,70;100,270;250,270;250,70);(50,70;50,270;150,270;150,70)")) + assert_equal(csort(r1.split_interacting(e3, 2)[0].to_s), csort("(100,70;100,270;250,270;250,70);(50,70;50,270;150,270;150,70)")) assert_equal(r1.interacting(e3, 3).to_s, "") assert_equal(r1.interacting(e3, 1, 1).to_s, "(10,20;10,200;100,200;100,20)") assert_equal(csort(r1.interacting(e3, 2, 2).to_s), csort("(100,70;100,270;250,270;250,70);(50,70;50,270;150,270;150,70)")) assert_equal(r1.not_interacting(e2).to_s, "") assert_equal(r1.not_interacting(e3, 1).to_s, "") assert_equal(r1.not_interacting(e3, 2).to_s, "(10,20;10,200;100,200;100,20)") + assert_equal(r1.split_interacting(e3, 2)[1].to_s, "(10,20;10,200;100,200;100,20)") assert_equal(csort(r1.not_interacting(e3, 3).to_s), csort("(100,70;100,270;250,270;250,70);(50,70;50,270;150,270;150,70);(10,20;10,200;100,200;100,20)")) assert_equal(csort(r1.not_interacting(e3, 1, 1).to_s), csort("(100,70;100,270;250,270;250,70);(50,70;50,270;150,270;150,70)")) assert_equal(r1.not_interacting(e3, 2, 2).to_s, "(10,20;10,200;100,200;100,20)") @@ -577,6 +594,7 @@ class DBRegion_TestClass < TestBase assert_equal(csort(r1.interacting(t2).to_s), csort("(50,70;50,270;150,270;150,70);(10,20;10,200;100,200;100,20)")) assert_equal(csort(r1.interacting(t3, 1).to_s), csort("(100,70;100,270;250,270;250,70);(50,70;50,270;150,270;150,70);(10,20;10,200;100,200;100,20)")) + assert_equal(csort(r1.split_interacting(t3, 1)[0].to_s), csort("(100,70;100,270;250,270;250,70);(50,70;50,270;150,270;150,70);(10,20;10,200;100,200;100,20)")) assert_equal(r1.interacting(t3, 2).to_s, "(50,70;50,270;150,270;150,70)") assert_equal(r1.interacting(t3, 3).to_s, "") assert_equal(csort(r1.interacting(t3, 1, 1).to_s), csort("(100,70;100,270;250,270;250,70);(10,20;10,200;100,200;100,20)")) @@ -584,6 +602,7 @@ class DBRegion_TestClass < TestBase assert_equal(r1.not_interacting(t2).to_s, "(100,70;100,270;250,270;250,70)") assert_equal(r1.not_interacting(t3, 1).to_s, "") assert_equal(csort(r1.not_interacting(t3, 2).to_s), csort("(100,70;100,270;250,270;250,70);(10,20;10,200;100,200;100,20)")) + assert_equal(csort(r1.split_interacting(t3, 2)[1].to_s), csort("(100,70;100,270;250,270;250,70);(10,20;10,200;100,200;100,20)")) assert_equal(csort(r1.not_interacting(t3, 3).to_s), csort("(100,70;100,270;250,270;250,70);(50,70;50,270;150,270;150,70);(10,20;10,200;100,200;100,20)")) assert_equal(r1.not_interacting(t3, 1, 1).to_s, "(50,70;50,270;150,270;150,70)") assert_equal(csort(r1.not_interacting(t3, 2, 2).to_s), csort("(100,70;100,270;250,270;250,70);(10,20;10,200;100,200;100,20)")) diff --git a/testdata/ruby/tlTest.rb b/testdata/ruby/tlTest.rb index 082875981..e1ffbab16 100644 --- a/testdata/ruby/tlTest.rb +++ b/testdata/ruby/tlTest.rb @@ -262,17 +262,29 @@ class Tl_TestClass < TestBase end + class MyRecipeExecutable < RBA::Executable + + def initialize(params) + @params = params + end + + def execute + a = @params["A"] || 0 + b = @params["B"] || 0.0 + c = @params["C"] || 1.0 + b * a * c + end + + end + class MyRecipe < RBA::Recipe def initialize super("rba_test_recipe", "description") end - def execute(params) - a = params["A"] || 0 - b = params["B"] || 0.0 - c = params["C"] || 1.0 - b * a * c + def executable(params) + return MyRecipeExecutable::new(params) end end @@ -291,7 +303,7 @@ class Tl_TestClass < TestBase g = my_recipe.generator("A" => 6, "B" => 7.0) assert_equal(g, "rba_test_recipe: A=#6,B=##7") - assert_equal("%g" % RBA::Recipe::make(g).to_s, "42") + assert_equal("%g" % RBA::Recipe::make(g), "42") assert_equal("%g" % RBA::Recipe::make(g, "C" => 1.5).to_s, "63") my_recipe._destroy