WIP: measure_net function for LayoutToNetlist

This commit is contained in:
Matthias Koefferlein 2025-08-02 19:17:23 +02:00
parent 8e95f6a8e1
commit e82ebf6733
8 changed files with 946 additions and 487 deletions

View File

@ -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 = \

View File

@ -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<db::NetShape> &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<db::NetShape> rci (clusters, layer_id, ci, cid); !rci.at_end (); ++rci) {
for (db::recursive_cluster_shape_iterator<db::NetShape> 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<db::NetShape> rci (clusters, layer_id, ci, cid); !rci.at_end (); ++rci) {
for (db::recursive_cluster_shape_iterator<db::NetShape> 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<db::NetShape>
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<db::NetShape> &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<db::NetShape> rci (clusters, layer_id, ci, cid); !rci.at_end (); ++rci) {
for (db::recursive_cluster_shape_iterator<db::NetShape> 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<db::NetShape> rci (clusters, layer_id, ci, cid); !rci.at_end (); ++rci) {
for (db::recursive_cluster_shape_iterator<db::NetShape> 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<db::NetShape> &clusters, db::c
}
}
db::AntennaShapeGenerator sg (layout, shapes, prop_id);
db::PolygonRefToShapesGenerator sg (const_cast<db::Layout *> (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<std::string, const db::Region *> &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<db::NetShape> &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<db::NetShape>::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)
{

View File

@ -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<std::pair<const db::Region *, double> > &diodes = std::vector<std::pair<const db::Region *, double> > (), 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<std::string, const db::Region *> &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);

561
src/db/db/dbMeasureEval.cc Normal file
View File

@ -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<tl::Variant> &args, const std::map<std::string, tl::Variant> * /*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<tl::Variant> &args, const std::map<std::string, tl::Variant> * /*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<tl::Variant> &args, const std::map<std::string, tl::Variant> * /*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<tl::Variant> &args, const std::map<std::string, tl::Variant> * /*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<tl::Variant> &args, const std::map<std::string, tl::Variant> * /*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<tl::Variant> &args, const std::map<std::string, tl::Variant> * /*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<tl::Variant> &args, const std::map<std::string, tl::Variant> * /*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<tl::Variant> &args, const std::map<std::string, tl::Variant> * /*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<tl::Variant> &args, const std::map<std::string, tl::Variant> * /*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<tl::Variant> &args, const std::map<std::string, tl::Variant> * /*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<std::pair<db::cell_index_type, size_t>, 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 ();
}
}
}

170
src/db/db/dbMeasureEval.h Normal file
View File

@ -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<unsigned int> 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<unsigned int, AreaAndPerimeter> m_area_and_perimeter_cache;
mutable std::unique_ptr<std::map<std::pair<db::cell_index_type, size_t>, 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

View File

@ -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<std::string, const db::Region *> &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<db::LayoutToNetlist> 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<tl::Variant> (), "[]"), 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<tl::Variant> (), "[]"), 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<tl::Variant> (), "[]"), 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") +

View File

@ -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<tl::Variant> &args, const std::map<std::string, tl::Variant> * /*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<tl::Variant> &args, const std::map<std::string, tl::Variant> * /*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<tl::Variant> &args, const std::map<std::string, tl::Variant> * /*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<tl::Variant> &args, const std::map<std::string, tl::Variant> * /*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<tl::Variant> &args, const std::map<std::string, tl::Variant> * /*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 ..
}

View File

@ -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<std::pair<db::property_names_id_type, tl::Expression> > m_expressions;
bool m_copy_properties;
std::map<tl::Variant, std::string> 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;