mirror of https://github.com/KLayout/klayout.git
WIP: measure_net function for LayoutToNetlist
This commit is contained in:
parent
8e95f6a8e1
commit
e82ebf6733
|
|
@ -58,6 +58,7 @@ SOURCES = \
|
||||||
dbLog.cc \
|
dbLog.cc \
|
||||||
dbManager.cc \
|
dbManager.cc \
|
||||||
dbMatrix.cc \
|
dbMatrix.cc \
|
||||||
|
dbMeasureEval.cc \
|
||||||
dbMemStatistics.cc \
|
dbMemStatistics.cc \
|
||||||
dbMutableEdgePairs.cc \
|
dbMutableEdgePairs.cc \
|
||||||
dbMutableEdges.cc \
|
dbMutableEdges.cc \
|
||||||
|
|
@ -296,6 +297,7 @@ HEADERS = \
|
||||||
dbLog.h \
|
dbLog.h \
|
||||||
dbManager.h \
|
dbManager.h \
|
||||||
dbMatrix.h \
|
dbMatrix.h \
|
||||||
|
dbMeasureEval.h \
|
||||||
dbMemStatistics.h \
|
dbMemStatistics.h \
|
||||||
dbMetaInfo.h \
|
dbMetaInfo.h \
|
||||||
dbMutableEdgePairs.h \
|
dbMutableEdgePairs.h \
|
||||||
|
|
@ -432,6 +434,7 @@ HEADERS = \
|
||||||
dbNetShape.h \
|
dbNetShape.h \
|
||||||
dbShapeCollection.h \
|
dbShapeCollection.h \
|
||||||
dbShapeCollectionUtils.h \
|
dbShapeCollectionUtils.h \
|
||||||
|
gsiDeclDbMeasureHelpers.h \
|
||||||
gsiDeclDbPropertiesSupport.h
|
gsiDeclDbPropertiesSupport.h
|
||||||
|
|
||||||
RESOURCES = \
|
RESOURCES = \
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@
|
||||||
#include "dbLayoutToNetlistSoftConnections.h"
|
#include "dbLayoutToNetlistSoftConnections.h"
|
||||||
#include "dbShapeProcessor.h"
|
#include "dbShapeProcessor.h"
|
||||||
#include "dbNetlistDeviceClasses.h"
|
#include "dbNetlistDeviceClasses.h"
|
||||||
|
#include "dbMeasureEval.h"
|
||||||
#include "dbLog.h"
|
#include "dbLog.h"
|
||||||
#include "tlGlobPattern.h"
|
#include "tlGlobPattern.h"
|
||||||
|
|
||||||
|
|
@ -1772,20 +1773,20 @@ public:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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)
|
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;
|
db::EdgeProcessor ep;
|
||||||
|
|
||||||
// count vertices and reserve space
|
// count vertices and reserve space
|
||||||
size_t n = 0;
|
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 ();
|
n += rci->polygon_ref ().vertices ();
|
||||||
}
|
}
|
||||||
ep.reserve (n);
|
ep.reserve (n);
|
||||||
|
|
||||||
size_t p = 0;
|
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);
|
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 ();
|
perimeter = ap_collector.perimeter ();
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
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
|
||||||
class AntennaShapeGenerator
|
|
||||||
: public PolygonSink
|
|
||||||
{
|
{
|
||||||
public:
|
const db::Layout *layout = &dss ().const_layout (m_layout_index);
|
||||||
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)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
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;
|
db::Point ref;
|
||||||
bool any_ref = false;
|
bool any_ref = false;
|
||||||
db::EdgeProcessor ep;
|
db::EdgeProcessor ep;
|
||||||
|
|
||||||
// count vertices and reserve space
|
// count vertices and reserve space
|
||||||
size_t n = 0;
|
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 ();
|
n += rci->polygon_ref ().vertices ();
|
||||||
}
|
}
|
||||||
ep.reserve (n);
|
ep.reserve (n);
|
||||||
|
|
||||||
size_t p = 0;
|
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 pr = rci->polygon_ref ();
|
||||||
db::PolygonRef::polygon_edge_iterator e = pr.begin_edge ();
|
db::PolygonRef::polygon_edge_iterator e = pr.begin_edge ();
|
||||||
if (! e.at_end ()) {
|
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::PolygonGenerator pg (sg, false);
|
||||||
db::SimpleMerge op;
|
db::SimpleMerge op;
|
||||||
ep.process (pg, 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::area_type adiode_int = 0;
|
||||||
db::Polygon::perimeter_type pdiode_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);
|
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::area_type agate_int = 0;
|
||||||
db::Polygon::perimeter_type pgate_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;
|
double agate = 0.0;
|
||||||
if (fabs (gate_area_factor) > 1e-6) {
|
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::area_type ametal_int = 0;
|
||||||
db::Polygon::perimeter_type pmetal_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;
|
double ametal = 0.0;
|
||||||
if (fabs (metal_area_factor) > 1e-6) {
|
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);
|
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) {
|
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));
|
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)
|
void LayoutToNetlist::save (const std::string &path, bool short_format)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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);
|
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
|
* @brief Saves the database to the given path
|
||||||
*
|
*
|
||||||
|
|
@ -1170,6 +1194,16 @@ public:
|
||||||
m_make_soft_connection_diodes = f;
|
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:
|
private:
|
||||||
// no copying
|
// no copying
|
||||||
LayoutToNetlist (const db::LayoutToNetlist &other);
|
LayoutToNetlist (const db::LayoutToNetlist &other);
|
||||||
|
|
|
||||||
|
|
@ -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 ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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);
|
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)
|
static void join_net_names (db::LayoutToNetlist *l2n, const std::string &s)
|
||||||
{
|
{
|
||||||
l2n->join_net_names (tl::GlobPattern (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."
|
"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"),
|
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"
|
"@brief Runs an antenna check on the extracted clusters\n"
|
||||||
"\n"
|
"\n"
|
||||||
"The antenna check will traverse all clusters and run an antenna check\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"
|
"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"
|
"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"
|
"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"
|
"the limit ratio all metal shapes are copied to the output region as\n"
|
||||||
"error markers.\n"
|
"error markers.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"The simple call is:\n"
|
"The simple call is:\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@code\n"
|
"@code\n"
|
||||||
"l2n = ... # a LayoutToNetlist object\n"
|
"l2n = ... # a LayoutToNetlist object\n"
|
||||||
"l2n.extract_netlist\n"
|
"l2n.extract_netlist\n"
|
||||||
"# check for antenna ratio 10.0 of metal vs. poly:\n"
|
"# check for antenna ratio 10.0 of metal vs. poly:\n"
|
||||||
"errors = l2n.antenna(poly, metal, 10.0)\n"
|
"errors = l2n.antenna(poly, metal, 10.0)\n"
|
||||||
"@/code\n"
|
"@/code\n"
|
||||||
"\n"
|
"\n"
|
||||||
"You can include diodes which rectify the antenna effect. "
|
"You can include diodes which rectify the antenna effect. "
|
||||||
"Provide recognition layers for theses diodes and include them "
|
"Provide recognition layers for theses diodes and include them "
|
||||||
"in the connections. Then specify the diode layers in the antenna call:\n"
|
"in the connections. Then specify the diode layers in the antenna call:\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@code\n"
|
"@code\n"
|
||||||
"...\n"
|
"...\n"
|
||||||
"# include diode_layer1:\n"
|
"# include diode_layer1:\n"
|
||||||
"errors = l2n.antenna(poly, metal, 10.0, [ diode_layer1 ])\n"
|
"errors = l2n.antenna(poly, metal, 10.0, [ diode_layer1 ])\n"
|
||||||
"# include diode_layer1 and diode_layer2:"
|
"# include diode_layer1 and diode_layer2:"
|
||||||
"errors = l2n.antenna(poly, metal, 10.0, [ diode_layer1, diode_layer2 ])\n"
|
"errors = l2n.antenna(poly, metal, 10.0, [ diode_layer1, diode_layer2 ])\n"
|
||||||
"@/code\n"
|
"@/code\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Diodes can be configured to partially reduce the antenna effect depending "
|
"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 "
|
"on their area. This will make the diode_layer1 increase the ratio by 50.0 "
|
||||||
"per square micrometer area of the diode:\n"
|
"per square micrometer area of the diode:\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@code\n"
|
"@code\n"
|
||||||
"...\n"
|
"...\n"
|
||||||
"# diode_layer1 increases the ratio by 50 per square micrometer area:\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"
|
"errors = l2n.antenna(poly, metal, 10.0 [ [ diode_layer, 50.0 ] ])\n"
|
||||||
"@/code\n"
|
"@/code\n"
|
||||||
"\n"
|
"\n"
|
||||||
"If 'texts' is non-nil, this text collection will receive labels explaining the error in "
|
"If 'texts' is non-nil, this text collection will receive labels explaining the error in "
|
||||||
"terms of area values and relevant ratio.\n"
|
"terms of area values and relevant ratio.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"The 'texts' parameter has been added in version 0.27.11."
|
"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"),
|
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"
|
"@brief Runs an antenna check on the extracted clusters taking the perimeter into account\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This version of the \\antenna_check method allows taking the perimeter of gate or metal into account. "
|
"This version of the \\antenna_check method allows taking the perimeter of gate or metal into account. "
|
||||||
"The effective area is computed using:\n"
|
"The effective area is computed using:\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@code\n"
|
"@code\n"
|
||||||
"Aeff = A + P * t\n"
|
"Aeff = A + P * t\n"
|
||||||
"@/code\n"
|
"@/code\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Here Aeff is the area used in the check, A is the polygon area, P the perimeter and t the perimeter factor. "
|
"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 "
|
"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 "
|
"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"
|
"of the material. Essentially the side walls of the material are taking into account for the surface area as well.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This variant has been introduced in version 0.26.6.\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"),
|
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"
|
"@brief Runs an antenna check on the extracted clusters taking the perimeter into account and providing an area factor\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This (most generic) version of the \\antenna_check method allows taking the perimeter of gate or metal into account and also "
|
"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"
|
"provides a scaling factor for the area part.\n"
|
||||||
"The effective area is computed using:\n"
|
"The effective area is computed using:\n"
|
||||||
"\n"
|
"\n"
|
||||||
"@code\n"
|
"@code\n"
|
||||||
"Aeff = A * f + P * t\n"
|
"Aeff = A * f + P * t\n"
|
||||||
"@/code\n"
|
"@/code\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Here f is the area factor and t the perimeter factor. A is the polygon area and P the polygon perimeter. "
|
"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 "
|
"A use case for this variant is to set the area factor to zero. This way, only perimeter contributions are "
|
||||||
"considered.\n"
|
"considered.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This variant has been introduced in version 0.26.6.\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
|
// test API
|
||||||
gsi::method ("make_soft_connection_diodes=", &db::LayoutToNetlist::set_make_soft_connection_diodes, gsi::arg ("flag"), "@hide") +
|
gsi::method ("make_soft_connection_diodes=", &db::LayoutToNetlist::set_make_soft_connection_diodes, gsi::arg ("flag"), "@hide") +
|
||||||
|
|
|
||||||
|
|
@ -20,307 +20,12 @@
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "dbMeasureEval.h"
|
||||||
#include "gsiDeclDbMeasureHelpers.h"
|
#include "gsiDeclDbMeasureHelpers.h"
|
||||||
|
|
||||||
namespace gsi
|
namespace gsi
|
||||||
{
|
{
|
||||||
|
|
||||||
class ShapeFunction
|
// .. nothing yet ..
|
||||||
: 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,13 +23,9 @@
|
||||||
#ifndef HDR_gsiDeclDbMeasureHelpers
|
#ifndef HDR_gsiDeclDbMeasureHelpers
|
||||||
#define HDR_gsiDeclDbMeasureHelpers
|
#define HDR_gsiDeclDbMeasureHelpers
|
||||||
|
|
||||||
#include "dbRegion.h"
|
#include "dbMeasureEval.h"
|
||||||
#include "dbEdges.h"
|
|
||||||
#include "dbEdgePairs.h"
|
|
||||||
#include "dbTexts.h"
|
|
||||||
#include "dbRegionUtils.h"
|
#include "dbRegionUtils.h"
|
||||||
#include "dbEdgesUtils.h"
|
#include "dbEdgesUtils.h"
|
||||||
#include "tlExpression.h"
|
|
||||||
#include "gsiClassBase.h"
|
#include "gsiClassBase.h"
|
||||||
#include "gsiDeclDbContainerHelpers.h"
|
#include "gsiDeclDbContainerHelpers.h"
|
||||||
|
|
||||||
|
|
@ -39,76 +35,6 @@ namespace gsi
|
||||||
// -------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------
|
||||||
// Some utilities
|
// 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
|
inline db::RecursiveShapeIterator
|
||||||
begin_iter (const db::Region *region)
|
begin_iter (const db::Region *region)
|
||||||
{
|
{
|
||||||
|
|
@ -224,7 +150,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MeasureEval m_eval;
|
db::MeasureEval m_eval;
|
||||||
std::vector<std::pair<db::property_names_id_type, tl::Expression> > m_expressions;
|
std::vector<std::pair<db::property_names_id_type, tl::Expression> > m_expressions;
|
||||||
bool m_copy_properties;
|
bool m_copy_properties;
|
||||||
std::map<tl::Variant, std::string> m_expression_strings;
|
std::map<tl::Variant, std::string> m_expression_strings;
|
||||||
|
|
@ -274,7 +200,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MeasureEval m_eval;
|
db::MeasureEval m_eval;
|
||||||
tl::Expression m_expression;
|
tl::Expression m_expression;
|
||||||
bool m_inverse;
|
bool m_inverse;
|
||||||
std::string m_expression_string;
|
std::string m_expression_string;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue