mirror of https://github.com/KLayout/klayout.git
WIP
This commit is contained in:
parent
1c1555f31c
commit
427ac0ae16
|
|
@ -26,20 +26,531 @@
|
|||
#include "dbEdgePairs.h"
|
||||
#include "dbTexts.h"
|
||||
#include "tlExpression.h"
|
||||
#include "gsiClassBase.h"
|
||||
#include "gsiDeclDbContainerHelpers.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// Some utilities
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
template <class Container>
|
||||
void compute_as_properties (Container *container, const std::map<tl::Variant, std::string> &expressions, bool clear_properties)
|
||||
/**
|
||||
* @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>
|
||||
struct measure_methods
|
||||
{
|
||||
/**
|
||||
* @brief Computes one or many properties from expressions
|
||||
*
|
||||
* This method will use the shapes from the "input" container and compute properties from them using the
|
||||
* given expression from "expressions". This map specifies the name of the target property, the value
|
||||
* specifies the expression to execute.
|
||||
*
|
||||
* The expressions can make use of the following variables and functions:
|
||||
* * "shape": the shape which is currently seen
|
||||
* * "<prop-name>": an existing property from the shape currently seen (or nil, if no such property is present).
|
||||
* This is a shortcut, only for properties with string names that are compatible with variable names
|
||||
* * "value(<name>)": the value of the property with the given name - if multiple properties with that
|
||||
* name are present, one value is returned
|
||||
* * "values(<name>)": a list of values for all properties with the given name
|
||||
*
|
||||
* Returns the new container with the computed properties attached.
|
||||
*/
|
||||
Container computed_properties (Container *input, const std::map<tl::Variant, std::string> &expressions, bool clear_properties);
|
||||
|
||||
/**
|
||||
* @brief Computes one or many properties from expressions
|
||||
*
|
||||
* Like "computed_properties", this method computes properties, but attaches them to the existing shapes.
|
||||
* As a side effect, the shapes may be merged if "merged_semantics" applies. If "clear_properties" is true,
|
||||
* any existing properties will be removed. If not, the new properties are added to the existing ones.
|
||||
*/
|
||||
void compute_properties_in_place (Container *container, const std::map<tl::Variant, std::string> &expressions, bool clear_properties);
|
||||
|
||||
/**
|
||||
* @brief Selects all shapes for which the condition expression renders true (or the inverse)
|
||||
*
|
||||
* The condition expression can use the features as described for "computed_properties".
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* @brief In-place version of "selected_if"
|
||||
*/
|
||||
void select_if (const 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);
|
||||
};
|
||||
|
||||
template <class Container, class ProcessorBase>
|
||||
Container
|
||||
measure_methods<Container, ProcessorBase>::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>
|
||||
void
|
||||
measure_methods<Container, ProcessorBase>::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>
|
||||
Container
|
||||
measure_methods<Container, ProcessorBase>::selected_if (const Container &container, const std::string &condition_expression, bool inverse)
|
||||
{
|
||||
// - collect property names
|
||||
// - define functions for
|
||||
|
||||
// - define tl::Eval functions for property names (properties_id -> value)
|
||||
// - define tl::Eval function for shape
|
||||
// - compile expression
|
||||
// - launch filter (Region::filtered)
|
||||
}
|
||||
|
||||
template <class Container, class ProcessorBase>
|
||||
void
|
||||
measure_methods<Container, ProcessorBase>::select_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)
|
||||
}
|
||||
|
||||
template <class Container, class ProcessorBase>
|
||||
std::pair<Container, Container>
|
||||
measure_methods<Container, ProcessorBase>::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)
|
||||
}
|
||||
|
||||
// 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> >;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -237,15 +237,22 @@ private:
|
|||
// ---------------------------------------------------------------------------------
|
||||
// Generic shape processor declarations
|
||||
|
||||
/**
|
||||
* @brief A "declarative" base for shape processors
|
||||
*
|
||||
* This implementation provides configuration options to tailor the behavior
|
||||
* of the processor base - specifically with respect to variants and various
|
||||
* attributes.
|
||||
*/
|
||||
template <class ProcessorBase>
|
||||
class shape_processor_impl
|
||||
class shape_processor_base
|
||||
: public ProcessorBase
|
||||
{
|
||||
public:
|
||||
typedef typename ProcessorBase::shape_type shape_type;
|
||||
typedef typename ProcessorBase::result_type result_type;
|
||||
typedef typename ProcessorBase::shape_type shape_type;
|
||||
typedef typename ProcessorBase::result_type result_type;
|
||||
|
||||
shape_processor_impl ()
|
||||
shape_processor_base ()
|
||||
{
|
||||
mp_vars = &m_mag_and_orient;
|
||||
m_wants_variants = true;
|
||||
|
|
@ -319,79 +326,17 @@ public:
|
|||
mp_vars = 0;
|
||||
}
|
||||
|
||||
virtual void process (const shape_type &shape, std::vector<result_type> &res) const
|
||||
{
|
||||
res = do_process (shape);
|
||||
}
|
||||
|
||||
virtual void process (const db::object_with_properties<shape_type> &shape, std::vector<db::object_with_properties<result_type> > &res) const
|
||||
{
|
||||
res = do_process (shape);
|
||||
}
|
||||
|
||||
std::vector<result_type> issue_do_process (const shape_type &) const
|
||||
{
|
||||
return std::vector<result_type> ();
|
||||
}
|
||||
|
||||
std::vector<db::object_with_properties<result_type> > issue_do_process_wp (const db::object_with_properties<shape_type> &) const
|
||||
{
|
||||
return std::vector<db::object_with_properties<result_type> > ();
|
||||
}
|
||||
|
||||
std::vector<result_type> do_process (const shape_type &shape) const
|
||||
{
|
||||
if (f_process.can_issue ()) {
|
||||
return f_process.issue<shape_processor_impl, std::vector<result_type>, const shape_type &> (&shape_processor_impl::issue_do_process, shape);
|
||||
} else {
|
||||
return issue_do_process (shape);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<db::object_with_properties<result_type> > do_process (const db::object_with_properties<shape_type> &shape) const
|
||||
{
|
||||
if (f_process_wp.can_issue ()) {
|
||||
return f_process.issue<shape_processor_impl, std::vector<db::object_with_properties<result_type> >, const db::object_with_properties<shape_type> &> (&shape_processor_impl::issue_do_process_wp, shape);
|
||||
} else if (f_process.can_issue ()) {
|
||||
auto tmp_result = f_process.issue<shape_processor_impl, std::vector<result_type>, const shape_type &> (&shape_processor_impl::issue_do_process, shape);
|
||||
std::vector<db::object_with_properties<result_type> > result;
|
||||
for (auto i = tmp_result.begin (); i != tmp_result.end (); ++i) {
|
||||
result.push_back (db::object_with_properties<result_type> (*i, shape.properties_id ()));
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
return issue_do_process_wp (shape);
|
||||
}
|
||||
}
|
||||
|
||||
gsi::Callback f_process;
|
||||
gsi::Callback f_process_wp;
|
||||
|
||||
static gsi::Methods method_decls (bool with_merged_options)
|
||||
{
|
||||
gsi::Methods decls =
|
||||
callback ("process", &shape_processor_impl::issue_do_process, &shape_processor_impl::f_process, gsi::arg ("shape"),
|
||||
"@brief Processes a shape\n"
|
||||
"This method is the actual payload. It needs to be reimplemented in a derived class.\n"
|
||||
"If needs to process the input shape and deliver a list of output shapes.\n"
|
||||
"The output list may be empty to entirely discard the input shape. It may also contain more than a single shape.\n"
|
||||
"In that case, the number of total shapes may grow during application of the processor.\n"
|
||||
) +
|
||||
callback ("process_with_properties", &shape_processor_impl::issue_do_process_wp, &shape_processor_impl::f_process_wp, gsi::arg ("shape"),
|
||||
"@brief Processes a shape with properties\n"
|
||||
"In scenarios with shapes with properties, this method is called to process the shapes. If the method is not implemented, "
|
||||
"the property-less 'process' method is called and the properties are copied from the input to the output.\n"
|
||||
"\n"
|
||||
"This flavor has been introduced in version 0.30."
|
||||
);
|
||||
gsi::Methods decls;
|
||||
|
||||
if (with_merged_options) {
|
||||
decls +=
|
||||
method ("requires_raw_input?", &shape_processor_impl::requires_raw_input,
|
||||
method ("requires_raw_input?", &shape_processor_base::requires_raw_input,
|
||||
"@brief Gets a value indicating whether the processor needs raw (unmerged) input\n"
|
||||
"See \\requires_raw_input= for details.\n"
|
||||
) +
|
||||
method ("requires_raw_input=", &shape_processor_impl::set_requires_raw_input, gsi::arg ("flag"),
|
||||
method ("requires_raw_input=", &shape_processor_base::set_requires_raw_input, gsi::arg ("flag"),
|
||||
"@brief Sets a value indicating whether the processor needs raw (unmerged) input\n"
|
||||
"This flag must be set before using this processor. It tells the processor implementation whether the "
|
||||
"processor wants to have raw input (unmerged). The default value is 'false', meaning that\n"
|
||||
|
|
@ -401,22 +346,22 @@ public:
|
|||
"Also, raw input means that strange shapes such as dot-like edges, self-overlapping polygons, "
|
||||
"empty or degenerated polygons are preserved."
|
||||
) +
|
||||
method ("result_is_merged?", &shape_processor_impl::result_is_merged,
|
||||
method ("result_is_merged?", &shape_processor_base::result_is_merged,
|
||||
"@brief Gets a value indicating whether the processor delivers merged output\n"
|
||||
"See \\result_is_merged= for details.\n"
|
||||
) +
|
||||
method ("result_is_merged=", &shape_processor_impl::set_result_is_merged, gsi::arg ("flag"),
|
||||
method ("result_is_merged=", &shape_processor_base::set_result_is_merged, gsi::arg ("flag"),
|
||||
"@brief Sets a value indicating whether the processor delivers merged output\n"
|
||||
"This flag must be set before using this processor. If the processor maintains the merged condition\n"
|
||||
"by design (output is merged if input is), it is a good idea to set this predicate to 'true'.\n"
|
||||
"This will avoid additional merge steps when the resulting collection is used in further operations\n"
|
||||
"that need merged input\n."
|
||||
) +
|
||||
method ("result_must_not_be_merged?", &shape_processor_impl::result_must_not_be_merged,
|
||||
method ("result_must_not_be_merged?", &shape_processor_base::result_must_not_be_merged,
|
||||
"@brief Gets a value indicating whether the processor's output must not be merged\n"
|
||||
"See \\result_must_not_be_merged= for details.\n"
|
||||
) +
|
||||
method ("result_must_not_be_merged=", &shape_processor_impl::set_result_must_not_be_merged, gsi::arg ("flag"),
|
||||
method ("result_must_not_be_merged=", &shape_processor_base::set_result_must_not_be_merged, gsi::arg ("flag"),
|
||||
"@brief Sets a value indicating whether the processor's output must not be merged\n"
|
||||
"This flag must be set before using this processor. The processor can set this flag if it wants to\n"
|
||||
"deliver shapes that must not be merged - e.g. point-like edges or strange or degenerated polygons.\n."
|
||||
|
|
@ -424,11 +369,11 @@ public:
|
|||
}
|
||||
|
||||
decls +=
|
||||
method ("wants_variants?", &shape_processor_impl::wants_variants,
|
||||
method ("wants_variants?", &shape_processor_base::wants_variants,
|
||||
"@brief Gets a value indicating whether the filter prefers cell variants\n"
|
||||
"See \\wants_variants= for details.\n"
|
||||
) +
|
||||
method ("wants_variants=", &shape_processor_impl::set_wants_variants, gsi::arg ("flag"),
|
||||
method ("wants_variants=", &shape_processor_base::set_wants_variants, gsi::arg ("flag"),
|
||||
"@brief Sets a value indicating whether the filter prefers cell variants\n"
|
||||
"This flag must be set before using this filter for hierarchical applications (deep mode). "
|
||||
"It tells the filter implementation whether cell variants should be created (true, the default) "
|
||||
|
|
@ -440,7 +385,7 @@ public:
|
|||
"need to be differentiated. Cell variant formation is one way, shape propagation the other way.\n"
|
||||
"Typically, cell variant formation is less expensive, but the hierarchy will be modified."
|
||||
) +
|
||||
method ("is_isotropic", &shape_processor_impl::is_isotropic,
|
||||
method ("is_isotropic", &shape_processor_base::is_isotropic,
|
||||
"@brief Indicates that the filter has isotropic properties\n"
|
||||
"Call this method before using the filter to indicate that the selection is independent of "
|
||||
"the orientation of the shape. This helps the filter algorithm optimizing the filter run, specifically in "
|
||||
|
|
@ -449,7 +394,7 @@ public:
|
|||
"Examples for isotropic (polygon) processors are size or shrink operators. Size or shrink is not dependent "
|
||||
"on orientation unless size or shrink needs to be different in x and y direction."
|
||||
) +
|
||||
method ("is_scale_invariant", &shape_processor_impl::is_scale_invariant,
|
||||
method ("is_scale_invariant", &shape_processor_base::is_scale_invariant,
|
||||
"@brief Indicates that the filter is scale invariant\n"
|
||||
"Call this method before using the filter to indicate that the selection is independent of "
|
||||
"the scale of the shape. This helps the filter algorithm optimizing the filter run, specifically in "
|
||||
|
|
@ -458,7 +403,7 @@ public:
|
|||
"An example for a scale invariant (polygon) processor is the rotation operator. Rotation is not depending on scale, "
|
||||
"but on the original orientation as mirrored versions need to be rotated differently."
|
||||
) +
|
||||
method ("is_isotropic_and_scale_invariant", &shape_processor_impl::is_isotropic_and_scale_invariant,
|
||||
method ("is_isotropic_and_scale_invariant", &shape_processor_base::is_isotropic_and_scale_invariant,
|
||||
"@brief Indicates that the filter is isotropic and scale invariant\n"
|
||||
"Call this method before using the filter to indicate that the selection is independent of "
|
||||
"the scale and orientation of the shape. This helps the filter algorithm optimizing the filter run, specifically in "
|
||||
|
|
@ -481,6 +426,71 @@ private:
|
|||
bool m_result_is_merged;
|
||||
bool m_result_must_not_be_merged;
|
||||
|
||||
// No copying
|
||||
shape_processor_base &operator= (const shape_processor_base &);
|
||||
shape_processor_base (const shape_processor_base &);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The implementation class for the generic shape processor
|
||||
*
|
||||
* In addition to the services provided by "shape_processor_base",
|
||||
* this class provides an overload slot for the "process" virtual method.
|
||||
*/
|
||||
template <class ProcessorBase>
|
||||
class shape_processor_impl
|
||||
: public shape_processor_base<ProcessorBase>
|
||||
{
|
||||
public:
|
||||
typedef typename ProcessorBase::shape_type shape_type;
|
||||
typedef typename ProcessorBase::result_type result_type;
|
||||
|
||||
shape_processor_impl ()
|
||||
: shape_processor_base<ProcessorBase> ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual void process (const db::object_with_properties<shape_type> &shape, std::vector<db::object_with_properties<result_type> > &res) const
|
||||
{
|
||||
res = do_process (shape);
|
||||
}
|
||||
|
||||
std::vector<db::object_with_properties<result_type> > issue_do_process (const db::object_with_properties<shape_type> &) const
|
||||
{
|
||||
return std::vector<db::object_with_properties<result_type> > ();
|
||||
}
|
||||
|
||||
std::vector<db::object_with_properties<result_type> > do_process (const db::object_with_properties<shape_type> &shape) const
|
||||
{
|
||||
if (f_process.can_issue ()) {
|
||||
return f_process.issue<shape_processor_impl, std::vector<db::object_with_properties<result_type> >, const db::object_with_properties<shape_type> &> (&shape_processor_impl::issue_do_process, shape);
|
||||
} else {
|
||||
return issue_do_process (shape);
|
||||
}
|
||||
}
|
||||
|
||||
gsi::Callback f_process;
|
||||
|
||||
static gsi::Methods method_decls (bool with_merged_options)
|
||||
{
|
||||
gsi::Methods decls =
|
||||
callback ("process", &shape_processor_impl::issue_do_process, &shape_processor_impl::f_process, gsi::arg ("shape"),
|
||||
"@brief Processes a shape\n"
|
||||
"This method is the actual payload. It needs to be reimplemented in a derived class.\n"
|
||||
"If needs to process the input shape and deliver a list of output shapes.\n"
|
||||
"The output list may be empty to entirely discard the input shape. It may also contain more than a single shape.\n"
|
||||
"In that case, the number of total shapes may grow during application of the processor.\n"
|
||||
"\n"
|
||||
"Since version 0.30.3, this method will always receive objects with properties and is also able to deliver them - "
|
||||
"hence modify the properties.\n"
|
||||
"'process_with_properties' is no longer supported."
|
||||
);
|
||||
|
||||
return decls + shape_processor_base<ProcessorBase>::method_decls (with_merged_options);
|
||||
}
|
||||
|
||||
private:
|
||||
// No copying
|
||||
shape_processor_impl &operator= (const shape_processor_impl &);
|
||||
shape_processor_impl (const shape_processor_impl &);
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ public:
|
|||
create_item_from_shape (mp_rdb, m_cell_stack.back ()->id (), mp_cat->id (), m_trans, shape, m_with_properties);
|
||||
}
|
||||
|
||||
public:
|
||||
private:
|
||||
rdb::Category *mp_cat;
|
||||
rdb::Database *mp_rdb;
|
||||
std::vector<const rdb::Cell *> m_cell_stack;
|
||||
|
|
|
|||
Loading…
Reference in New Issue