diff --git a/src/db/db/dbAsIfFlatEdges.cc b/src/db/db/dbAsIfFlatEdges.cc index 9cb62ba1a..588eaf462 100644 --- a/src/db/db/dbAsIfFlatEdges.cc +++ b/src/db/db/dbAsIfFlatEdges.cc @@ -180,7 +180,7 @@ AsIfFlatEdges::pull_generic (const Edges &edges) const { db::box_scanner scanner (report_progress (), progress_desc ()); - AddressableEdgeDelivery e (begin (), true); + AddressableEdgeDelivery e (begin (), has_valid_edges ()); for ( ; ! e.at_end (); ++e) { scanner.insert (e.operator-> (), 1); @@ -507,7 +507,7 @@ AsIfFlatEdges::run_check (db::edge_relation_type rel, const Edges *other, db::Co db::box_scanner scanner (report_progress (), progress_desc ()); scanner.reserve (size () + (other ? other->size () : 0)); - AddressableEdgeDelivery e (begin_merged (), has_valid_edges ()); + AddressableEdgeDelivery e (begin_merged (), has_valid_merged_edges ()); size_t n = 0; for ( ; ! e.at_end (); ++e) { diff --git a/src/db/db/dbAsIfFlatTexts.cc b/src/db/db/dbAsIfFlatTexts.cc index a3b8a1958..fe9c86da3 100644 --- a/src/db/db/dbAsIfFlatTexts.cc +++ b/src/db/db/dbAsIfFlatTexts.cc @@ -342,7 +342,7 @@ AsIfFlatTexts::pull_generic (const Region &other) const db::box_scanner2 scanner (report_progress (), progress_desc ()); - AddressableTextDelivery e (begin (), true); + AddressableTextDelivery e (begin (), has_valid_texts ()); for ( ; ! e.at_end (); ++e) { scanner.insert1 (e.operator-> (), 0); diff --git a/src/db/db/dbTilingProcessor.cc b/src/db/db/dbTilingProcessor.cc index 7682293eb..db3604562 100644 --- a/src/db/db/dbTilingProcessor.cc +++ b/src/db/db/dbTilingProcessor.cc @@ -164,6 +164,34 @@ private: const db::ICplxTrans m_trans; }; +/** + * @brief A helper class for the generic implementation of the text collection insert functionality + */ +class TextsInserter +{ +public: + TextsInserter (db::Texts *texts, const db::ICplxTrans &trans) + : mp_texts (texts), m_trans (trans) + { + // .. nothing yet .. + } + + template + void operator() (const T &) + { + // .. discard anything except Texts .. + } + + void operator() (const db::Text &t) + { + mp_texts->insert (t.transformed (m_trans)); + } + +private: + db::Texts *mp_texts; + const db::ICplxTrans m_trans; +}; + class TileLayoutOutputReceiver : public db::TileOutputReceiver { @@ -271,6 +299,26 @@ private: db::EdgePairs *mp_edge_pairs; }; +class TileTextsOutputReceiver + : public db::TileOutputReceiver +{ +public: + TileTextsOutputReceiver (db::Texts *texts) + : mp_texts (texts) + { + // .. nothing yet .. + } + + void put (size_t /*ix*/, size_t /*iy*/, const db::Box &tile, size_t /*id*/, const tl::Variant &obj, double /*dbu*/, const db::ICplxTrans &trans, bool clip) + { + TextsInserter inserter (mp_texts, trans); + insert_var (inserter, obj, tile, clip); + } + +private: + db::Texts *mp_texts; +}; + class TilingProcessorJob : public tl::JobBase { @@ -395,6 +443,7 @@ private: TilingProcessorJob *mp_job; void do_perform (const TilingProcessorTask *task); + void make_input_var (const TilingProcessor::InputSpec &is, const db::RecursiveShapeIterator *iter, tl::Eval &eval, double sf); }; class TilingProcessorReceiverFunction @@ -452,6 +501,24 @@ public: } }; +void +TilingProcessorWorker::make_input_var (const TilingProcessor::InputSpec &is, const db::RecursiveShapeIterator *iter, tl::Eval &eval, double sf) +{ + if (! iter) { + iter = &is.iter; + } + + if (is.type == TilingProcessor::TypeRegion) { + eval.set_var (is.name, tl::Variant (db::Region (*iter, db::ICplxTrans (sf) * is.trans, is.merged_semantics))); + } else if (is.type == TilingProcessor::TypeEdges) { + eval.set_var (is.name, tl::Variant (db::Edges (*iter, db::ICplxTrans (sf) * is.trans, is.merged_semantics))); + } else if (is.type == TilingProcessor::TypeEdgePairs) { + eval.set_var (is.name, tl::Variant (db::EdgePairs (*iter, db::ICplxTrans (sf) * is.trans))); + } else if (is.type == TilingProcessor::TypeTexts) { + eval.set_var (is.name, tl::Variant (db::Texts (*iter, db::ICplxTrans (sf) * is.trans))); + } +} + void TilingProcessorWorker::do_perform (const TilingProcessorTask *tile_task) { @@ -492,11 +559,7 @@ TilingProcessorWorker::do_perform (const TilingProcessorTask *tile_task) if (! mp_job->has_tiles ()) { - if (i->region) { - eval.set_var (i->name, tl::Variant (db::Region (i->iter, db::ICplxTrans (sf) * i->trans, i->merged_semantics))); - } else { - eval.set_var (i->name, tl::Variant (db::Edges (i->iter, db::ICplxTrans (sf) * i->trans, i->merged_semantics))); - } + make_input_var (*i, 0, eval, sf); } else { @@ -509,11 +572,7 @@ TilingProcessorWorker::do_perform (const TilingProcessorTask *tile_task) iter.confine_region (region_dbu); } - if (i->region) { - eval.set_var (i->name, tl::Variant (db::Region (iter, db::ICplxTrans (sf) * i->trans, i->merged_semantics))); - } else { - eval.set_var (i->name, tl::Variant (db::Edges (iter, db::ICplxTrans (sf) * i->trans, i->merged_semantics))); - } + make_input_var (*i, &iter, eval, sf); } @@ -559,7 +618,7 @@ TilingProcessor::TilingProcessor () } void -TilingProcessor::input (const std::string &name, const db::RecursiveShapeIterator &iter, const db::ICplxTrans &trans, bool as_region, bool merged_semantics) +TilingProcessor::input (const std::string &name, const db::RecursiveShapeIterator &iter, const db::ICplxTrans &trans, Type type, bool merged_semantics) { if (m_inputs.empty () && iter.layout ()) { m_dbu = iter.layout ()->dbu (); @@ -568,7 +627,7 @@ TilingProcessor::input (const std::string &name, const db::RecursiveShapeIterato m_inputs.back ().name = name; m_inputs.back ().iter = iter; m_inputs.back ().trans = trans; - m_inputs.back ().region = as_region; + m_inputs.back ().type = type; m_inputs.back ().merged_semantics = merged_semantics; } @@ -699,7 +758,17 @@ TilingProcessor::output (const std::string &name, db::EdgePairs &edge_pairs) m_outputs.back ().receiver = new TileEdgePairsOutputReceiver (&edge_pairs); } -void +void +TilingProcessor::output (const std::string &name, db::Texts &texts) +{ + m_top_eval.set_var (name, m_outputs.size ()); + m_outputs.push_back (OutputSpec ()); + m_outputs.back ().name = name; + m_outputs.back ().id = 0; + m_outputs.back ().receiver = new TileTextsOutputReceiver (&texts); +} + +void TilingProcessor::output (const std::string &name, db::Edges &edges) { m_top_eval.set_var (name, m_outputs.size ()); diff --git a/src/db/db/dbTilingProcessor.h b/src/db/db/dbTilingProcessor.h index 0419f74a8..7a4359d34 100644 --- a/src/db/db/dbTilingProcessor.h +++ b/src/db/db/dbTilingProcessor.h @@ -346,6 +346,20 @@ void insert (X &inserter, const db::EdgePairs &data, const db::Box &tile, bool c } } +/** + * @brief Delivery of tiling processor output + * This utility is put between the container and the receiver. + * The inserter is an object having an operator() that takes the object. + * This function is responsible for preparing (i.e. clipping) and delivering the output. + */ +template +void insert (X &inserter, const db::Texts &data, const db::Box &tile, bool clip) +{ + for (db::Texts::const_iterator o = data.begin (); ! o.at_end (); ++o) { + insert (inserter, *o, tile, clip); + } +} + /** * @brief Delivery of tiling processor output * This utility is put between the container and the receiver. @@ -364,6 +378,9 @@ bool insert_var (X &inserter, const tl::Variant &obj, const db::Box &tile, bool } else if (obj.is_user ()) { insert (inserter, obj.to_user (), tile, clip); return true; + } else if (obj.is_user ()) { + insert (inserter, obj.to_user (), tile, clip); + return true; } else if (obj.is_user ()) { insert (inserter, obj.to_user (), tile, clip); return true; @@ -417,6 +434,8 @@ bool insert_var (X &inserter, const tl::Variant &obj, const db::Box &tile, bool class DB_PUBLIC TilingProcessor { public: + enum Type { TypeRegion, TypeEdges, TypeEdgePairs, TypeTexts }; + /** * @brief Constructor */ @@ -441,7 +460,7 @@ public: * The transformation can be used to convert between database units. * If "as_region" is false, the input is taken as edge input. */ - void input (const std::string &name, const db::RecursiveShapeIterator &iter, const db::ICplxTrans &trans = db::ICplxTrans (), bool as_region = true, bool merged_semantics = true); + void input (const std::string &name, const db::RecursiveShapeIterator &iter, const db::ICplxTrans &trans = db::ICplxTrans (), Type type = TypeRegion, bool merged_semantics = true); /** * @brief Specifies the output @@ -489,6 +508,14 @@ public: */ void output (const std::string &name, db::EdgePairs &edge_pairs); + /** + * @brief Specifies output to an text collection + * + * This version will specify output to a Texts object. + * Only texts will be stored. + */ + void output (const std::string &name, db::Texts &texts); + /** * @brief Specifies output to an edge collection * @@ -624,11 +651,11 @@ private: struct InputSpec { - InputSpec () : region (false), merged_semantics (false) { } + InputSpec () : type (TilingProcessor::TypeRegion), merged_semantics (false) { } std::string name; db::RecursiveShapeIterator iter; db::ICplxTrans trans; - bool region; + TilingProcessor::Type type; bool merged_semantics; }; diff --git a/src/db/db/gsiDeclDbTilingProcessor.cc b/src/db/db/gsiDeclDbTilingProcessor.cc index bfa92fc79..13e525f19 100644 --- a/src/db/db/gsiDeclDbTilingProcessor.cc +++ b/src/db/db/gsiDeclDbTilingProcessor.cc @@ -255,6 +255,11 @@ static void tp_output_edge_pairs (db::TilingProcessor *proc, const std::string & proc->output (name, edge_pairs); } +static void tp_output_texts (db::TilingProcessor *proc, const std::string &name, db::Texts &texts) +{ + proc->output (name, texts); +} + static void tp_output_double (db::TilingProcessor *proc, const std::string &name, double *v) { proc->output (name, 0, new DoubleCollectingTileOutputReceiver (v), db::ICplxTrans ()); @@ -311,25 +316,49 @@ static void tp_input7 (db::TilingProcessor *proc, const std::string &name, const static void tp_input8 (db::TilingProcessor *proc, const std::string &name, const db::Region ®ion) { std::pair it = region.begin_iter (); - proc->input (name, it.first, it.second, true /*as polygons*/, region.merged_semantics ()); + proc->input (name, it.first, it.second, db::TilingProcessor::TypeRegion, region.merged_semantics ()); } static void tp_input9 (db::TilingProcessor *proc, const std::string &name, const db::Region ®ion, const db::ICplxTrans &trans) { std::pair it = region.begin_iter (); - proc->input (name, it.first, trans * it.second, true /*as polygons*/, region.merged_semantics ()); + proc->input (name, it.first, trans * it.second, db::TilingProcessor::TypeRegion, region.merged_semantics ()); } static void tp_input10 (db::TilingProcessor *proc, const std::string &name, const db::Edges &edges) { std::pair it = edges.begin_iter (); - proc->input (name, it.first, it.second, false /*not as polygons*/, edges.merged_semantics ()); + proc->input (name, it.first, it.second, db::TilingProcessor::TypeEdges, edges.merged_semantics ()); } static void tp_input11 (db::TilingProcessor *proc, const std::string &name, const db::Edges &edges, const db::ICplxTrans &trans) { std::pair it = edges.begin_iter (); - proc->input (name, it.first, trans * it.second, false /*not as polygons*/, edges.merged_semantics ()); + proc->input (name, it.first, trans * it.second, db::TilingProcessor::TypeEdges, edges.merged_semantics ()); +} + +static void tp_input12 (db::TilingProcessor *proc, const std::string &name, const db::EdgePairs &edge_pairs) +{ + std::pair it = edge_pairs.begin_iter (); + proc->input (name, it.first, it.second, db::TilingProcessor::TypeEdgePairs); +} + +static void tp_input13 (db::TilingProcessor *proc, const std::string &name, const db::EdgePairs &edge_pairs, const db::ICplxTrans &trans) +{ + std::pair it = edge_pairs.begin_iter (); + proc->input (name, it.first, trans * it.second, db::TilingProcessor::TypeEdgePairs); +} + +static void tp_input14 (db::TilingProcessor *proc, const std::string &name, const db::Texts &texts) +{ + std::pair it = texts.begin_iter (); + proc->input (name, it.first, it.second, db::TilingProcessor::TypeTexts); +} + +static void tp_input15 (db::TilingProcessor *proc, const std::string &name, const db::Texts &texts, const db::ICplxTrans &trans) +{ + std::pair it = texts.begin_iter (); + proc->input (name, it.first, trans * it.second, db::TilingProcessor::TypeTexts); } Class decl_TilingProcessor ("db", "TilingProcessor", @@ -385,16 +414,16 @@ Class decl_TilingProcessor ("db", "TilingProcessor", method_ext ("input", &tp_input8, gsi::arg ("name"), gsi::arg ("region"), "@brief Specifies input for the tiling processor\n" "This method will establish an input channel for the processor. This version receives input from a \\Region object. " - "Regions don't always come with a database unit, hence a database unit should be specified with the \\dbu= method if only " - "regions and edges are used as input.\n" + "Regions don't always come with a database unit, hence a database unit should be specified with the \\dbu= method unless " + "a layout object is specified as input too.\n" "\n" "The name specifies the variable under which the input can be used in the scripts." ) + method_ext ("input", &tp_input9, gsi::arg ("name"), gsi::arg ("region"), gsi::arg ("trans"), "@brief Specifies input for the tiling processor\n" "This method will establish an input channel for the processor. This version receives input from a \\Region object. " - "Regions don't always come with a database unit, hence a database unit should be specified with the \\dbu= method if only " - "regions and edges are used as input.\n" + "Regions don't always come with a database unit, hence a database unit should be specified with the \\dbu= method unless " + "a layout object is specified as input too.\n" "\n" "The name specifies the variable under which the input can be used in the scripts." "\n" @@ -403,22 +432,62 @@ Class decl_TilingProcessor ("db", "TilingProcessor", method_ext ("input", &tp_input10, gsi::arg ("name"), gsi::arg ("edges"), "@brief Specifies input for the tiling processor\n" "This method will establish an input channel for the processor. This version receives input from an \\Edges object. " - "Edge collections don't always come with a database unit, hence a database unit should be specified with the \\dbu= method if only " - "regions and edges are used as input.\n" + "Edge collections don't always come with a database unit, hence a database unit should be specified with the \\dbu= method unless " + "a layout object is specified as input too.\n" "\n" "The name specifies the variable under which the input can be used in the scripts." ) + method_ext ("input", &tp_input11, gsi::arg ("name"), gsi::arg ("edges"), gsi::arg ("trans"), "@brief Specifies input for the tiling processor\n" "This method will establish an input channel for the processor. This version receives input from an \\Edges object. " - "Edge collections don't always come with a database unit, hence a database unit should be specified with the \\dbu= method if only " - "regions and edges are used as input.\n" + "Edge collections don't always come with a database unit, hence a database unit should be specified with the \\dbu= method unless " + "a layout object is specified as input too.\n" "\n" "The name specifies the variable under which the input can be used in the scripts." "\n" "This variant allows one to specify an additional transformation too. It has been introduced in version 0.23.2.\n" "\n" ) + + method_ext ("input", &tp_input12, gsi::arg ("name"), gsi::arg ("edge_pairs"), + "@brief Specifies input for the tiling processor\n" + "This method will establish an input channel for the processor. This version receives input from an \\EdgePairs object. " + "Edge pair collections don't always come with a database unit, hence a database unit should be specified with the \\dbu= method unless " + "a layout object is specified as input too.\n" + "\n" + "The name specifies the variable under which the input can be used in the scripts." + "\n" + "This variant has been introduced in version 0.27.\n" + ) + + method_ext ("input", &tp_input13, gsi::arg ("name"), gsi::arg ("edge_pairs"), gsi::arg ("trans"), + "@brief Specifies input for the tiling processor\n" + "This method will establish an input channel for the processor. This version receives input from an \\EdgePairs object. " + "Edge pair collections don't always come with a database unit, hence a database unit should be specified with the \\dbu= method unless " + "a layout object is specified as input too.\n" + "\n" + "The name specifies the variable under which the input can be used in the scripts." + "\n" + "This variant has been introduced in version 0.27.\n" + ) + + method_ext ("input", &tp_input14, gsi::arg ("name"), gsi::arg ("texts"), + "@brief Specifies input for the tiling processor\n" + "This method will establish an input channel for the processor. This version receives input from an \\Texts object. " + "Text collections don't always come with a database unit, hence a database unit should be specified with the \\dbu= method unless " + "a layout object is specified as input too.\n" + "\n" + "The name specifies the variable under which the input can be used in the scripts." + "\n" + "This variant has been introduced in version 0.27.\n" + ) + + method_ext ("input", &tp_input15, gsi::arg ("name"), gsi::arg ("texts"), gsi::arg ("trans"), + "@brief Specifies input for the tiling processor\n" + "This method will establish an input channel for the processor. This version receives input from an \\Texts object. " + "Text collections don't always come with a database unit, hence a database unit should be specified with the \\dbu= method unless " + "a layout object is specified as input too.\n" + "\n" + "The name specifies the variable under which the input can be used in the scripts." + "\n" + "This variant has been introduced in version 0.27.\n" + ) + method ("var", &db::TilingProcessor::var, gsi::arg ("name"), gsi::arg ("value"), "@brief Defines a variable for the tiling processor script\n" "\n" @@ -525,6 +594,20 @@ Class decl_TilingProcessor ("db", "TilingProcessor", "@param name The name of the channel\n" "@param edge_pairs The \\EdgePairs object to which the data is sent\n" ) + + method_ext ("output", &tp_output_texts, gsi::arg ("name"), gsi::arg ("texts"), + "@brief Specifies output to an \\Texts object\n" + "This method will establish an output channel to an \\Texts object. The output sent to that channel " + "will be put into the specified edge pair collection.\n" + "Only \\Text objects are accepted. Other objects are discarded.\n" + "\n" + "The name is the name which must be used in the _output function of the scripts in order to " + "address that channel.\n" + "\n" + "@param name The name of the channel\n" + "@param texts The \\Texts object to which the data is sent\n" + "\n" + "This variant has been introduced in version 0.27." + ) + method_ext ("output", &tp_output_double, gsi::arg ("name"), gsi::arg ("sum"), "@brief Specifies output to single value\n" "This method will establish an output channel which sums up float data delivered by calling the _output function.\n" diff --git a/testdata/drc/.drcSuiteTests.drc.swp b/testdata/drc/.drcSuiteTests.drc.swp new file mode 100644 index 000000000..fd3a3af2f Binary files /dev/null and b/testdata/drc/.drcSuiteTests.drc.swp differ diff --git a/testdata/drc/.drctest.drc.swp b/testdata/drc/.drctest.drc.swp new file mode 100644 index 000000000..03518e417 Binary files /dev/null and b/testdata/drc/.drctest.drc.swp differ diff --git a/testdata/drc/drcSuiteTests.drc b/testdata/drc/drcSuiteTests.drc index be4c43ed6..969736ce9 100644 --- a/testdata/drc/drcSuiteTests.drc +++ b/testdata/drc/drcSuiteTests.drc @@ -15,8 +15,10 @@ def run_testsuite(dm, ic, tiled = false, hier = false) lb = 100 a = polygons(RBA::LayerInfo::new(1, 0)) + at = labels(1) b = polygons(2) c = polygons(3) + d = polygons(4) x = polygons(10) y = polygons(11) empty = polygons(1000) @@ -605,6 +607,44 @@ def run_testsuite(dm, ic, tiled = false, hier = false) p = b.edges.intersections(c.edges) p.output(lb + 5, dm) + lb += 10 #450 + message "--- texts and filters #{lb}" + + p = at + p.output(lb, dm) + p = at.texts + p.output(lb + 1, dm) + p = at.texts("A*") + p.output(lb + 2, dm) + p = at.texts(pattern("A*")) + p.output(lb + 3, dm) + p = at.texts(pattern("A*"), as_dots) + p.output(lb + 4, dm) + p = at.texts(text("A*"), as_boxes) + p.output(lb + 5, dm) + p = at.texts_not("A*") + p.output(lb + 6, dm) + p = at.texts_not(pattern("A*")) + p.output(lb + 7, dm) + p = at.texts_not(pattern("A*"), as_dots) + p.output(lb + 8, dm) + p = at.texts_not(text("A*"), as_boxes) + p.output(lb + 9, dm) + + lb += 10 #460 + message "--- texts and polygon booleans and interactions #{lb}" + + p = at & d + p.output(lb, dm) + p = d.interacting(at) + p.output(lb + 1, dm) + p = at.interacting(d) + p.output(lb + 2, dm) + p = d.pull_interacting(at) + p.output(lb + 3, dm) + p = at.pull_interacting(d) + p.output(lb + 4, dm) + end if $drc_test_mode == 1 diff --git a/testdata/drc/drcSuiteTests_au1.oas b/testdata/drc/drcSuiteTests_au1.oas index 2288862ff..4dfbe6425 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 f02a19739..0f41d4df2 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 50f9a2516..19c82e622 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 5f3a3ad0f..4feb67d3f 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 c596d626f..c3f8dba2c 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 bf3a28492..9cd6913ee 100644 Binary files a/testdata/drc/drcSuiteTests_au6.oas and b/testdata/drc/drcSuiteTests_au6.oas differ diff --git a/testdata/drc/drctest.gds b/testdata/drc/drctest.gds index 460e30ad8..643a120cb 100644 Binary files a/testdata/drc/drctest.gds and b/testdata/drc/drctest.gds differ