diff --git a/src/db/db/db.pro b/src/db/db/db.pro index f4cb732bc..bde28f9b3 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -58,7 +58,6 @@ SOURCES = \ dbLog.cc \ dbManager.cc \ dbMatrix.cc \ - dbMeasure.cc \ dbMemStatistics.cc \ dbMutableEdgePairs.cc \ dbMutableEdges.cc \ @@ -140,6 +139,7 @@ SOURCES = \ gsiDeclDbLog.cc \ gsiDeclDbManager.cc \ gsiDeclDbMatrix.cc \ + gsiDeclDbMeasureHelpers.cc \ gsiDeclDbMetaInfo.cc \ gsiDeclDbPath.cc \ gsiDeclDbPoint.cc \ @@ -296,7 +296,6 @@ HEADERS = \ dbLog.h \ dbManager.h \ dbMatrix.h \ - dbMeasure.h \ dbMemStatistics.h \ dbMetaInfo.h \ dbMutableEdgePairs.h \ diff --git a/src/db/db/gsiDeclDbContainerHelpers.h b/src/db/db/gsiDeclDbContainerHelpers.h index e347f4f38..e6d9f3c24 100644 --- a/src/db/db/gsiDeclDbContainerHelpers.h +++ b/src/db/db/gsiDeclDbContainerHelpers.h @@ -453,18 +453,23 @@ public: virtual void process (const db::object_with_properties &shape, std::vector > &res) const { - res = do_process (shape); + res = do_process_wp (shape); + + auto res_no_prop = do_process (shape.base ()); + for (auto i = res_no_prop.begin (); i != res_no_prop.end (); ++i) { + res.push_back (db::object_with_properties (*i, shape.properties_id ())); + } } - std::vector > issue_do_process (const db::object_with_properties &) const + std::vector issue_do_process (const shape_type &) const { - return std::vector > (); + return std::vector (); } - std::vector > do_process (const db::object_with_properties &shape) const + std::vector do_process (const shape_type &shape) const { if (f_process.can_issue ()) { - return f_process.issue >, const db::object_with_properties &> (&shape_processor_impl::issue_do_process, shape); + return f_process.issue, const shape_type &> (&shape_processor_impl::issue_do_process, shape); } else { return issue_do_process (shape); } @@ -472,6 +477,22 @@ public: gsi::Callback f_process; + std::vector > issue_do_process_wp (const db::object_with_properties &) const + { + return std::vector > (); + } + + std::vector > do_process_wp (const db::object_with_properties &shape) const + { + if (f_process_wp.can_issue ()) { + return f_process_wp.issue >, const db::object_with_properties &> (&shape_processor_impl::issue_do_process_wp, shape); + } else { + return issue_do_process_wp (shape); + } + } + + gsi::Callback f_process_wp; + static gsi::Methods method_decls (bool with_merged_options) { gsi::Methods decls = @@ -482,9 +503,15 @@ public: "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." + "Instead of implementing 'process', you can also implement \\process_with_properties. The latter function " + "allows modifying the properties of an object." + ) + + callback ("process_witp_properties", &shape_processor_impl::issue_do_process_wp, &shape_processor_impl::f_process_wp, gsi::arg ("shape"), + "@brief Processes a shape with properties\n" + "This method is called in addition to \\process. If reimplemented it allows producing objects " + "with different properties than the input one.\n" + "\n" + "Modification of properties is supported since version 0.30.3.\n" ); return decls + shape_processor_base::method_decls (with_merged_options); diff --git a/src/db/db/gsiDeclDbMeasureHelpers.cc b/src/db/db/gsiDeclDbMeasureHelpers.cc index c1e0a4b13..1d2133719 100644 --- a/src/db/db/gsiDeclDbMeasureHelpers.cc +++ b/src/db/db/gsiDeclDbMeasureHelpers.cc @@ -25,104 +25,234 @@ namespace gsi { -/** - * @brief Provides methods to handle measurement functions on various containers - */ -template -struct measure_methods +class ShapeFunction + : public tl::EvalFunction { - /** - * @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 - * * "": 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()": the value of the property with the given name - if multiple properties with that - * name are present, one value is returned - * * "values()": 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 &expressions, bool clear_properties); +public: + ShapeFunction (MeasureEval *eval) + : mp_eval (eval) + { + // .. nothing yet .. + } - /** - * @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 &expressions, bool clear_properties); + virtual void execute (const tl::ExpressionParserContext &context, tl::Variant &out, const std::vector &args, const std::map * /*kwargs*/) const + { + if (args.size () != 0) { + throw tl::EvalError (tl::to_string (tr ("'shape' function does not take arguments")), context); + } + out = mp_eval->shape_func (); + } - /** - * @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 (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 split_if (const Container *container, const std::string &condition_expression); +private: + MeasureEval *mp_eval; }; -template -Container -measure_methods::computed_properties (Container *container, const std::map &expressions, bool clear_properties) +class ValueFunction + : public tl::EvalFunction { - property_computation_processor proc (container, expressions, !clear_properties); - return container->processed (proc); +public: + ValueFunction (MeasureEval *eval) + : mp_eval (eval) + { + // .. nothing yet .. + } + + virtual void execute (const tl::ExpressionParserContext &context, tl::Variant &out, const std::vector &args, const std::map * /*kwargs*/) const + { + if (args.size () != 1) { + throw tl::EvalError (tl::to_string (tr ("'value' function takes one argument")), context); + } + out = mp_eval->value_func (args [0]); + } + +private: + MeasureEval *mp_eval; +}; + +class ValuesFunction + : public tl::EvalFunction +{ +public: + ValuesFunction (MeasureEval *eval) + : mp_eval (eval) + { + // .. nothing yet .. + } + + virtual void execute (const tl::ExpressionParserContext &context, tl::Variant &out, const std::vector &args, const std::map * /*kwargs*/) const + { + if (args.size () != 1) { + throw tl::EvalError (tl::to_string (tr ("'values' function takes one argument")), context); + } + out = mp_eval->values_func (args [0]); + } + +private: + MeasureEval *mp_eval; +}; + +class PropertyFunction + : public tl::EvalFunction +{ +public: + PropertyFunction (MeasureEval *eval, const tl::Variant &name) + : mp_eval (eval), m_name_id (db::property_names_id (name)) + { + // .. nothing yet .. + } + + virtual void execute (const tl::ExpressionParserContext &context, tl::Variant &out, const std::vector &args, const std::map * /*kwargs*/) const + { + if (args.size () != 0) { + throw tl::EvalError (tl::to_string (tr ("Property getter function does not take arguments")), context); + } + out = mp_eval->value_func (m_name_id); + } + +private: + MeasureEval *mp_eval; + db::property_names_id_type m_name_id; +}; + +// -------------------------------------------------------------------- +// MeasureEval implementation + +MeasureEval::MeasureEval () + : m_shape_type (None), m_prop_id (0) +{ + mp_shape.any = 0; } -template void -measure_methods::compute_properties_in_place (Container *container, const std::map &expressions, bool clear_properties) +MeasureEval::init () { - property_computation_processor proc (container, expressions, !clear_properties); - container->process (proc); + define_function ("shape", new ShapeFunction (this)); + define_function ("value", new ValueFunction (this)); + define_function ("values", new ValuesFunction (this)); } -template -Container -measure_methods::selected_if (const Container *container, const std::string &condition_expression, bool inverse) -{ - expression_filter filter (condition_expression, inverse); - return container->filtered (filter); -} - -template void -measure_methods::select_if (Container *container, const std::string &condition_expression, bool inverse) +MeasureEval::reset_shape () const { - expression_filter filter (condition_expression, inverse); - container->filter (filter); + m_shape_type = None; + mp_shape.any = 0; + m_prop_id = 0; } -template -std::pair -measure_methods::split_if (const Container *container, const std::string &condition_expression) +void +MeasureEval::set_shape (const db::Polygon *poly) const { - expression_filter filter (condition_expression, false); - return container->split_filter (filter); + m_shape_type = Polygon; + mp_shape.poly = poly; } -// explicit instantiations -template struct measure_methods, db::AllMustMatchFilter>; -template struct measure_methods, db::AllEdgesMustMatchFilter>; -template struct measure_methods, db::EdgePairFilterBase>; -template struct measure_methods, db::TextFilterBase>; +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 +{ + 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 +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; +} } diff --git a/src/db/db/gsiDeclDbMeasureHelpers.h b/src/db/db/gsiDeclDbMeasureHelpers.h index af300f0de..b28e0b5b2 100644 --- a/src/db/db/gsiDeclDbMeasureHelpers.h +++ b/src/db/db/gsiDeclDbMeasureHelpers.h @@ -44,167 +44,30 @@ namespace gsi * * This class provides the methods, functions and variables for the expressions. */ -class MeasureEval +class DB_PUBLIC MeasureEval : public tl::Eval { public: - MeasureEval () - : m_shape_type (None), m_prop_id (0) - { - mp_shape.any = 0; - } + MeasureEval (); - void init () - { - define_function ("shape", new ShapesFunction (this)); - define_function ("value", new ValueFunction (this)); - define_function ("values", new ValuesFunction (this)); - } + void init (); - 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; - } + 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; 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; - } - } + virtual void resolve_name (const std::string &name, const tl::EvalFunction *&function, const tl::Variant *&value, tl::Variant *&var); 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 &args, const std::map * /*kwargs*/) const - { - if (args.size () != 0) { - throw tl::EvalError (tl::to_string (tr ("'shape' function does not take arguments")), context); - } - out = mp_eval->shape_func (); - } - - private: - MeasureEval *mp_eval; - }; - - class ValueFunction - : public tl::EvalFunction - { - public: - ValueFunction (MeasureEval *eval) - : mp_eval (eval) - { - // .. nothing yet .. - } - - virtual void execute (const tl::ExpressionParserContext &context, tl::Variant &out, const std::vector &args, const std::map * /*kwargs*/) const - { - if (args.size () != 1) { - throw tl::EvalError (tl::to_string (tr ("'value' function takes one argument")), context); - } - out = mp_eval->value_func (args [0]); - } - - private: - MeasureEval *mp_eval; - }; - - class ValuesFunction - : public tl::EvalFunction - { - public: - ValuesFunction (MeasureEval *eval) - : mp_eval (eval) - { - // .. nothing yet .. - } - - virtual void execute (const tl::ExpressionParserContext &context, tl::Variant &out, const std::vector &args, const std::map * /*kwargs*/) const - { - if (args.size () != 1) { - throw tl::EvalError (tl::to_string (tr ("'values' function takes one argument")), context); - } - out = mp_eval->values_func (args [0]); - } - - private: - MeasureEval *mp_eval; - }; - - class PropertyFunction - : public tl::EvalFunction - { - public: - PropertyFunction (MeasureEval *eval, const tl::Variant &name) - : mp_eval (eval), m_name (name) - { - // .. nothing yet .. - } - - virtual void execute (const tl::ExpressionParserContext &context, tl::Variant &out, const std::vector &args, const std::map * /*kwargs*/) const - { - if (args.size () != 0) { - throw tl::EvalError (tl::to_string (tr ("Property getter function does not take arguments")), context); - } - out = mp_eval->value_func (m_name); - } - - private: - MeasureEval *mp_eval; - tl::Variant m_name; - }; + friend class ShapeFunction; + friend class ValueFunction; + friend class ValuesFunction; + friend class PropertyFunction; union ShapeRef { @@ -230,51 +93,10 @@ private: 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; - } + 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; }; inline db::RecursiveShapeIterator @@ -341,7 +163,7 @@ public: typedef typename ProcessorBase::result_type result_type; property_computation_processor (const Container *container, const std::map &expressions, bool copy_properties) - : m_eval (), m_copy_properties (copy_properties) + : m_eval (), m_copy_properties (copy_properties), m_expression_strings (expressions) { if (container) { this->set_result_is_merged (is_merged (container)); @@ -350,7 +172,7 @@ public: m_eval.init (); // compile the expressions - for (auto e = expressions.begin (); e != expressions.end (); ++e) { + for (auto e = m_expression_strings.begin (); e != m_expression_strings.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); @@ -367,6 +189,9 @@ public: 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.erase (e->first); + } } for (auto e = m_expressions.begin (); e != m_expressions.end (); ++e) { @@ -380,6 +205,7 @@ public: MeasureEval m_eval; std::vector > m_expressions; bool m_copy_properties; + std::map m_expression_strings; }; /** @@ -397,12 +223,12 @@ public: typedef typename FilterBase::shape_type shape_type; expression_filter (const std::string &expression, bool inverse) - : m_eval (), m_inverse (inverse) + : m_eval (), m_inverse (inverse), m_expression_string (expression) { m_eval.init (); // compile the expression - tl::Extractor ex (expression.c_str ()); + tl::Extractor ex (m_expression_string.c_str ()); m_eval.parse (m_expression, ex); } @@ -429,6 +255,7 @@ public: MeasureEval m_eval; tl::Expression m_expression; bool m_inverse; + std::string m_expression_string; }; } diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index 102bfdcdb..bc5b3adbf 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -227,7 +227,9 @@ Class decl_PolygonFilterImpl (decl_PolygonFilterBase, "d // --------------------------------------------------------------------------------- // PolygonProcessor binding -Class > decl_PolygonOperator ("db", "PolygonOperator", +Class decl_PolygonProcessorBase ("db", "PolygonProcessorBase", "@hide"); + +Class > decl_PolygonOperator (decl_PolygonProcessorBase, "db", "PolygonOperator", shape_processor_impl::method_decls (true), "@brief A generic polygon operator\n" "\n" @@ -279,7 +281,7 @@ new_pcp (const db::Region *container, const std::map & return new property_computation_processor (container, expressions, copy_properties); } -Class > decl_PolygonPropertiesExpressions ("db", "PolygonPropertiesExpressions", +Class > decl_PolygonPropertiesExpressions (decl_PolygonProcessorBase, "db", "PolygonPropertiesExpressions", property_computation_processor::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" @@ -307,7 +309,9 @@ Class > dec "This class has been introduced in version 0.30.3.\n" ); -Class > decl_PolygonToEdgeProcessor ("db", "PolygonToEdgeOperator", +Class decl_PolygonToEdgeProcessorBase ("db", "PolygonToEdgeProcessorBase", "@hide"); + +Class > decl_PolygonToEdgeProcessor (decl_PolygonToEdgeProcessorBase, "db", "PolygonToEdgeOperator", shape_processor_impl::method_decls (true), "@brief A generic polygon-to-edge operator\n" "\n" @@ -331,7 +335,9 @@ Class > decl_PolygonToEdgeP "This class has been introduced in version 0.29.\n" ); -Class > decl_PolygonToEdgePairProcessor ("db", "PolygonToEdgePairOperator", +Class decl_PolygonToEdgePairProcessorBase ("db", "PolygonToEdgePairProcessorBase", "@hide"); + +Class > decl_PolygonToEdgePairProcessor (decl_PolygonToEdgePairProcessorBase, "db", "PolygonToEdgePairOperator", shape_processor_impl::method_decls (true), "@brief A generic polygon-to-edge-pair operator\n" "\n" @@ -686,22 +692,22 @@ static std::vector split_filter (const db::Region *r, const PolygonF return as_2region_vector (r->split_filter (*f)); } -static db::Region processed_pp (const db::Region *r, const shape_processor_impl *f) +static db::Region processed_pp (const db::Region *r, const db::PolygonProcessorBase *f) { return r->processed (*f); } -static void process_pp (db::Region *r, const shape_processor_impl *f) +static void process_pp (db::Region *r, const db::PolygonProcessorBase *f) { r->process (*f); } -static db::EdgePairs processed_pep (const db::Region *r, const shape_processor_impl *f) +static db::EdgePairs processed_pep (const db::Region *r, const db::PolygonToEdgePairProcessorBase *f) { return r->processed (*f); } -static db::Edges processed_pe (const db::Region *r, const shape_processor_impl *f) +static db::Edges processed_pe (const db::Region *r, const db::PolygonToEdgeProcessorBase *f) { return r->processed (*f); }