Add support for boolean values in filters, and reading of boolean

values from PostGIS data sources.
This commit is contained in:
Tom Hughes 2008-02-27 18:50:59 +00:00
parent e1ea0a72db
commit 37eeb870cc
5 changed files with 167 additions and 9 deletions

View file

@ -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 <mapnik/filter.hpp>
#include <mapnik/expression.hpp>
namespace mapnik
{
template <typename FeatureT>
struct boolean_filter : public filter<FeatureT>
{
boolean_filter(expression<FeatureT> const& exp)
: filter<FeatureT>(),
exp_(exp.clone()) {}
boolean_filter(boolean_filter const& other)
: filter<FeatureT>(),
exp_(other.exp_->clone()) {}
bool pass(FeatureT const& feature) const
{
return exp_->get_value(feature).to_bool();
}
void accept(filter_visitor<FeatureT>& v)
{
exp_->accept(v);
v.visit(*this);
}
filter<FeatureT>* clone() const
{
return new boolean_filter(*this);
}
std::string to_string() const
{
return exp_->to_string();
}
~boolean_filter()
{
delete exp_;
}
private:
expression<FeatureT>* exp_;
};
}
#endif //BOOLEAN_FILTER_HPP

View file

@ -45,6 +45,9 @@ namespace mapnik {
class literal : public expression<FeatureT>
{
public:
literal(bool val)
: expression<FeatureT>(),
value_(val) {}
literal(int val)
: expression<FeatureT>(),
value_(val) {}

View file

@ -33,6 +33,7 @@
#include <mapnik/expression.hpp>
#include <mapnik/filter.hpp>
#include <mapnik/regex_filter.hpp>
#include <mapnik/boolean_filter.hpp>
#include <mapnik/logical.hpp>
// boost
@ -60,6 +61,24 @@ namespace mapnik
using std::clog;
using std::stack;
template <typename FeatureT>
struct push_boolean
{
push_boolean(stack<shared_ptr<expression<FeatureT> > >& exprs)
: exprs_(exprs) {}
void operator() (std::string const& val) const
{
if (val == "true")
exprs_.push(shared_ptr<expression<FeatureT> >
( new literal<FeatureT>(true)));
else if (val == "false")
exprs_.push(shared_ptr<expression<FeatureT> >
( new literal<FeatureT>(false)));
}
stack<shared_ptr<expression<FeatureT> > >& exprs_;
};
template <typename FeatureT>
struct push_integer
{
@ -203,7 +222,31 @@ namespace mapnik
stack<shared_ptr<filter<FeatureT> > >& filters_;
stack<shared_ptr<expression<FeatureT> > >& exprs_;
};
template <typename FeatureT>
struct compose_boolean_filter
{
compose_boolean_filter(stack<shared_ptr<filter<FeatureT> > >& filters,
stack<shared_ptr<expression<FeatureT> > >& exprs)
: filters_(filters),exprs_(exprs) {}
template <typename Iter>
void operator() (Iter,Iter) const
{
if (exprs_.size()>=1)
{
shared_ptr<expression<FeatureT> > exp = exprs_.top();
exprs_.pop();
if (exp)
{
filters_.push(shared_ptr<filter<FeatureT> >(new boolean_filter<FeatureT>(*exp)));
}
}
}
stack<shared_ptr<filter<FeatureT> > >& filters_;
stack<shared_ptr<expression<FeatureT> > >& exprs_;
};
template <typename FeatureT>
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<FeatureT>(self.exprs)];
number = strict_real_p [push_real<FeatureT>(self.exprs)]
| int_p [push_integer<FeatureT>(self.exprs)];
string_ = confix_p(L'\'',(*lex_escape_ch_p)
[push_string<FeatureT>(self.exprs,self.tr)],
L'\'');
property = L'[' >> ( (Letter | L'_' | L':')
>> *NameChar )[push_property<FeatureT>(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<FeatureT,not_equals<value> >(self.filters,self.exprs)]);
not_expr = equation | *(str_p(L"not") >> equation)[compose_not_filter<FeatureT>(self.filters)];
cond_expr = equation | (expression)[compose_boolean_filter<FeatureT>(self.filters,self.exprs)];
not_expr = cond_expr | *(str_p(L"not") >> cond_expr)[compose_not_filter<FeatureT>(self.filters)];
and_expr = not_expr >> *(L"and" >> not_expr)[compose_and_filter<FeatureT>(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<ScannerT> expression;
boost::spirit::rule<ScannerT> relation;
boost::spirit::rule<ScannerT> equation;
boost::spirit::rule<ScannerT> cond_expr;
boost::spirit::rule<ScannerT> not_expr;
boost::spirit::rule<ScannerT> and_expr;
boost::spirit::rule<ScannerT> or_expr;
boost::spirit::rule<ScannerT> filter_statement;
boost::spirit::rule<ScannerT> literal;
boost::spirit::rule<ScannerT> boolean;
boost::spirit::rule<ScannerT> number;
boost::spirit::rule<ScannerT> string_;
boost::spirit::rule<ScannerT> property;
@ -467,6 +519,7 @@ namespace mapnik
symbols<string> func1_op;
symbols<string> func2_op;
symbols<string> spatial_op;
symbols<string> boolean_const;
};

View file

@ -26,6 +26,7 @@
// mapnik
#include <mapnik/unicode.hpp>
#include <mapnik/config_error.hpp>
// boost
#include <boost/variant.hpp>
// stl
@ -38,7 +39,7 @@
namespace mapnik {
typedef boost::variant<int,double,UnicodeString> value_base;
typedef boost::variant<bool,int,double,UnicodeString> value_base;
namespace impl {
struct equals
@ -328,7 +329,22 @@ namespace mapnik {
return lhs / rhs;
}
};
struct to_bool : public boost::static_visitor<bool>
{
template <typename T>
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<std::string>
{
@ -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_);

View file

@ -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);