mirror of https://github.com/KLayout/klayout.git
WIP
This commit is contained in:
parent
427ac0ae16
commit
ede15ffcc0
|
|
@ -55,6 +55,8 @@ class EdgePairs;
|
|||
class DB_PUBLIC EdgePairFilterBase
|
||||
{
|
||||
public:
|
||||
typedef db::EdgePair shape_type;
|
||||
|
||||
EdgePairFilterBase () { }
|
||||
virtual ~EdgePairFilterBase () { }
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@ namespace db {
|
|||
class DB_PUBLIC EdgeFilterBase
|
||||
{
|
||||
public:
|
||||
typedef db::Edge shape_type;
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -20,434 +20,15 @@
|
|||
|
||||
*/
|
||||
|
||||
#include "dbMeasure.h"
|
||||
#include "dbRegion.h"
|
||||
#include "dbEdges.h"
|
||||
#include "dbEdgePairs.h"
|
||||
#include "dbTexts.h"
|
||||
#include "tlExpression.h"
|
||||
#include "gsiClassBase.h"
|
||||
#include "gsiDeclDbContainerHelpers.h"
|
||||
#include "gsiDeclDbMeasureHelpers.h"
|
||||
|
||||
namespace db
|
||||
namespace gsi
|
||||
{
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// Some utilities
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A class collecting the properties names from the shapes delivered by a RecursiveShapeIterator
|
||||
*
|
||||
* This class implements the "RecursiveShapeReceiver" interface and will collect all property names
|
||||
* present in the shapes delivered by a RecursiveShapeIterator. Use this class as a target for
|
||||
* the RecursiveShapeIterator's "push" method. After this, "names" will give you a set with the
|
||||
* property names found.
|
||||
*/
|
||||
class PropertyNamesCollector
|
||||
: public db::RecursiveShapeReceiver
|
||||
{
|
||||
public:
|
||||
PropertyNamesCollector ()
|
||||
: m_names (), m_name_ids ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
const std::set<tl::Variant> &names () const
|
||||
{
|
||||
return m_names;
|
||||
}
|
||||
|
||||
virtual void enter_cell (const db::RecursiveShapeIterator * /*iter*/, const db::Cell *cell, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
|
||||
{
|
||||
m_cell_ids.insert (cell->cell_index ());
|
||||
}
|
||||
|
||||
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator * /*iter*/, const db::CellInstArray &inst, const db::ICplxTrans & /*always_apply*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/, bool /*skip_shapes*/)
|
||||
{
|
||||
if (m_cell_ids.find (inst.object ().cell_index ()) != m_cell_ids.end ()) {
|
||||
return NI_skip;
|
||||
} else {
|
||||
return NI_single;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void shape (const db::RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*always_apply*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
|
||||
{
|
||||
auto pid = shape.prop_id ();
|
||||
if (pid != 0 && m_pids.find (pid) == m_pids.end ()) {
|
||||
m_pids.insert (pid);
|
||||
const db::PropertiesSet &ps = db::properties (pid);
|
||||
for (auto i = ps.begin (); i != ps.end (); ++i) {
|
||||
if (m_name_ids.find (i->first) == m_name_ids.end ()) {
|
||||
m_name_ids.insert (i->first);
|
||||
m_names.insert (db::property_name (i->first));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::set<tl::Variant> m_names;
|
||||
std::unordered_set<db::property_names_id_type> m_name_ids;
|
||||
std::unordered_set<db::properties_id_type> m_pids;
|
||||
std::set<db::cell_index_type> m_cell_ids;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An evaluation context for the expressions
|
||||
*
|
||||
* This class provides the methods, functions and variables for the expressions.
|
||||
*/
|
||||
class MeasureEval
|
||||
: public tl::Eval
|
||||
{
|
||||
public:
|
||||
MeasureEval ()
|
||||
: m_shape_type (None), m_prop_id (0)
|
||||
{
|
||||
mp_shape.any = 0;
|
||||
}
|
||||
|
||||
void init (const std::set<tl::Variant> &names)
|
||||
{
|
||||
define_function ("shape", new ShapesFunction (this));
|
||||
define_function ("value", new ValueFunction (this));
|
||||
define_function ("values", new ValuesFunction (this));
|
||||
|
||||
for (auto n = names.begin (); n != names.end (); ++n) {
|
||||
if (n->is_a_string ()) {
|
||||
// TODO: should check, if the name is a word
|
||||
define_function (n->to_string (), new PropertyFunction (this, n->to_string ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void reset_shape () const
|
||||
{
|
||||
m_shape_type = None;
|
||||
mp_shape.any = 0;
|
||||
m_prop_id = 0;
|
||||
}
|
||||
|
||||
void set_shape (const db::Polygon *poly) const
|
||||
{
|
||||
m_shape_type = Polygon;
|
||||
mp_shape.poly = poly;
|
||||
}
|
||||
|
||||
void set_shape (const db::PolygonRef *poly) const
|
||||
{
|
||||
m_shape_type = PolygonRef;
|
||||
mp_shape.poly_ref = poly;
|
||||
}
|
||||
|
||||
void set_shape (const db::Edge *edge) const
|
||||
{
|
||||
m_shape_type = Edge;
|
||||
mp_shape.edge = edge;
|
||||
}
|
||||
|
||||
void set_shape (const db::EdgePair *edge_pair) const
|
||||
{
|
||||
m_shape_type = EdgePair;
|
||||
mp_shape.edge_pair = edge_pair;
|
||||
}
|
||||
|
||||
void set_shape (const db::Text *text) const
|
||||
{
|
||||
m_shape_type = Text;
|
||||
mp_shape.text = text;
|
||||
}
|
||||
|
||||
void set_prop_id (db::properties_id_type prop_id) const
|
||||
{
|
||||
m_prop_id = prop_id;
|
||||
}
|
||||
|
||||
private:
|
||||
class ShapesFunction
|
||||
: public tl::EvalFunction
|
||||
{
|
||||
public:
|
||||
ShapesFunction (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 (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);
|
||||
}
|
||||
|
||||
private:
|
||||
MeasureEval *mp_eval;
|
||||
tl::Variant m_name;
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
tl::Variant shape_func () const
|
||||
{
|
||||
switch (m_shape_type)
|
||||
{
|
||||
case None:
|
||||
default:
|
||||
return tl::Variant ();
|
||||
case Polygon:
|
||||
return tl::Variant (mp_shape.poly);
|
||||
case PolygonRef:
|
||||
return tl::Variant (mp_shape.poly_ref);
|
||||
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 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 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;
|
||||
}
|
||||
};
|
||||
|
||||
static db::RecursiveShapeIterator
|
||||
begin_iter (db::Region *region)
|
||||
{
|
||||
return region->merged_semantics () ? region->begin_merged_iter ().first : region->begin_iter ().first;
|
||||
}
|
||||
|
||||
static bool
|
||||
is_merged (db::Region *region)
|
||||
{
|
||||
return region->merged_semantics ();
|
||||
}
|
||||
|
||||
static db::RecursiveShapeIterator
|
||||
begin_iter (db::Edges *edges)
|
||||
{
|
||||
return edges->merged_semantics () ? edges->begin_merged_iter ().first : edges->begin_iter ().first;
|
||||
}
|
||||
|
||||
static bool
|
||||
is_merged (db::Edges *edges)
|
||||
{
|
||||
return edges->merged_semantics ();
|
||||
}
|
||||
|
||||
static db::RecursiveShapeIterator
|
||||
begin_iter (db::EdgePairs *edge_pairs)
|
||||
{
|
||||
return edge_pairs->begin_iter ().first;
|
||||
}
|
||||
|
||||
static bool
|
||||
is_merged (db::EdgePairs *)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static db::RecursiveShapeIterator
|
||||
begin_iter (db::Texts *texts)
|
||||
{
|
||||
return texts->begin_iter ().first;
|
||||
}
|
||||
|
||||
static bool
|
||||
is_merged (db::Texts *)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A specialization of the shape processor
|
||||
*
|
||||
* This class provides the evaluation of the expressions in the context of
|
||||
* a specific shape and shape properties. It allows creating properties with
|
||||
* a computed value.
|
||||
*/
|
||||
template <class ProcessorBase, class Container>
|
||||
class property_computation_processor
|
||||
: public gsi::shape_processor_base<ProcessorBase>
|
||||
{
|
||||
public:
|
||||
typedef typename ProcessorBase::shape_type shape_type;
|
||||
typedef typename ProcessorBase::result_type result_type;
|
||||
|
||||
property_computation_processor (Container *container, const std::map<tl::Variant, std::string> &expressions, bool copy_properties)
|
||||
: m_eval (), m_copy_properties (copy_properties)
|
||||
{
|
||||
PropertyNamesCollector names_collector;
|
||||
if (container) {
|
||||
|
||||
db::RecursiveShapeIterator iter = begin_iter (container);
|
||||
iter.push (&names_collector);
|
||||
|
||||
this->set_result_is_merged (is_merged (container));
|
||||
|
||||
}
|
||||
|
||||
m_eval.init (names_collector.names ());
|
||||
|
||||
// compile the expressions
|
||||
for (auto e = expressions.begin (); e != expressions.end (); ++e) {
|
||||
m_expressions.push_back (std::make_pair (db::property_names_id (e->first), tl::Expression ()));
|
||||
tl::Extractor ex (e->second.c_str ());
|
||||
m_eval.parse (m_expressions.back ().second, ex);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void process (const db::object_with_properties<shape_type> &shape, std::vector<db::object_with_properties<shape_type> > &res) const
|
||||
{
|
||||
res.push_back (shape);
|
||||
|
||||
m_eval.set_prop_id (shape.properties_id ());
|
||||
m_eval.set_shape (&shape);
|
||||
|
||||
db::PropertiesSet ps;
|
||||
if (m_copy_properties) {
|
||||
ps = db::properties (shape.properties_id ());
|
||||
}
|
||||
|
||||
for (auto e = m_expressions.begin (); e != m_expressions.end (); ++e) {
|
||||
ps.insert (e->first, e->second.execute ());
|
||||
}
|
||||
|
||||
res.back ().properties_id (db::properties_id (ps));
|
||||
}
|
||||
|
||||
public:
|
||||
MeasureEval m_eval;
|
||||
std::vector<std::pair<db::property_names_id_type, tl::Expression> > m_expressions;
|
||||
bool m_copy_properties;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Provides methods to handle measurement functions on various containers
|
||||
*/
|
||||
template <class Container, class ProcessorBase>
|
||||
template <class Container, class ProcessorBase, class FilterBase>
|
||||
struct measure_methods
|
||||
{
|
||||
/**
|
||||
|
|
@ -485,72 +66,63 @@ struct measure_methods
|
|||
* If inverse is false, all shapes are selected for which the condition renders true. If
|
||||
* inverse is true, all shapes are selected for which the condition renders false.
|
||||
*/
|
||||
Container selected_if (const Container &container, const std::string &condition_expression, bool inverse);
|
||||
Container selected_if (const Container *container, const std::string &condition_expression, bool inverse);
|
||||
|
||||
/**
|
||||
* @brief In-place version of "selected_if"
|
||||
*/
|
||||
void select_if (const Container &container, const std::string &condition_expression, bool inverse);
|
||||
void select_if (Container *container, const std::string &condition_expression, bool inverse);
|
||||
|
||||
/**
|
||||
* @brief Splits the container into one for which is the condition is true and one with the other shapes
|
||||
*/
|
||||
std::pair<Container, Container> split_if (const Container &container, const std::string &condition_expression);
|
||||
std::pair<Container, Container> split_if (const Container *container, const std::string &condition_expression);
|
||||
};
|
||||
|
||||
template <class Container, class ProcessorBase>
|
||||
template <class Container, class ProcessorBase, class FilterBase>
|
||||
Container
|
||||
measure_methods<Container, ProcessorBase>::computed_properties (Container *container, const std::map<tl::Variant, std::string> &expressions, bool clear_properties)
|
||||
measure_methods<Container, ProcessorBase, FilterBase>::computed_properties (Container *container, const std::map<tl::Variant, std::string> &expressions, bool clear_properties)
|
||||
{
|
||||
property_computation_processor<ProcessorBase, Container> proc (container, expressions, !clear_properties);
|
||||
return container->processed (proc);
|
||||
}
|
||||
|
||||
template <class Container, class ProcessorBase>
|
||||
template <class Container, class ProcessorBase, class FilterBase>
|
||||
void
|
||||
measure_methods<Container, ProcessorBase>::compute_properties_in_place (Container *container, const std::map<tl::Variant, std::string> &expressions, bool clear_properties)
|
||||
measure_methods<Container, ProcessorBase, FilterBase>::compute_properties_in_place (Container *container, const std::map<tl::Variant, std::string> &expressions, bool clear_properties)
|
||||
{
|
||||
property_computation_processor<ProcessorBase, Container> proc (container, expressions, !clear_properties);
|
||||
container->process (proc);
|
||||
}
|
||||
|
||||
template <class Container, class ProcessorBase>
|
||||
template <class Container, class ProcessorBase, class FilterBase>
|
||||
Container
|
||||
measure_methods<Container, ProcessorBase>::selected_if (const Container &container, const std::string &condition_expression, bool inverse)
|
||||
measure_methods<Container, ProcessorBase, FilterBase>::selected_if (const Container *container, const std::string &condition_expression, bool inverse)
|
||||
{
|
||||
// - collect property names
|
||||
// - define tl::Eval functions for property names (properties_id -> value)
|
||||
// - define tl::Eval function for shape
|
||||
// - compile expression
|
||||
// - launch filter (Region::filtered)
|
||||
expression_filter<FilterBase, Container> filter (condition_expression, inverse);
|
||||
return container->filtered (filter);
|
||||
}
|
||||
|
||||
template <class Container, class ProcessorBase>
|
||||
template <class Container, class ProcessorBase, class FilterBase>
|
||||
void
|
||||
measure_methods<Container, ProcessorBase>::select_if (const Container &container, const std::string &condition_expression, bool inverse)
|
||||
measure_methods<Container, ProcessorBase, FilterBase>::select_if (Container *container, const std::string &condition_expression, bool inverse)
|
||||
{
|
||||
// - collect property names
|
||||
// - define tl::Eval functions for property names (properties_id -> value)
|
||||
// - define tl::Eval function for shape
|
||||
// - compile expression
|
||||
// - launch filter (Region::filtered)
|
||||
expression_filter<FilterBase, Container> filter (condition_expression, inverse);
|
||||
container->filter (filter);
|
||||
}
|
||||
|
||||
template <class Container, class ProcessorBase>
|
||||
template <class Container, class ProcessorBase, class FilterBase>
|
||||
std::pair<Container, Container>
|
||||
measure_methods<Container, ProcessorBase>::split_if (const Container &container, const std::string &condition_expression)
|
||||
measure_methods<Container, ProcessorBase, FilterBase>::split_if (const Container *container, const std::string &condition_expression)
|
||||
{
|
||||
// - collect property names
|
||||
// - define tl::Eval functions for property names (properties_id -> value)
|
||||
// - define tl::Eval function for shape
|
||||
// - compile expression
|
||||
// - launch filter (Region::filtered)
|
||||
expression_filter<FilterBase, Container> filter (condition_expression, false);
|
||||
return container->split_filter (filter);
|
||||
}
|
||||
|
||||
// explicit instantiations
|
||||
template struct measure_methods<db::Region, db::shape_collection_processor<db::Polygon, db::Polygon> >;
|
||||
template struct measure_methods<db::Edges, db::shape_collection_processor<db::Edge, db::Edge> >;
|
||||
template struct measure_methods<db::EdgePairs, db::shape_collection_processor<db::EdgePair, db::EdgePair> >;
|
||||
template struct measure_methods<db::Texts, db::shape_collection_processor<db::Text, db::Text> >;
|
||||
template struct measure_methods<db::Region, db::shape_collection_processor<db::Polygon, db::Polygon>, db::AllMustMatchFilter>;
|
||||
template struct measure_methods<db::Edges, db::shape_collection_processor<db::Edge, db::Edge>, db::AllEdgesMustMatchFilter>;
|
||||
template struct measure_methods<db::EdgePairs, db::shape_collection_processor<db::EdgePair, db::EdgePair>, db::EdgePairFilterBase>;
|
||||
template struct measure_methods<db::Texts, db::shape_collection_processor<db::Text, db::Text>, db::TextFilterBase>;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,6 +57,8 @@ class Net;
|
|||
class DB_PUBLIC PolygonFilterBase
|
||||
{
|
||||
public:
|
||||
typedef db::Polygon shape_type;
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -54,6 +54,8 @@ class Texts;
|
|||
class DB_PUBLIC TextFilterBase
|
||||
{
|
||||
public:
|
||||
typedef db::Text shape_type;
|
||||
|
||||
TextFilterBase () { }
|
||||
virtual ~TextFilterBase () { }
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,436 @@
|
|||
|
||||
/*
|
||||
|
||||
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_gsiDeclDbMeasureHelpers
|
||||
#define HDR_gsiDeclDbMeasureHelpers
|
||||
|
||||
#include "dbRegion.h"
|
||||
#include "dbEdges.h"
|
||||
#include "dbEdgePairs.h"
|
||||
#include "dbTexts.h"
|
||||
#include "dbRegionUtils.h"
|
||||
#include "dbEdgesUtils.h"
|
||||
#include "tlExpression.h"
|
||||
#include "gsiClassBase.h"
|
||||
#include "gsiDeclDbContainerHelpers.h"
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// Some utilities
|
||||
|
||||
/**
|
||||
* @brief An evaluation context for the expressions
|
||||
*
|
||||
* This class provides the methods, functions and variables for the expressions.
|
||||
*/
|
||||
class MeasureEval
|
||||
: public tl::Eval
|
||||
{
|
||||
public:
|
||||
MeasureEval ()
|
||||
: m_shape_type (None), m_prop_id (0)
|
||||
{
|
||||
mp_shape.any = 0;
|
||||
}
|
||||
|
||||
void init ()
|
||||
{
|
||||
define_function ("shape", new ShapesFunction (this));
|
||||
define_function ("value", new ValueFunction (this));
|
||||
define_function ("values", new ValuesFunction (this));
|
||||
}
|
||||
|
||||
void reset_shape () const
|
||||
{
|
||||
m_shape_type = None;
|
||||
mp_shape.any = 0;
|
||||
m_prop_id = 0;
|
||||
}
|
||||
|
||||
void set_shape (const db::Polygon *poly) const
|
||||
{
|
||||
m_shape_type = Polygon;
|
||||
mp_shape.poly = poly;
|
||||
}
|
||||
|
||||
void set_shape (const db::PolygonRef *poly) const
|
||||
{
|
||||
m_shape_type = PolygonRef;
|
||||
mp_shape.poly_ref = poly;
|
||||
}
|
||||
|
||||
void set_shape (const db::Edge *edge) const
|
||||
{
|
||||
m_shape_type = Edge;
|
||||
mp_shape.edge = edge;
|
||||
}
|
||||
|
||||
void set_shape (const db::EdgePair *edge_pair) const
|
||||
{
|
||||
m_shape_type = EdgePair;
|
||||
mp_shape.edge_pair = edge_pair;
|
||||
}
|
||||
|
||||
void set_shape (const db::Text *text) const
|
||||
{
|
||||
m_shape_type = Text;
|
||||
mp_shape.text = text;
|
||||
}
|
||||
|
||||
void set_prop_id (db::properties_id_type prop_id) const
|
||||
{
|
||||
m_prop_id = prop_id;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void 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;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
class ShapesFunction
|
||||
: public tl::EvalFunction
|
||||
{
|
||||
public:
|
||||
ShapesFunction (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 (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);
|
||||
}
|
||||
|
||||
private:
|
||||
MeasureEval *mp_eval;
|
||||
tl::Variant m_name;
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
tl::Variant shape_func () const
|
||||
{
|
||||
switch (m_shape_type)
|
||||
{
|
||||
case None:
|
||||
default:
|
||||
return tl::Variant ();
|
||||
case Polygon:
|
||||
return tl::Variant (mp_shape.poly);
|
||||
case PolygonRef:
|
||||
return tl::Variant (mp_shape.poly_ref);
|
||||
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 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 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;
|
||||
}
|
||||
};
|
||||
|
||||
inline db::RecursiveShapeIterator
|
||||
begin_iter (const db::Region *region)
|
||||
{
|
||||
return region->merged_semantics () ? region->begin_merged_iter ().first : region->begin_iter ().first;
|
||||
}
|
||||
|
||||
inline bool
|
||||
is_merged (const db::Region *region)
|
||||
{
|
||||
return region->merged_semantics ();
|
||||
}
|
||||
|
||||
inline db::RecursiveShapeIterator
|
||||
begin_iter (const db::Edges *edges)
|
||||
{
|
||||
return edges->merged_semantics () ? edges->begin_merged_iter ().first : edges->begin_iter ().first;
|
||||
}
|
||||
|
||||
inline bool
|
||||
is_merged (const db::Edges *edges)
|
||||
{
|
||||
return edges->merged_semantics ();
|
||||
}
|
||||
|
||||
inline db::RecursiveShapeIterator
|
||||
begin_iter (const db::EdgePairs *edge_pairs)
|
||||
{
|
||||
return edge_pairs->begin_iter ().first;
|
||||
}
|
||||
|
||||
inline bool
|
||||
is_merged (const db::EdgePairs *)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
inline db::RecursiveShapeIterator
|
||||
begin_iter (const db::Texts *texts)
|
||||
{
|
||||
return texts->begin_iter ().first;
|
||||
}
|
||||
|
||||
inline bool
|
||||
is_merged (const db::Texts *)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A specialization of the shape processor
|
||||
*
|
||||
* This class provides the evaluation of the expressions in the context of
|
||||
* a specific shape and shape properties. It allows creating properties with
|
||||
* a computed value.
|
||||
*/
|
||||
template <class ProcessorBase, class Container>
|
||||
class property_computation_processor
|
||||
: public gsi::shape_processor_base<ProcessorBase>
|
||||
{
|
||||
public:
|
||||
typedef typename ProcessorBase::shape_type shape_type;
|
||||
typedef typename ProcessorBase::result_type result_type;
|
||||
|
||||
property_computation_processor (const Container *container, const std::map<tl::Variant, std::string> &expressions, bool copy_properties)
|
||||
: m_eval (), m_copy_properties (copy_properties)
|
||||
{
|
||||
if (container) {
|
||||
this->set_result_is_merged (is_merged (container));
|
||||
}
|
||||
|
||||
m_eval.init ();
|
||||
|
||||
// compile the expressions
|
||||
for (auto e = expressions.begin (); e != expressions.end (); ++e) {
|
||||
m_expressions.push_back (std::make_pair (db::property_names_id (e->first), tl::Expression ()));
|
||||
tl::Extractor ex (e->second.c_str ());
|
||||
m_eval.parse (m_expressions.back ().second, ex);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void process (const db::object_with_properties<shape_type> &shape, std::vector<db::object_with_properties<shape_type> > &res) const
|
||||
{
|
||||
res.push_back (shape);
|
||||
|
||||
m_eval.set_prop_id (shape.properties_id ());
|
||||
m_eval.set_shape (&shape);
|
||||
|
||||
db::PropertiesSet ps;
|
||||
if (m_copy_properties) {
|
||||
ps = db::properties (shape.properties_id ());
|
||||
}
|
||||
|
||||
for (auto e = m_expressions.begin (); e != m_expressions.end (); ++e) {
|
||||
ps.insert (e->first, e->second.execute ());
|
||||
}
|
||||
|
||||
res.back ().properties_id (db::properties_id (ps));
|
||||
}
|
||||
|
||||
public:
|
||||
MeasureEval m_eval;
|
||||
std::vector<std::pair<db::property_names_id_type, tl::Expression> > m_expressions;
|
||||
bool m_copy_properties;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A specialization of the shape processor
|
||||
*
|
||||
* This class provides the evaluation of the expressions in the context of
|
||||
* a specific shape and shape properties. It allows creating properties with
|
||||
* a computed value.
|
||||
*/
|
||||
template <class FilterBase, class Container>
|
||||
class expression_filter
|
||||
: public gsi::shape_filter_impl<FilterBase>
|
||||
{
|
||||
public:
|
||||
typedef typename FilterBase::shape_type shape_type;
|
||||
|
||||
expression_filter (const std::string &expression, bool inverse)
|
||||
: m_eval (), m_inverse (inverse)
|
||||
{
|
||||
m_eval.init ();
|
||||
|
||||
// compile the expression
|
||||
tl::Extractor ex (expression.c_str ());
|
||||
m_eval.parse (m_expression, ex);
|
||||
}
|
||||
|
||||
virtual bool selected (const shape_type &shape, db::properties_id_type prop_id) const
|
||||
{
|
||||
m_eval.set_prop_id (prop_id);
|
||||
m_eval.set_shape (&shape);
|
||||
|
||||
bool res = m_expression.execute ().to_bool ();
|
||||
return m_inverse ? !res : res;
|
||||
}
|
||||
|
||||
// only needed for PolygonFilterBase
|
||||
virtual bool selected (const db::PolygonRef &shape, db::properties_id_type prop_id) const
|
||||
{
|
||||
m_eval.set_prop_id (prop_id);
|
||||
m_eval.set_shape (&shape);
|
||||
|
||||
bool res = m_expression.execute ().to_bool ();
|
||||
return m_inverse ? !res : res;
|
||||
}
|
||||
|
||||
public:
|
||||
MeasureEval m_eval;
|
||||
tl::Expression m_expression;
|
||||
bool m_inverse;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -41,6 +41,7 @@
|
|||
#include "tlGlobPattern.h"
|
||||
|
||||
#include "gsiDeclDbContainerHelpers.h"
|
||||
#include "gsiDeclDbMeasureHelpers.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
|
@ -108,6 +109,11 @@ static gsi::PolygonFilterBase *make_pg (const tl::Variant &name, const std::stri
|
|||
return new PolygonPropertiesFilter (name, pattern, inverse);
|
||||
}
|
||||
|
||||
static gsi::PolygonFilterBase *make_pe (const std::string &expression, bool inverse)
|
||||
{
|
||||
return new gsi::expression_filter<gsi::PolygonFilterBase, db::Region> (expression, inverse);
|
||||
}
|
||||
|
||||
Class<gsi::PolygonFilterBase> decl_PolygonFilterBase ("db", "PolygonFilterBase",
|
||||
gsi::PolygonFilterBase::method_decls (true) +
|
||||
gsi::constructor ("property_glob", &make_pg, gsi::arg ("name"), gsi::arg ("pattern"), gsi::arg ("inverse", false), gsi::arg ("case_sensitive", true),
|
||||
|
|
@ -148,6 +154,24 @@ Class<gsi::PolygonFilterBase> decl_PolygonFilterBase ("db", "PolygonFilterBase",
|
|||
"Apply this filter with \\Region#filtered. See \\property_glob for an example.\n"
|
||||
"\n"
|
||||
"This feature has been introduced in version 0.30."
|
||||
) +
|
||||
gsi::constructor ("expression_filter", &make_pe, gsi::arg ("expression"), gsi::arg ("inverse", false),
|
||||
"@brief Creates an expression-based filter\n"
|
||||
"@param expression The expression to evaluate.\n"
|
||||
"@param inverse If true, inverts the selection - i.e. all polygons without a property with the given name and value range are selected.\n"
|
||||
"\n"
|
||||
"Creates a filter that will evaluate the given expression on every shape and select the shape "
|
||||
"when the expression renders a boolean true value. "
|
||||
"The expression may use the following variables and functions:\n"
|
||||
"\n"
|
||||
"@ul\n"
|
||||
"@li @b shape @/b: The current shape @/li\n"
|
||||
"@li @b value(<name>) @/b: The value of the property with the given name (the first one if there are multiple properties with the same name) @/li\n"
|
||||
"@li @b values(<name>) @/b: All values of the properties with the given name (returns a list) @/li\n"
|
||||
"@li @b <name> @/b: A shortcut for 'value(<name>)' (<name> is used as a symbol) @/li\n"
|
||||
"@/ul\n"
|
||||
"\n"
|
||||
"This feature has been introduced in version 0.30.3."
|
||||
),
|
||||
"@hide"
|
||||
);
|
||||
|
|
@ -248,6 +272,41 @@ Class<shape_processor_impl<db::PolygonProcessorBase> > decl_PolygonOperator ("db
|
|||
"This class has been introduced in version 0.29.\n"
|
||||
);
|
||||
|
||||
static
|
||||
property_computation_processor<db::PolygonProcessorBase, db::Region> *
|
||||
new_pcp (const db::Region *container, const std::map<tl::Variant, std::string> &expressions, bool copy_properties)
|
||||
{
|
||||
return new property_computation_processor<db::PolygonProcessorBase, db::Region> (container, expressions, copy_properties);
|
||||
}
|
||||
|
||||
Class<property_computation_processor<db::PolygonProcessorBase, db::Region> > decl_PolygonPropertiesExpressions ("db", "PolygonPropertiesExpressions",
|
||||
property_computation_processor<db::PolygonProcessorBase, db::Region>::method_decls (true) +
|
||||
gsi::constructor ("new", &new_pcp, gsi::arg ("region"), gsi::arg ("expressions"), gsi::arg ("copy_properties", false),
|
||||
"@brief Creates a new properties expressions operator\n"
|
||||
"\n"
|
||||
"@param region The region, the processor will be used on. Can be nil, but if given, allows some optimization.\n"
|
||||
"@param expressions A map of property names and expressions used to generate the values of the properties (see class description for details).\n"
|
||||
"@param copy_properties If true, new properties will be added to existing ones.\n"
|
||||
),
|
||||
"@brief An operator attaching computed properties to the polygons\n"
|
||||
"\n"
|
||||
"This operator will execute a number of expressions and attach the results as new properties. "
|
||||
"The expression inputs can be taken either from the polygons themselves or from existing properties.\n"
|
||||
"\n"
|
||||
"A number of expressions can be supplied with a name. The expressions will be evaluated and the result "
|
||||
"is attached to the output polygons as user properties with the given names.\n"
|
||||
"The expression may use the following variables and functions:\n"
|
||||
"\n"
|
||||
"@ul\n"
|
||||
"@li @b shape @/b: The current shape @/li\n"
|
||||
"@li @b value(<name>) @/b: The value of the property with the given name (the first one if there are multiple properties with the same name) @/li\n"
|
||||
"@li @b values(<name>) @/b: All values of the properties with the given name (returns a list) @/li\n"
|
||||
"@li @b <name> @/b: A shortcut for 'value(<name>)' (<name> is used as a symbol) @/li\n"
|
||||
"@/ul\n"
|
||||
"\n"
|
||||
"This class has been introduced in version 0.30.3.\n"
|
||||
);
|
||||
|
||||
Class<shape_processor_impl<db::PolygonToEdgeProcessorBase> > decl_PolygonToEdgeProcessor ("db", "PolygonToEdgeOperator",
|
||||
shape_processor_impl<db::PolygonToEdgeProcessorBase>::method_decls (true),
|
||||
"@brief A generic polygon-to-edge operator\n"
|
||||
|
|
|
|||
|
|
@ -579,6 +579,21 @@ public:
|
|||
return mp_parent;
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Resolves a name into a function, a constant value or a variable
|
||||
*
|
||||
* Can be overloaded to change the resolution scheme
|
||||
*/
|
||||
virtual void resolve_name (const std::string &name, const EvalFunction *&function, const tl::Variant *&value, tl::Variant *&var);
|
||||
|
||||
/**
|
||||
* @brief Resolves a name into a variable
|
||||
*
|
||||
* Can be overloaded to change the resolution scheme
|
||||
*/
|
||||
virtual void resolve_var_name (const std::string &name, tl::Variant *&value);
|
||||
|
||||
private:
|
||||
friend class Expression;
|
||||
|
||||
|
|
@ -601,8 +616,6 @@ private:
|
|||
void eval_unary (ExpressionParserContext &context, std::unique_ptr<ExpressionNode> &v);
|
||||
void eval_atomic (ExpressionParserContext &context, std::unique_ptr<ExpressionNode> &v, int am);
|
||||
void eval_suffix (ExpressionParserContext &context, std::unique_ptr<ExpressionNode> &v);
|
||||
void resolve_name (const std::string &name, const EvalFunction *&function, const tl::Variant *&value, tl::Variant *&var);
|
||||
void resolve_var_name (const std::string &name, tl::Variant *&value);
|
||||
|
||||
static Eval m_global;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue