From e82ebf67330f80854d762a2d499a4c38312c859b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 2 Aug 2025 19:17:23 +0200 Subject: [PATCH] WIP: measure_net function for LayoutToNetlist --- src/db/db/db.pro | 3 + src/db/db/dbLayoutToNetlist.cc | 109 +++-- src/db/db/dbLayoutToNetlist.h | 34 ++ src/db/db/dbMeasureEval.cc | 561 ++++++++++++++++++++++++++ src/db/db/dbMeasureEval.h | 170 ++++++++ src/db/db/gsiDeclDbLayoutToNetlist.cc | 177 ++++---- src/db/db/gsiDeclDbMeasureHelpers.cc | 299 +------------- src/db/db/gsiDeclDbMeasureHelpers.h | 80 +--- 8 files changed, 946 insertions(+), 487 deletions(-) create mode 100644 src/db/db/dbMeasureEval.cc create mode 100644 src/db/db/dbMeasureEval.h diff --git a/src/db/db/db.pro b/src/db/db/db.pro index bde28f9b3..390e18425 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -58,6 +58,7 @@ SOURCES = \ dbLog.cc \ dbManager.cc \ dbMatrix.cc \ + dbMeasureEval.cc \ dbMemStatistics.cc \ dbMutableEdgePairs.cc \ dbMutableEdges.cc \ @@ -296,6 +297,7 @@ HEADERS = \ dbLog.h \ dbManager.h \ dbMatrix.h \ + dbMeasureEval.h \ dbMemStatistics.h \ dbMetaInfo.h \ dbMutableEdgePairs.h \ @@ -432,6 +434,7 @@ HEADERS = \ dbNetShape.h \ dbShapeCollection.h \ dbShapeCollectionUtils.h \ + gsiDeclDbMeasureHelpers.h \ gsiDeclDbPropertiesSupport.h RESOURCES = \ diff --git a/src/db/db/dbLayoutToNetlist.cc b/src/db/db/dbLayoutToNetlist.cc index ecc43f376..04095cb64 100644 --- a/src/db/db/dbLayoutToNetlist.cc +++ b/src/db/db/dbLayoutToNetlist.cc @@ -34,6 +34,7 @@ #include "dbLayoutToNetlistSoftConnections.h" #include "dbShapeProcessor.h" #include "dbNetlistDeviceClasses.h" +#include "dbMeasureEval.h" #include "dbLog.h" #include "tlGlobPattern.h" @@ -1772,20 +1773,20 @@ public: } -static void -compute_area_and_perimeter_of_net_shapes (const db::hier_clusters &clusters, db::cell_index_type ci, size_t cid, unsigned int layer_id, db::Polygon::area_type &area, db::Polygon::perimeter_type &perimeter) +void +LayoutToNetlist::compute_area_and_perimeter_of_net_shapes (db::cell_index_type ci, size_t cid, unsigned int layer_id, db::Polygon::area_type &area, db::Polygon::perimeter_type &perimeter) const { db::EdgeProcessor ep; // count vertices and reserve space size_t n = 0; - for (db::recursive_cluster_shape_iterator rci (clusters, layer_id, ci, cid); !rci.at_end (); ++rci) { + for (db::recursive_cluster_shape_iterator rci (m_net_clusters, layer_id, ci, cid); !rci.at_end (); ++rci) { n += rci->polygon_ref ().vertices (); } ep.reserve (n); size_t p = 0; - for (db::recursive_cluster_shape_iterator rci (clusters, layer_id, ci, cid); !rci.at_end (); ++rci) { + for (db::recursive_cluster_shape_iterator rci (m_net_clusters, layer_id, ci, cid); !rci.at_end (); ++rci) { ep.insert_with_trans (rci->polygon_ref (), rci.trans (), ++p); } @@ -1798,49 +1799,24 @@ compute_area_and_perimeter_of_net_shapes (const db::hier_clusters perimeter = ap_collector.perimeter (); } -namespace { - -class AntennaShapeGenerator - : public PolygonSink +db::Point +LayoutToNetlist::get_merged_shapes_of_net (db::cell_index_type ci, size_t cid, unsigned int layer_id, db::Shapes &shapes, db::properties_id_type prop_id) const { -public: - AntennaShapeGenerator (db::Layout *layout, db::Shapes &shapes, db::properties_id_type prop_id) - : PolygonSink (), mp_layout (layout), mp_shapes (&shapes), m_prop_id (prop_id) - { } + const db::Layout *layout = &dss ().const_layout (m_layout_index); - virtual void put (const db::Polygon &polygon) - { - if (m_prop_id != 0) { - mp_shapes->insert (db::PolygonRefWithProperties (db::PolygonRef (polygon, mp_layout->shape_repository ()), m_prop_id)); - } else { - mp_shapes->insert (db::PolygonRef (polygon, mp_layout->shape_repository ())); - } - } - -private: - db::Layout *mp_layout; - db::Shapes *mp_shapes; - db::properties_id_type m_prop_id; -}; - -} - -static db::Point -get_merged_shapes_of_net (const db::hier_clusters &clusters, db::cell_index_type ci, size_t cid, unsigned int layer_id, db::Layout *layout, db::Shapes &shapes, db::properties_id_type prop_id) -{ db::Point ref; bool any_ref = false; db::EdgeProcessor ep; // count vertices and reserve space size_t n = 0; - for (db::recursive_cluster_shape_iterator rci (clusters, layer_id, ci, cid); !rci.at_end (); ++rci) { + for (db::recursive_cluster_shape_iterator rci (m_net_clusters, layer_id, ci, cid); !rci.at_end (); ++rci) { n += rci->polygon_ref ().vertices (); } ep.reserve (n); size_t p = 0; - for (db::recursive_cluster_shape_iterator rci (clusters, layer_id, ci, cid); !rci.at_end (); ++rci) { + for (db::recursive_cluster_shape_iterator rci (m_net_clusters, layer_id, ci, cid); !rci.at_end (); ++rci) { db::PolygonRef pr = rci->polygon_ref (); db::PolygonRef::polygon_edge_iterator e = pr.begin_edge (); if (! e.at_end ()) { @@ -1854,7 +1830,7 @@ get_merged_shapes_of_net (const db::hier_clusters &clusters, db::c } } - db::AntennaShapeGenerator sg (layout, shapes, prop_id); + db::PolygonRefToShapesGenerator sg (const_cast (layout), &shapes, prop_id); db::PolygonGenerator pg (sg, false); db::SimpleMerge op; ep.process (pg, op); @@ -1968,7 +1944,7 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_a db::Polygon::area_type adiode_int = 0; db::Polygon::perimeter_type pdiode_int = 0; - compute_area_and_perimeter_of_net_shapes (m_net_clusters, *cid, *c, layer_of (*d->first), adiode_int, pdiode_int); + compute_area_and_perimeter_of_net_shapes (*cid, *c, layer_of (*d->first), adiode_int, pdiode_int); adiodes_int.push_back (adiode_int); @@ -1987,7 +1963,7 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_a db::Polygon::area_type agate_int = 0; db::Polygon::perimeter_type pgate_int = 0; - compute_area_and_perimeter_of_net_shapes (m_net_clusters, *cid, *c, layer_of (gate), agate_int, pgate_int); + compute_area_and_perimeter_of_net_shapes (*cid, *c, layer_of (gate), agate_int, pgate_int); double agate = 0.0; if (fabs (gate_area_factor) > 1e-6) { @@ -2002,7 +1978,7 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_a db::Polygon::area_type ametal_int = 0; db::Polygon::perimeter_type pmetal_int = 0; - compute_area_and_perimeter_of_net_shapes (m_net_clusters, *cid, *c, layer_of (metal), ametal_int, pmetal_int); + compute_area_and_perimeter_of_net_shapes (*cid, *c, layer_of (metal), ametal_int, pmetal_int); double ametal = 0.0; if (fabs (metal_area_factor) > 1e-6) { @@ -2041,7 +2017,7 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_a prop_id = db::properties_id (ps); } - db::Point ref = get_merged_shapes_of_net (m_net_clusters, *cid, *c, layer_of (metal), &ly, shapes, prop_id); + db::Point ref = get_merged_shapes_of_net (*cid, *c, layer_of (metal), shapes, prop_id); if (values) { @@ -2078,6 +2054,61 @@ db::Region LayoutToNetlist::antenna_check (const db::Region &gate, double gate_a return db::Region (new db::DeepRegion (dl)); } +db::Region +LayoutToNetlist::measure_net (const db::Region &primary, const std::map &secondary, const std::string &expression) +{ + // TODO: that's basically too much .. we only need the clusters + if (! m_netlist_extracted) { + throw tl::Exception (tl::to_string (tr ("The netlist has not been extracted yet"))); + } + + db::Layout &ly = dss ().layout (m_layout_index); + double dbu = ly.dbu (); + + db::DeepLayer dl (&dss (), m_layout_index, ly.insert_layer ()); + + for (db::Layout::bottom_up_const_iterator cid = ly.begin_bottom_up (); cid != ly.end_bottom_up (); ++cid) { + + const connected_clusters &clusters = m_net_clusters.clusters_per_cell (*cid); + if (clusters.empty ()) { + continue; + } + + db::MeasureNetEval eval (this, dbu); + + eval.set_primary_layer (layer_of (primary)); + for (auto s = secondary.begin (); s != secondary.end (); ++s) { + if (s->second) { + eval.set_secondary_layer (s->first, layer_of (*s->second)); + } + } + + eval.init (); + + tl::Extractor ex (expression.c_str ()); + tl::Expression compiled_expr; + eval.parse (compiled_expr, ex); + + for (connected_clusters::all_iterator c = clusters.begin_all (); ! c.at_end (); ++c) { + + if (! clusters.is_root (*c)) { + continue; + } + + eval.reset (*cid, *c); + compiled_expr.execute (); + + if (! eval.skip ()) { + db::Shapes &shapes = ly.cell (*cid).shapes (dl.layer ()); + get_merged_shapes_of_net (*cid, *c, layer_of (primary), shapes, db::properties_id (eval.prop_set_out ())); + } + + } + + } + + return db::Region (new db::DeepRegion (dl)); +} void LayoutToNetlist::save (const std::string &path, bool short_format) { diff --git a/src/db/db/dbLayoutToNetlist.h b/src/db/db/dbLayoutToNetlist.h index 4b35c7914..4eb8b86c4 100644 --- a/src/db/db/dbLayoutToNetlist.h +++ b/src/db/db/dbLayoutToNetlist.h @@ -1126,6 +1126,30 @@ public: */ db::Region antenna_check (const db::Region &gate, double gate_area_factor, double gate_perimeter_factor, const db::Region &metal, double metal_area_factor, double metal_perimeter_factor, double ratio, const std::vector > &diodes = std::vector > (), Texts *values = 0); + /** + * @brief Runs a generic net measurement function + * + * This method accepts some primary layer, a number of secondary layers with names and an expression. + * + * It will look at nets connecting to shapes on the primary layer and execute the expression for each + * of those nets. After that it will copy the primary shapes of the net to the output with the properties + * placed by "put" attached to them. + * + * It is possible to skip primary shapes of a specific net by calling the "skip" function with a "true" + * value. + * + * The formulas may use the following functions: + * + * * "area": the area of all primary-layer shapes on the net in square um + * * "area(name)": the area of all secondary-layer shapes. 'name' is a symbol with the name given in the secondary-layer map + * * "perimeter": the perimeter of the primary-layer shapes on the net in um + * * "perimeter(name)": the perimeter of the secondary-layer shapes. 'name' is a symbol with the name given in the secondary-layer map + * * "put(name, value)": places the value as property 'name' on the output shapes + * * "skip(flag)": will skip the primary shapes of that net when called with a true value + * * "net_name": the name of the net + */ + db::Region measure_net (const db::Region &primary, const std::map &secondary, const std::string &expression); + /** * @brief Saves the database to the given path * @@ -1170,6 +1194,16 @@ public: m_make_soft_connection_diodes = f; } + /** + * @brief Utility: computes the area and perimeter of a net's shapes + */ + void compute_area_and_perimeter_of_net_shapes (db::cell_index_type ci, size_t cid, unsigned int layer_id, db::Polygon::area_type &area, db::Polygon::perimeter_type &perimeter) const; + + /** + * @brief Utility: computes the merged shapes of a net + */ + db::Point get_merged_shapes_of_net (db::cell_index_type ci, size_t cid, unsigned int layer_id, db::Shapes &shapes, db::properties_id_type prop_id) const; + private: // no copying LayoutToNetlist (const db::LayoutToNetlist &other); diff --git a/src/db/db/dbMeasureEval.cc b/src/db/db/dbMeasureEval.cc new file mode 100644 index 000000000..071b9636c --- /dev/null +++ b/src/db/db/dbMeasureEval.cc @@ -0,0 +1,561 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2025 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "dbMeasureEval.h" + +namespace db +{ + +// ----------------------------------------------------------------------------- +// MeasureEval implementation + +class ShapeFunction + : public tl::EvalFunction +{ +public: + ShapeFunction (MeasureEval *eval) + : mp_eval (eval) + { + // .. nothing yet .. + } + + virtual void execute (const tl::ExpressionParserContext &context, tl::Variant &out, const std::vector &args, const std::map * /*kwargs*/) const + { + if (args.size () != 0) { + throw tl::EvalError (tl::to_string (tr ("'shape' function does not take arguments")), context); + } + out = mp_eval->shape_func (); + } + +private: + MeasureEval *mp_eval; +}; + +class ValueFunction + : public tl::EvalFunction +{ +public: + ValueFunction (MeasureEval *eval) + : mp_eval (eval) + { + // .. nothing yet .. + } + + virtual void execute (const tl::ExpressionParserContext &context, tl::Variant &out, const std::vector &args, const std::map * /*kwargs*/) const + { + if (args.size () != 1) { + throw tl::EvalError (tl::to_string (tr ("'value' function takes one argument")), context); + } + out = mp_eval->value_func (args [0]); + } + +private: + MeasureEval *mp_eval; +}; + +class ValuesFunction + : public tl::EvalFunction +{ +public: + ValuesFunction (MeasureEval *eval) + : mp_eval (eval) + { + // .. nothing yet .. + } + + virtual void execute (const tl::ExpressionParserContext &context, tl::Variant &out, const std::vector &args, const std::map * /*kwargs*/) const + { + if (args.size () != 1) { + throw tl::EvalError (tl::to_string (tr ("'values' function takes one argument")), context); + } + out = mp_eval->values_func (args [0]); + } + +private: + MeasureEval *mp_eval; +}; + +class PropertyFunction + : public tl::EvalFunction +{ +public: + PropertyFunction (MeasureEval *eval, const tl::Variant &name) + : mp_eval (eval), m_name_id (db::property_names_id (name)) + { + // .. nothing yet .. + } + + virtual void execute (const tl::ExpressionParserContext &context, tl::Variant &out, const std::vector &args, const std::map * /*kwargs*/) const + { + if (args.size () != 0) { + throw tl::EvalError (tl::to_string (tr ("Property getter function does not take arguments")), context); + } + out = mp_eval->value_func (m_name_id); + } + +private: + MeasureEval *mp_eval; + db::property_names_id_type m_name_id; +}; + +class PutFunction + : public tl::EvalFunction +{ +public: + PutFunction (MeasureEval *eval) + : mp_eval (eval) + { + // .. nothing yet .. + } + + virtual void execute (const tl::ExpressionParserContext &context, tl::Variant & /*out*/, const std::vector &args, const std::map * /*kwargs*/) const + { + if (args.size () != 2) { + throw tl::EvalError (tl::to_string (tr ("'put' function takes two arguments (name, value)")), context); + } + mp_eval->put_func (args [0], args [1]); + } + +private: + MeasureEval *mp_eval; +}; + +// -------------------------------------------------------------------- +// MeasureEval implementation + +MeasureEval::MeasureEval (double dbu, bool with_put) + : m_shape_type (None), m_prop_id (0), m_dbu (dbu), m_with_put (with_put) +{ + mp_shape.any = 0; +} + +void +MeasureEval::init () +{ + if (m_with_put) { + define_function ("put", new PutFunction (this)); + } + + define_function ("shape", new ShapeFunction (this)); + define_function ("value", new ValueFunction (this)); + define_function ("values", new ValuesFunction (this)); +} + +void +MeasureEval::reset_shape () const +{ + m_shape_type = None; + mp_shape.any = 0; + m_prop_id = 0; +} + +void +MeasureEval::set_shape (const db::Polygon *poly) const +{ + m_shape_type = Polygon; + mp_shape.poly = poly; +} + +void +MeasureEval::set_shape (const db::PolygonRef *poly) const +{ + m_shape_type = PolygonRef; + mp_shape.poly_ref = poly; +} + +void +MeasureEval::set_shape (const db::Edge *edge) const +{ + m_shape_type = Edge; + mp_shape.edge = edge; +} + +void +MeasureEval::set_shape (const db::EdgePair *edge_pair) const +{ + m_shape_type = EdgePair; + mp_shape.edge_pair = edge_pair; +} + +void +MeasureEval::set_shape (const db::Text *text) const +{ + m_shape_type = Text; + mp_shape.text = text; +} + +void +MeasureEval::set_prop_id (db::properties_id_type prop_id) const +{ + m_prop_id = prop_id; +} + +void +MeasureEval::resolve_name (const std::string &name, const tl::EvalFunction *&function, const tl::Variant *&value, tl::Variant *&var) +{ + tl::Eval::resolve_name (name, function, value, var); + + if (!function && !value && !var) { + // connect the name with a function getting the property value + tl::EvalFunction *f = new PropertyFunction (this, name); + define_function (name, f); + function = f; + } +} + +tl::Variant +MeasureEval::shape_func () const +{ + if (m_dbu > 1e-10) { + + db::CplxTrans tr (m_dbu); + + switch (m_shape_type) + { + case None: + default: + return tl::Variant (); + case Polygon: + return tl::Variant (tr * *mp_shape.poly); + case PolygonRef: + { + db::Polygon poly; + mp_shape.poly_ref->instantiate (poly); + return tl::Variant (tr * poly); + } + case Edge: + return tl::Variant (tr * *mp_shape.edge); + case EdgePair: + return tl::Variant (tr * *mp_shape.edge_pair); + case Text: + return tl::Variant (tr * *mp_shape.text); + } + + } else { + + switch (m_shape_type) + { + case None: + default: + return tl::Variant (); + case Polygon: + return tl::Variant (*mp_shape.poly); + case PolygonRef: + { + db::Polygon poly; + mp_shape.poly_ref->instantiate (poly); + return tl::Variant (poly); + } + case Edge: + return tl::Variant (*mp_shape.edge); + case EdgePair: + return tl::Variant (*mp_shape.edge_pair); + case Text: + return tl::Variant (*mp_shape.text); + } + + } +} + +tl::Variant +MeasureEval::value_func (db::property_names_id_type name_id) const +{ + const db::PropertiesSet &ps = db::properties (m_prop_id); + for (auto i = ps.begin (); i != ps.end (); ++i) { + if (i->first == name_id) { + return db::property_value (i->second); + } + } + + return tl::Variant (); +} + +tl::Variant +MeasureEval::value_func (const tl::Variant &name) const +{ + const db::PropertiesSet &ps = db::properties (m_prop_id); + for (auto i = ps.begin (); i != ps.end (); ++i) { + if (db::property_name (i->first) == name) { + return db::property_value (i->second); + } + } + + return tl::Variant (); +} + +tl::Variant +MeasureEval::values_func (const tl::Variant &name) const +{ + tl::Variant res = tl::Variant::empty_list (); + + const db::PropertiesSet &ps = db::properties (m_prop_id); + for (auto i = ps.begin (); i != ps.end (); ++i) { + if (db::property_name (i->first) == name) { + res.push (db::property_value (i->second)); + } + } + + return res; +} + +void +MeasureEval::put_func (const tl::Variant &name, const tl::Variant &value) const +{ + auto prop_name_id = db::property_names_id (name); + m_prop_set_out.erase (prop_name_id); + m_prop_set_out.insert (prop_name_id, value); +} + +// ----------------------------------------------------------------------------- +// MeasureNetEval implementation + +class NetPutFunction + : public tl::EvalFunction +{ +public: + NetPutFunction (MeasureNetEval *eval) + : mp_eval (eval) + { + // .. nothing yet .. + } + + virtual void execute (const tl::ExpressionParserContext &context, tl::Variant & /*out*/, const std::vector &args, const std::map * /*kwargs*/) const + { + if (args.size () != 2) { + throw tl::EvalError (tl::to_string (tr ("'put' function takes two arguments (name, value)")), context); + } + mp_eval->put_func (args [0], args [1]); + } + +private: + MeasureNetEval *mp_eval; +}; + +class NetSkipFunction + : public tl::EvalFunction +{ +public: + NetSkipFunction (MeasureNetEval *eval) + : mp_eval (eval) + { + // .. nothing yet .. + } + + virtual void execute (const tl::ExpressionParserContext &context, tl::Variant & /*out*/, const std::vector &args, const std::map * /*kwargs*/) const + { + if (args.size () != 1) { + throw tl::EvalError (tl::to_string (tr ("'skip' function takes one argument (flag)")), context); + } + mp_eval->skip_func (args [0].to_bool ()); + } + +private: + MeasureNetEval *mp_eval; +}; + +class NetNameFunction + : public tl::EvalFunction +{ +public: + NetNameFunction (MeasureNetEval *eval) + : mp_eval (eval) + { + // .. nothing yet .. + } + + virtual void execute (const tl::ExpressionParserContext &context, tl::Variant &out, const std::vector &args, const std::map * /*kwargs*/) const + { + if (args.size () != 1) { + throw tl::EvalError (tl::to_string (tr ("'net_name' function does not take and argument")), context); + } + out = mp_eval->net_name_func (); + } + +private: + MeasureNetEval *mp_eval; +}; + +class NetAreaFunction + : public tl::EvalFunction +{ +public: + NetAreaFunction (MeasureNetEval *eval) + : mp_eval (eval) + { + // .. nothing yet .. + } + + virtual void execute (const tl::ExpressionParserContext &context, tl::Variant &out, const std::vector &args, const std::map * /*kwargs*/) const + { + if (args.size () > 1) { + throw tl::EvalError (tl::to_string (tr ("'area' function takes one optional argument (layer symbol)")), context); + } + out = mp_eval->area_func (args.size () == 0 ? 0 : args [0].to_int ()); + } + +private: + MeasureNetEval *mp_eval; +}; + +class NetPerimeterFunction + : public tl::EvalFunction +{ +public: + NetPerimeterFunction (MeasureNetEval *eval) + : mp_eval (eval) + { + // .. nothing yet .. + } + + virtual void execute (const tl::ExpressionParserContext &context, tl::Variant &out, const std::vector &args, const std::map * /*kwargs*/) const + { + if (args.size () > 1) { + throw tl::EvalError (tl::to_string (tr ("'perimeter' function takes one optional argument (layer symbol)")), context); + } + out = mp_eval->perimeter_func (args.size () == 0 ? 0 : args [0].to_int ()); + } + +private: + MeasureNetEval *mp_eval; +}; + +MeasureNetEval::MeasureNetEval (const db::LayoutToNetlist *l2n, double dbu) + : tl::Eval (), mp_l2n (l2n), m_dbu (dbu) +{ + // .. nothing yet .. +} + +void +MeasureNetEval::set_primary_layer (unsigned int layer_index) +{ + tl_assert (m_layers.empty ()); + m_layers.push_back (layer_index); +} + +void +MeasureNetEval::set_secondary_layer (const std::string &name, unsigned int layer_index) +{ + set_var (name, tl::Variant (int (m_layers.size ()))); + m_layers.push_back (layer_index); +} + +void +MeasureNetEval::init () +{ + define_function ("put", new NetPutFunction (this)); + define_function ("skip", new NetSkipFunction (this)); + define_function ("area", new NetAreaFunction (this)); + define_function ("perimeter", new NetPerimeterFunction (this)); + define_function ("net_name", new NetNameFunction (this)); +} + +void +MeasureNetEval::reset (db::cell_index_type cell_index, size_t cluster_id) const +{ + m_skip = false; + m_cell_index = cell_index; + m_cluster_id = cluster_id; + m_area_and_perimeter_cache.clear (); +} + +void +MeasureNetEval::put_func (const tl::Variant &name, const tl::Variant &value) const +{ + auto prop_name_id = db::property_names_id (name); + m_prop_set_out.erase (prop_name_id); + m_prop_set_out.insert (prop_name_id, value); +} + +MeasureNetEval::AreaAndPerimeter +MeasureNetEval::compute_area_and_perimeter (int layer_index) const +{ + if (layer_index < 0 || layer_index >= (unsigned int) m_layers.size ()) { + return AreaAndPerimeter (); + } + + unsigned int layer = m_layers [layer_index]; + db::Polygon::area_type area = 0; + db::Polygon::perimeter_type perimeter = 0; + mp_l2n->compute_area_and_perimeter_of_net_shapes (m_cell_index, m_cluster_id, layer, area, perimeter); + + AreaAndPerimeter ap; + ap.area = m_dbu * m_dbu * area; + ap.perimeter = m_dbu * perimeter; + + return ap; +} + +tl::Variant +MeasureNetEval::area_func (int layer_index) const +{ + auto ap = m_area_and_perimeter_cache.find (layer_index); + if (ap == m_area_and_perimeter_cache.end ()) { + ap = m_area_and_perimeter_cache.insert (std::make_pair (layer_index, compute_area_and_perimeter (layer_index))).first; + } + return ap->second.area; +} + +tl::Variant +MeasureNetEval::perimeter_func (int layer_index) const +{ + auto ap = m_area_and_perimeter_cache.find (layer_index); + if (ap == m_area_and_perimeter_cache.end ()) { + ap = m_area_and_perimeter_cache.insert (std::make_pair (layer_index, compute_area_and_perimeter (layer_index))).first; + } + return ap->second.perimeter; +} + +void +MeasureNetEval::skip_func (bool f) const +{ + m_skip = f; +} + +tl::Variant +MeasureNetEval::net_name_func () const +{ + const db::Netlist *nl = mp_l2n->netlist (); + if (! nl) { + return tl::Variant (); + } + + // build a lookup table of nets vs. cell_index+cluster_id + if (! m_nets_per_cell_and_cluster_id.get ()) { + m_nets_per_cell_and_cluster_id.reset (new std::map, const db::Net *> ()); + for (auto c = nl->begin_circuits (); c != nl->end_circuits (); ++c) { + auto ci = c->cell_index (); + for (auto n = c->begin_nets (); n != c->end_nets (); ++n) { + auto cid = n->cluster_id (); + m_nets_per_cell_and_cluster_id->insert (std::make_pair (std::make_pair (ci, cid), n.operator-> ())); + } + } + } + + auto n = m_nets_per_cell_and_cluster_id->find (std::make_pair (m_cell_index, m_cluster_id)); + if (n != m_nets_per_cell_and_cluster_id->end ()) { + return tl::Variant (n->second->name ()); + } else { + return tl::Variant (); + } +} + +} diff --git a/src/db/db/dbMeasureEval.h b/src/db/db/dbMeasureEval.h new file mode 100644 index 000000000..a0957ed2c --- /dev/null +++ b/src/db/db/dbMeasureEval.h @@ -0,0 +1,170 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2025 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#ifndef HDR_dbMeasureEval +#define HDR_dbMeasureEval + +#include "dbRegion.h" +#include "dbEdges.h" +#include "dbEdgePairs.h" +#include "dbTexts.h" +#include "dbLayoutToNetlist.h" +#include "tlExpression.h" + +namespace db +{ + +// ------------------------------------------------------------------------------------- +// Some utilities + +/** + * @brief An evaluation context for the expressions + * + * This class provides the methods, functions and variables for the expressions. + */ +class DB_PUBLIC MeasureEval + : public tl::Eval +{ +public: + MeasureEval (double dbu, bool with_put); + + void init (); + + void reset_shape () const; + void set_shape (const db::Polygon *poly) const; + void set_shape (const db::PolygonRef *poly) const; + void set_shape (const db::Edge *edge) const; + void set_shape (const db::EdgePair *edge_pair) const; + void set_shape (const db::Text *text) const; + void set_prop_id (db::properties_id_type prop_id) const; + + db::PropertiesSet &prop_set_out () const + { + return m_prop_set_out; + } + +protected: + virtual void resolve_name (const std::string &name, const tl::EvalFunction *&function, const tl::Variant *&value, tl::Variant *&var); + +private: + friend class ShapeFunction; + friend class ValueFunction; + friend class ValuesFunction; + friend class PropertyFunction; + friend class PutFunction; + + union ShapeRef + { + const db::Polygon *poly; + const db::PolygonRef *poly_ref; + const db::Edge *edge; + const db::EdgePair *edge_pair; + const db::Text *text; + void *any; + }; + + enum ShapeType + { + None, + Polygon, + PolygonRef, + Edge, + EdgePair, + Text + }; + + mutable ShapeType m_shape_type; + mutable ShapeRef mp_shape; + mutable db::properties_id_type m_prop_id; + mutable db::PropertiesSet m_prop_set_out; + double m_dbu; + bool m_with_put; + + tl::Variant shape_func () const; + tl::Variant value_func (db::property_names_id_type name_id) const; + tl::Variant value_func (const tl::Variant &name) const; + tl::Variant values_func (const tl::Variant &name) const; + void put_func (const tl::Variant &name, const tl::Variant &value) const; +}; + +/** + * @brief An evaluation context for net expressions + * + * This class provides the methods, functions and variables for the expressions. + */ +class DB_PUBLIC MeasureNetEval + : public tl::Eval +{ +public: + MeasureNetEval (const db::LayoutToNetlist *l2n, double dbu); + + void set_primary_layer (unsigned int layer_index); + void set_secondary_layer (const std::string &name, unsigned int layer_index); + void init (); + + void reset (db::cell_index_type cell_index, size_t cluster_id) const; + + bool skip () const + { + return m_skip; + } + + db::PropertiesSet &prop_set_out () const + { + return m_prop_set_out; + } + +private: + friend class NetPutFunction; + friend class NetAreaFunction; + friend class NetPerimeterFunction; + friend class NetNameFunction; + friend class NetSkipFunction; + + struct AreaAndPerimeter + { + AreaAndPerimeter () : area (0.0), perimeter (0.0) { } + double area, perimeter; + }; + + const db::LayoutToNetlist *mp_l2n; + double m_dbu; + std::vector m_layers; + mutable bool m_skip; + mutable db::PropertiesSet m_prop_set_out; + mutable db::cell_index_type m_cell_index; + mutable size_t m_cluster_id; + mutable std::map m_area_and_perimeter_cache; + mutable std::unique_ptr, const db::Net *> > m_nets_per_cell_and_cluster_id; + + AreaAndPerimeter compute_area_and_perimeter (int layer_index) const; + + void put_func (const tl::Variant &name, const tl::Variant &value) const; + tl::Variant area_func (int layer_index) const; + tl::Variant perimeter_func (int layer_index) const; + void skip_func (bool f) const; + tl::Variant net_name_func () const; +}; + +} + +#endif diff --git a/src/db/db/gsiDeclDbLayoutToNetlist.cc b/src/db/db/gsiDeclDbLayoutToNetlist.cc index c5c0a5307..91d5ca21d 100644 --- a/src/db/db/gsiDeclDbLayoutToNetlist.cc +++ b/src/db/db/gsiDeclDbLayoutToNetlist.cc @@ -216,6 +216,11 @@ static db::Region antenna_check (db::LayoutToNetlist *l2n, const db::Region &pol return antenna_check3 (l2n, poly, 1, 0, metal, 1, 0, ratio, diodes, texts); } +static db::Region measure_net (db::LayoutToNetlist *l2n, const db::Region &primary, const std::map &secondary, const std::string &expression) +{ + return l2n->measure_net (primary, secondary, expression); +} + static void join_net_names (db::LayoutToNetlist *l2n, const std::string &s) { l2n->join_net_names (tl::GlobPattern (s)); @@ -1131,84 +1136,108 @@ Class decl_dbLayoutToNetlist ("db", "LayoutToNetlist", "This method has been introduced in version 0.28.13." ) + gsi::method_ext ("antenna_check", &antenna_check, gsi::arg ("gate"), gsi::arg ("metal"), gsi::arg ("ratio"), gsi::arg ("diodes", std::vector (), "[]"), gsi::arg ("texts", (db::Texts *) 0, "nil"), - "@brief Runs an antenna check on the extracted clusters\n" - "\n" - "The antenna check will traverse all clusters and run an antenna check\n" - "for all root clusters. The antenna ratio is defined by the total\n" - "area of all \"metal\" shapes divided by the total area of all \"gate\" shapes\n" - "on the cluster. Of all clusters where the antenna ratio is larger than\n" - "the limit ratio all metal shapes are copied to the output region as\n" - "error markers.\n" - "\n" - "The simple call is:\n" - "\n" - "@code\n" - "l2n = ... # a LayoutToNetlist object\n" - "l2n.extract_netlist\n" - "# check for antenna ratio 10.0 of metal vs. poly:\n" - "errors = l2n.antenna(poly, metal, 10.0)\n" - "@/code\n" - "\n" - "You can include diodes which rectify the antenna effect. " - "Provide recognition layers for theses diodes and include them " - "in the connections. Then specify the diode layers in the antenna call:\n" - "\n" - "@code\n" - "...\n" - "# include diode_layer1:\n" - "errors = l2n.antenna(poly, metal, 10.0, [ diode_layer1 ])\n" - "# include diode_layer1 and diode_layer2:" - "errors = l2n.antenna(poly, metal, 10.0, [ diode_layer1, diode_layer2 ])\n" - "@/code\n" - "\n" - "Diodes can be configured to partially reduce the antenna effect depending " - "on their area. This will make the diode_layer1 increase the ratio by 50.0 " - "per square micrometer area of the diode:\n" - "\n" - "@code\n" - "...\n" - "# diode_layer1 increases the ratio by 50 per square micrometer area:\n" - "errors = l2n.antenna(poly, metal, 10.0 [ [ diode_layer, 50.0 ] ])\n" - "@/code\n" - "\n" - "If 'texts' is non-nil, this text collection will receive labels explaining the error in " - "terms of area values and relevant ratio.\n" - "\n" - "The 'texts' parameter has been added in version 0.27.11." + "@brief Runs an antenna check on the extracted clusters\n" + "\n" + "The antenna check will traverse all clusters and run an antenna check\n" + "for all root clusters. The antenna ratio is defined by the total\n" + "area of all \"metal\" shapes divided by the total area of all \"gate\" shapes\n" + "on the cluster. Of all clusters where the antenna ratio is larger than\n" + "the limit ratio all metal shapes are copied to the output region as\n" + "error markers.\n" + "\n" + "The simple call is:\n" + "\n" + "@code\n" + "l2n = ... # a LayoutToNetlist object\n" + "l2n.extract_netlist\n" + "# check for antenna ratio 10.0 of metal vs. poly:\n" + "errors = l2n.antenna(poly, metal, 10.0)\n" + "@/code\n" + "\n" + "You can include diodes which rectify the antenna effect. " + "Provide recognition layers for theses diodes and include them " + "in the connections. Then specify the diode layers in the antenna call:\n" + "\n" + "@code\n" + "...\n" + "# include diode_layer1:\n" + "errors = l2n.antenna(poly, metal, 10.0, [ diode_layer1 ])\n" + "# include diode_layer1 and diode_layer2:" + "errors = l2n.antenna(poly, metal, 10.0, [ diode_layer1, diode_layer2 ])\n" + "@/code\n" + "\n" + "Diodes can be configured to partially reduce the antenna effect depending " + "on their area. This will make the diode_layer1 increase the ratio by 50.0 " + "per square micrometer area of the diode:\n" + "\n" + "@code\n" + "...\n" + "# diode_layer1 increases the ratio by 50 per square micrometer area:\n" + "errors = l2n.antenna(poly, metal, 10.0 [ [ diode_layer, 50.0 ] ])\n" + "@/code\n" + "\n" + "If 'texts' is non-nil, this text collection will receive labels explaining the error in " + "terms of area values and relevant ratio.\n" + "\n" + "The 'texts' parameter has been added in version 0.27.11." ) + gsi::method_ext ("antenna_check", &antenna_check2, gsi::arg ("gate"), gsi::arg ("gate_perimeter_factor"), gsi::arg ("metal"), gsi::arg ("metal_perimeter_factor"), gsi::arg ("ratio"), gsi::arg ("diodes", std::vector (), "[]"), gsi::arg ("texts", (db::Texts *) 0, "nil"), - "@brief Runs an antenna check on the extracted clusters taking the perimeter into account\n" - "\n" - "This version of the \\antenna_check method allows taking the perimeter of gate or metal into account. " - "The effective area is computed using:\n" - "\n" - "@code\n" - "Aeff = A + P * t\n" - "@/code\n" - "\n" - "Here Aeff is the area used in the check, A is the polygon area, P the perimeter and t the perimeter factor. " - "This formula applies to gate polygon area/perimeter with 'gate_perimeter_factor' for t and metal polygon area/perimeter " - "with 'metal_perimeter_factor'. The perimeter_factor has the dimension of micrometers and can be thought of as the width " - "of the material. Essentially the side walls of the material are taking into account for the surface area as well.\n" - "\n" - "This variant has been introduced in version 0.26.6.\n" + "@brief Runs an antenna check on the extracted clusters taking the perimeter into account\n" + "\n" + "This version of the \\antenna_check method allows taking the perimeter of gate or metal into account. " + "The effective area is computed using:\n" + "\n" + "@code\n" + "Aeff = A + P * t\n" + "@/code\n" + "\n" + "Here Aeff is the area used in the check, A is the polygon area, P the perimeter and t the perimeter factor. " + "This formula applies to gate polygon area/perimeter with 'gate_perimeter_factor' for t and metal polygon area/perimeter " + "with 'metal_perimeter_factor'. The perimeter_factor has the dimension of micrometers and can be thought of as the width " + "of the material. Essentially the side walls of the material are taking into account for the surface area as well.\n" + "\n" + "This variant has been introduced in version 0.26.6.\n" ) + gsi::method_ext ("antenna_check", &antenna_check3, gsi::arg ("gate"), gsi::arg ("gate_area_factor"), gsi::arg ("gate_perimeter_factor"), gsi::arg ("metal"), gsi::arg ("metal_area_factor"), gsi::arg ("metal_perimeter_factor"), gsi::arg ("ratio"), gsi::arg ("diodes", std::vector (), "[]"), gsi::arg ("texts", (db::Texts *) 0, "nil"), - "@brief Runs an antenna check on the extracted clusters taking the perimeter into account and providing an area factor\n" - "\n" - "This (most generic) version of the \\antenna_check method allows taking the perimeter of gate or metal into account and also " - "provides a scaling factor for the area part.\n" - "The effective area is computed using:\n" - "\n" - "@code\n" - "Aeff = A * f + P * t\n" - "@/code\n" - "\n" - "Here f is the area factor and t the perimeter factor. A is the polygon area and P the polygon perimeter. " - "A use case for this variant is to set the area factor to zero. This way, only perimeter contributions are " - "considered.\n" - "\n" - "This variant has been introduced in version 0.26.6.\n" + "@brief Runs an antenna check on the extracted clusters taking the perimeter into account and providing an area factor\n" + "\n" + "This (most generic) version of the \\antenna_check method allows taking the perimeter of gate or metal into account and also " + "provides a scaling factor for the area part.\n" + "The effective area is computed using:\n" + "\n" + "@code\n" + "Aeff = A * f + P * t\n" + "@/code\n" + "\n" + "Here f is the area factor and t the perimeter factor. A is the polygon area and P the polygon perimeter. " + "A use case for this variant is to set the area factor to zero. This way, only perimeter contributions are " + "considered.\n" + "\n" + "This variant has been introduced in version 0.26.6.\n" + ) + + gsi::method_ext ("measure_net", &measure_net, gsi::arg ("primary"), gsi::arg ("secondary"), gsi::arg ("expression"), + "@brief Runs a generic net measurement function\n" + "\n" + "This method accepts some primary layer, a number of secondary layers with names and an expression.\n" + "\n" + "It will look at nets connecting to shapes on the primary layer and execute the expression for each\n" + "of those nets. After that it will copy the primary shapes of the net to the output with the properties\n" + "placed by 'put' attached to them.\n" + "\n" + "It is possible to skip primary shapes of a specific net by calling the 'skip' function with a 'true'\n" + "value.\n" + "\n" + "The expression may use the following functions:\n" + "\n" + "@ul\n" + "@li 'area': the area of all primary-layer shapes on the net in square um @/li\n" + "@li 'area(name)': the area of all secondary-layer shapes. 'name' is a symbol with the name given in the secondary-layer map @/li\n" + "@li 'perimeter': the perimeter of the primary-layer shapes on the net in um @/li\n" + "@li 'perimeter(name)': the perimeter of the secondary-layer shapes. 'name' is a symbol with the name given in the secondary-layer map @/li\n" + "@li 'put(name, value)': places the value as property 'name' on the output shapes @/li\n" + "@li 'skip(flag)': will skip the primary shapes of that net when called with a true value @/li\n" + "@li 'net_name': the name of the net @/li\n" + "@/ul\n" ) + // test API gsi::method ("make_soft_connection_diodes=", &db::LayoutToNetlist::set_make_soft_connection_diodes, gsi::arg ("flag"), "@hide") + diff --git a/src/db/db/gsiDeclDbMeasureHelpers.cc b/src/db/db/gsiDeclDbMeasureHelpers.cc index ad3958037..1fb1dae0c 100644 --- a/src/db/db/gsiDeclDbMeasureHelpers.cc +++ b/src/db/db/gsiDeclDbMeasureHelpers.cc @@ -20,307 +20,12 @@ */ +#include "dbMeasureEval.h" #include "gsiDeclDbMeasureHelpers.h" namespace gsi { -class ShapeFunction - : public tl::EvalFunction -{ -public: - ShapeFunction (MeasureEval *eval) - : mp_eval (eval) - { - // .. nothing yet .. - } - - virtual void execute (const tl::ExpressionParserContext &context, tl::Variant &out, const std::vector &args, const std::map * /*kwargs*/) const - { - if (args.size () != 0) { - throw tl::EvalError (tl::to_string (tr ("'shape' function does not take arguments")), context); - } - out = mp_eval->shape_func (); - } - -private: - MeasureEval *mp_eval; -}; - -class ValueFunction - : public tl::EvalFunction -{ -public: - ValueFunction (MeasureEval *eval) - : mp_eval (eval) - { - // .. nothing yet .. - } - - virtual void execute (const tl::ExpressionParserContext &context, tl::Variant &out, const std::vector &args, const std::map * /*kwargs*/) const - { - if (args.size () != 1) { - throw tl::EvalError (tl::to_string (tr ("'value' function takes one argument")), context); - } - out = mp_eval->value_func (args [0]); - } - -private: - MeasureEval *mp_eval; -}; - -class ValuesFunction - : public tl::EvalFunction -{ -public: - ValuesFunction (MeasureEval *eval) - : mp_eval (eval) - { - // .. nothing yet .. - } - - virtual void execute (const tl::ExpressionParserContext &context, tl::Variant &out, const std::vector &args, const std::map * /*kwargs*/) const - { - if (args.size () != 1) { - throw tl::EvalError (tl::to_string (tr ("'values' function takes one argument")), context); - } - out = mp_eval->values_func (args [0]); - } - -private: - MeasureEval *mp_eval; -}; - -class PropertyFunction - : public tl::EvalFunction -{ -public: - PropertyFunction (MeasureEval *eval, const tl::Variant &name) - : mp_eval (eval), m_name_id (db::property_names_id (name)) - { - // .. nothing yet .. - } - - virtual void execute (const tl::ExpressionParserContext &context, tl::Variant &out, const std::vector &args, const std::map * /*kwargs*/) const - { - if (args.size () != 0) { - throw tl::EvalError (tl::to_string (tr ("Property getter function does not take arguments")), context); - } - out = mp_eval->value_func (m_name_id); - } - -private: - MeasureEval *mp_eval; - db::property_names_id_type m_name_id; -}; - -class PutFunction - : public tl::EvalFunction -{ -public: - PutFunction (MeasureEval *eval) - : mp_eval (eval) - { - // .. nothing yet .. - } - - virtual void execute (const tl::ExpressionParserContext &context, tl::Variant & /*out*/, const std::vector &args, const std::map * /*kwargs*/) const - { - if (args.size () != 2) { - throw tl::EvalError (tl::to_string (tr ("'put' function takes two arguments (name, value)")), context); - } - mp_eval->put_func (args [0], args [1]); - } - -private: - MeasureEval *mp_eval; - db::property_names_id_type m_name_id; -}; - -// -------------------------------------------------------------------- -// MeasureEval implementation - -MeasureEval::MeasureEval (double dbu, bool with_put) - : m_shape_type (None), m_prop_id (0), m_dbu (dbu), m_with_put (with_put) -{ - mp_shape.any = 0; -} - -void -MeasureEval::init () -{ - if (m_with_put) { - define_function ("put", new PutFunction (this)); - } - - define_function ("shape", new ShapeFunction (this)); - define_function ("value", new ValueFunction (this)); - define_function ("values", new ValuesFunction (this)); -} - -void -MeasureEval::reset_shape () const -{ - m_shape_type = None; - mp_shape.any = 0; - m_prop_id = 0; -} - -void -MeasureEval::set_shape (const db::Polygon *poly) const -{ - m_shape_type = Polygon; - mp_shape.poly = poly; -} - -void -MeasureEval::set_shape (const db::PolygonRef *poly) const -{ - m_shape_type = PolygonRef; - mp_shape.poly_ref = poly; -} - -void -MeasureEval::set_shape (const db::Edge *edge) const -{ - m_shape_type = Edge; - mp_shape.edge = edge; -} - -void -MeasureEval::set_shape (const db::EdgePair *edge_pair) const -{ - m_shape_type = EdgePair; - mp_shape.edge_pair = edge_pair; -} - -void -MeasureEval::set_shape (const db::Text *text) const -{ - m_shape_type = Text; - mp_shape.text = text; -} - -void -MeasureEval::set_prop_id (db::properties_id_type prop_id) const -{ - m_prop_id = prop_id; -} - -void -MeasureEval::resolve_name (const std::string &name, const tl::EvalFunction *&function, const tl::Variant *&value, tl::Variant *&var) -{ - tl::Eval::resolve_name (name, function, value, var); - - if (!function && !value && !var) { - // connect the name with a function getting the property value - tl::EvalFunction *f = new PropertyFunction (this, name); - define_function (name, f); - function = f; - } -} - -tl::Variant -MeasureEval::shape_func () const -{ - if (m_dbu > 1e-10) { - - db::CplxTrans tr (m_dbu); - - switch (m_shape_type) - { - case None: - default: - return tl::Variant (); - case Polygon: - return tl::Variant (tr * *mp_shape.poly); - case PolygonRef: - { - db::Polygon poly; - mp_shape.poly_ref->instantiate (poly); - return tl::Variant (tr * poly); - } - case Edge: - return tl::Variant (tr * *mp_shape.edge); - case EdgePair: - return tl::Variant (tr * *mp_shape.edge_pair); - case Text: - return tl::Variant (tr * *mp_shape.text); - } - - } else { - - switch (m_shape_type) - { - case None: - default: - return tl::Variant (); - case Polygon: - return tl::Variant (*mp_shape.poly); - case PolygonRef: - { - db::Polygon poly; - mp_shape.poly_ref->instantiate (poly); - return tl::Variant (poly); - } - case Edge: - return tl::Variant (*mp_shape.edge); - case EdgePair: - return tl::Variant (*mp_shape.edge_pair); - case Text: - return tl::Variant (*mp_shape.text); - } - - } -} - -tl::Variant -MeasureEval::value_func (db::property_names_id_type name_id) const -{ - const db::PropertiesSet &ps = db::properties (m_prop_id); - for (auto i = ps.begin (); i != ps.end (); ++i) { - if (i->first == name_id) { - return db::property_value (i->second); - } - } - - return tl::Variant (); -} - -tl::Variant -MeasureEval::value_func (const tl::Variant &name) const -{ - const db::PropertiesSet &ps = db::properties (m_prop_id); - for (auto i = ps.begin (); i != ps.end (); ++i) { - if (db::property_name (i->first) == name) { - return db::property_value (i->second); - } - } - - return tl::Variant (); -} - -tl::Variant -MeasureEval::values_func (const tl::Variant &name) const -{ - tl::Variant res = tl::Variant::empty_list (); - - const db::PropertiesSet &ps = db::properties (m_prop_id); - for (auto i = ps.begin (); i != ps.end (); ++i) { - if (db::property_name (i->first) == name) { - res.push (db::property_value (i->second)); - } - } - - return res; -} - -void -MeasureEval::put_func (const tl::Variant &name, const tl::Variant &value) const -{ - auto prop_name_id = db::property_names_id (name); - m_prop_set_out.erase (prop_name_id); - m_prop_set_out.insert (prop_name_id, value); -} + // .. nothing yet .. } diff --git a/src/db/db/gsiDeclDbMeasureHelpers.h b/src/db/db/gsiDeclDbMeasureHelpers.h index 6013aa65b..2ed72114e 100644 --- a/src/db/db/gsiDeclDbMeasureHelpers.h +++ b/src/db/db/gsiDeclDbMeasureHelpers.h @@ -23,13 +23,9 @@ #ifndef HDR_gsiDeclDbMeasureHelpers #define HDR_gsiDeclDbMeasureHelpers -#include "dbRegion.h" -#include "dbEdges.h" -#include "dbEdgePairs.h" -#include "dbTexts.h" +#include "dbMeasureEval.h" #include "dbRegionUtils.h" #include "dbEdgesUtils.h" -#include "tlExpression.h" #include "gsiClassBase.h" #include "gsiDeclDbContainerHelpers.h" @@ -39,76 +35,6 @@ namespace gsi // ------------------------------------------------------------------------------------- // Some utilities -/** - * @brief An evaluation context for the expressions - * - * This class provides the methods, functions and variables for the expressions. - */ -class DB_PUBLIC MeasureEval - : public tl::Eval -{ -public: - MeasureEval (double dbu, bool with_put); - - void init (); - - void reset_shape () const; - void set_shape (const db::Polygon *poly) const; - void set_shape (const db::PolygonRef *poly) const; - void set_shape (const db::Edge *edge) const; - void set_shape (const db::EdgePair *edge_pair) const; - void set_shape (const db::Text *text) const; - void set_prop_id (db::properties_id_type prop_id) const; - - db::PropertiesSet &prop_set_out () const - { - return m_prop_set_out; - } - -protected: - virtual void resolve_name (const std::string &name, const tl::EvalFunction *&function, const tl::Variant *&value, tl::Variant *&var); - -private: - friend class ShapeFunction; - friend class ValueFunction; - friend class ValuesFunction; - friend class PropertyFunction; - friend class PutFunction; - - union ShapeRef - { - const db::Polygon *poly; - const db::PolygonRef *poly_ref; - const db::Edge *edge; - const db::EdgePair *edge_pair; - const db::Text *text; - void *any; - }; - - enum ShapeType - { - None, - Polygon, - PolygonRef, - Edge, - EdgePair, - Text - }; - - mutable ShapeType m_shape_type; - mutable ShapeRef mp_shape; - mutable db::properties_id_type m_prop_id; - mutable db::PropertiesSet m_prop_set_out; - double m_dbu; - bool m_with_put; - - tl::Variant shape_func () const; - tl::Variant value_func (db::property_names_id_type name_id) const; - tl::Variant value_func (const tl::Variant &name) const; - tl::Variant values_func (const tl::Variant &name) const; - void put_func (const tl::Variant &name, const tl::Variant &value) const; -}; - inline db::RecursiveShapeIterator begin_iter (const db::Region *region) { @@ -224,7 +150,7 @@ public: } public: - MeasureEval m_eval; + db::MeasureEval m_eval; std::vector > m_expressions; bool m_copy_properties; std::map m_expression_strings; @@ -274,7 +200,7 @@ public: } public: - MeasureEval m_eval; + db::MeasureEval m_eval; tl::Expression m_expression; bool m_inverse; std::string m_expression_string;