From 37eeb870ccc1762152d7550534265baf6cf2b19f Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Wed, 27 Feb 2008 18:50:59 +0000 Subject: [PATCH] Add support for boolean values in filters, and reading of boolean values from PostGIS data sources. --- include/mapnik/boolean_filter.hpp | 77 +++++++++++++++++++++++++++++ include/mapnik/expression.hpp | 3 ++ include/mapnik/filter_parser.hpp | 65 +++++++++++++++++++++--- include/mapnik/value.hpp | 25 +++++++++- plugins/input/postgis/postgisfs.cpp | 6 ++- 5 files changed, 167 insertions(+), 9 deletions(-) create mode 100644 include/mapnik/boolean_filter.hpp diff --git a/include/mapnik/boolean_filter.hpp b/include/mapnik/boolean_filter.hpp new file mode 100644 index 0000000000..244f77a915 --- /dev/null +++ b/include/mapnik/boolean_filter.hpp @@ -0,0 +1,77 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2008 Tom Hughes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + + +//$Id$ + +#ifndef BOOLEAN_FILTER_HPP +#define BOOLEAN_FILTER_HPP +// mapnik +#include +#include + +namespace mapnik +{ + template + struct boolean_filter : public filter + { + + boolean_filter(expression const& exp) + : filter(), + exp_(exp.clone()) {} + + boolean_filter(boolean_filter const& other) + : filter(), + exp_(other.exp_->clone()) {} + + bool pass(FeatureT const& feature) const + { + return exp_->get_value(feature).to_bool(); + } + + void accept(filter_visitor& v) + { + exp_->accept(v); + v.visit(*this); + } + + filter* clone() const + { + return new boolean_filter(*this); + } + std::string to_string() const + { + return exp_->to_string(); + } + ~boolean_filter() + { + delete exp_; + } + + private: + expression* exp_; + + }; +} + + +#endif //BOOLEAN_FILTER_HPP diff --git a/include/mapnik/expression.hpp b/include/mapnik/expression.hpp index 05f8306039..d440685715 100644 --- a/include/mapnik/expression.hpp +++ b/include/mapnik/expression.hpp @@ -45,6 +45,9 @@ namespace mapnik { class literal : public expression { public: + literal(bool val) + : expression(), + value_(val) {} literal(int val) : expression(), value_(val) {} diff --git a/include/mapnik/filter_parser.hpp b/include/mapnik/filter_parser.hpp index d3cc2d6349..f719372d6b 100644 --- a/include/mapnik/filter_parser.hpp +++ b/include/mapnik/filter_parser.hpp @@ -33,6 +33,7 @@ #include #include #include +#include #include // boost @@ -60,6 +61,24 @@ namespace mapnik using std::clog; using std::stack; + template + struct push_boolean + { + push_boolean(stack > >& exprs) + : exprs_(exprs) {} + + void operator() (std::string const& val) const + { + if (val == "true") + exprs_.push(shared_ptr > + ( new literal(true))); + else if (val == "false") + exprs_.push(shared_ptr > + ( new literal(false))); + } + stack > >& exprs_; + }; + template struct push_integer { @@ -203,7 +222,31 @@ namespace mapnik stack > >& filters_; stack > >& exprs_; }; - + + template + struct compose_boolean_filter + { + compose_boolean_filter(stack > >& filters, + stack > >& exprs) + : filters_(filters),exprs_(exprs) {} + + template + void operator() (Iter,Iter) const + { + if (exprs_.size()>=1) + { + shared_ptr > exp = exprs_.top(); + exprs_.pop(); + if (exp) + { + filters_.push(shared_ptr >(new boolean_filter(*exp))); + } + } + } + stack > >& filters_; + stack > >& exprs_; + }; + template struct compose_and_filter { @@ -297,7 +340,8 @@ namespace mapnik func2_op = "min","max"; spatial_op = "Equals","Disjoint","Touches","Within","Overlaps", "Crosses","Intersects","Contains","DWithin","Beyond","BBOX"; - + boolean_const = "true","false"; + chset_t BaseChar (L"\x41-\x5A\x61-\x7A\xC0-\xD6\xD8-\xF6\xF8-\xFF\x100-\x131\x134-\x13E" L"\x141-\x148\x14A-\x17E\x180-\x1C3\x1CD-\x1F0\x1F4-\x1F5\x1FA-\x217" L"\x250-\x2A8\x2BB-\x2C1\x386\x388-\x38A\x38C\x38E-\x3A1\x3A3-\x3CE" @@ -368,18 +412,20 @@ namespace mapnik | L':' | CombiningChar | Extender; - + + boolean = boolean_const [push_boolean(self.exprs)]; + number = strict_real_p [push_real(self.exprs)] | int_p [push_integer(self.exprs)]; string_ = confix_p(L'\'',(*lex_escape_ch_p) [push_string(self.exprs,self.tr)], L'\''); - + property = L'[' >> ( (Letter | L'_' | L':') >> *NameChar )[push_property(self.exprs)] >> L']'; - literal = number | string_ | property; + literal = boolean | number | string_ | property; function = literal | ( func1_op >> L'('>> literal >> L')') | (func2_op >> L'(' >> literal >> L','>> literal >> L')'); @@ -415,7 +461,9 @@ namespace mapnik | ( L"<>" >> relation) [compose_filter >(self.filters,self.exprs)]); - not_expr = equation | *(str_p(L"not") >> equation)[compose_not_filter(self.filters)]; + cond_expr = equation | (expression)[compose_boolean_filter(self.filters,self.exprs)]; + + not_expr = cond_expr | *(str_p(L"not") >> cond_expr)[compose_not_filter(self.filters)]; and_expr = not_expr >> *(L"and" >> not_expr)[compose_and_filter(self.filters)]; @@ -429,12 +477,14 @@ namespace mapnik BOOST_SPIRIT_DEBUG_RULE( expression ); BOOST_SPIRIT_DEBUG_RULE( relation ); BOOST_SPIRIT_DEBUG_RULE( equation ); + BOOST_SPIRIT_DEBUG_RULE( cond_expr ); BOOST_SPIRIT_DEBUG_RULE( not_expr ); BOOST_SPIRIT_DEBUG_RULE( and_expr ); BOOST_SPIRIT_DEBUG_RULE( or_expr ); BOOST_SPIRIT_DEBUG_RULE( filter_statement ); BOOST_SPIRIT_DEBUG_RULE( literal ); + BOOST_SPIRIT_DEBUG_RULE( boolean ); BOOST_SPIRIT_DEBUG_RULE( number ); BOOST_SPIRIT_DEBUG_RULE( string_ ); BOOST_SPIRIT_DEBUG_RULE( property ); @@ -453,12 +503,14 @@ namespace mapnik boost::spirit::rule expression; boost::spirit::rule relation; boost::spirit::rule equation; + boost::spirit::rule cond_expr; boost::spirit::rule not_expr; boost::spirit::rule and_expr; boost::spirit::rule or_expr; boost::spirit::rule filter_statement; boost::spirit::rule literal; + boost::spirit::rule boolean; boost::spirit::rule number; boost::spirit::rule string_; boost::spirit::rule property; @@ -467,6 +519,7 @@ namespace mapnik symbols func1_op; symbols func2_op; symbols spatial_op; + symbols boolean_const; }; diff --git a/include/mapnik/value.hpp b/include/mapnik/value.hpp index b4939a94d8..344645b84a 100644 --- a/include/mapnik/value.hpp +++ b/include/mapnik/value.hpp @@ -26,6 +26,7 @@ // mapnik #include +#include // boost #include // stl @@ -38,7 +39,7 @@ namespace mapnik { - typedef boost::variant value_base; + typedef boost::variant value_base; namespace impl { struct equals @@ -328,7 +329,22 @@ namespace mapnik { return lhs / rhs; } }; - + + struct to_bool : public boost::static_visitor + { + + template + bool operator() (T val) const + { + throw config_error("Boolean value expected"); + } + + bool operator() (bool val) const + { + return val; + } + }; + struct to_string : public boost::static_visitor { @@ -492,6 +508,11 @@ namespace mapnik { return base_; } + bool to_bool() const + { + return boost::apply_visitor(impl::to_bool(),base_); + } + std::string to_expression_string() const { return boost::apply_visitor(impl::to_expression_string(),base_); diff --git a/plugins/input/postgis/postgisfs.cpp b/plugins/input/postgis/postgisfs.cpp index f7eaff40c4..13da227820 100644 --- a/plugins/input/postgis/postgisfs.cpp +++ b/plugins/input/postgis/postgisfs.cpp @@ -111,7 +111,11 @@ feature_ptr postgis_featureset::next() const char* buf=rs_->getValue(pos); int oid = rs_->getTypeOID(pos); - if (oid==23) //int4 + if (oid==16) //bool + { + boost::put(*feature,name,buf[0] != 0); + } + else if (oid==23) //int4 { int val = int4net(buf); boost::put(*feature,name,val);