Add support for dynamic expressions for dasharrays - closes #2168
This commit is contained in:
parent
b7ecd00c31
commit
2a18280dc5
7 changed files with 93 additions and 41 deletions
|
@ -40,6 +40,8 @@
|
|||
#include <mapnik/attribute.hpp>
|
||||
#include <mapnik/gamma_method.hpp>
|
||||
#include <mapnik/symbolizer_enumerations.hpp>
|
||||
#include <mapnik/util/dasharray_parser.hpp>
|
||||
|
||||
// stl
|
||||
#include <type_traits>
|
||||
#include <algorithm>
|
||||
|
@ -365,6 +367,25 @@ struct evaluate_expression_wrapper<mapnik::enumeration_wrapper>
|
|||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct evaluate_expression_wrapper<mapnik::dash_array>
|
||||
{
|
||||
template <typename T1, typename T2, typename T3>
|
||||
mapnik::dash_array operator() (T1 const& expr, T2 const& feature, T3 const& vars) const
|
||||
{
|
||||
mapnik::value_type val = boost::apply_visitor(mapnik::evaluate<T2,mapnik::value_type,T3>(feature,vars), expr);
|
||||
// FIXME - throw?
|
||||
if (val.is_null()) return dash_array();
|
||||
dash_array dash;
|
||||
std::vector<double> buf;
|
||||
std::string str = val.to_string();
|
||||
if (util::parse_dasharray(str.begin(),str.end(),buf))
|
||||
{
|
||||
add_dashes(buf,dash);
|
||||
}
|
||||
return dash;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct extract_value : public boost::static_visitor<T>
|
||||
|
|
|
@ -392,6 +392,49 @@ struct set_symbolizer_property_impl<Symbolizer,transform_type,false>
|
|||
}
|
||||
};
|
||||
|
||||
template <typename Symbolizer>
|
||||
struct set_symbolizer_property_impl<Symbolizer,dash_array,false>
|
||||
{
|
||||
static void apply(Symbolizer & sym, keys key, xml_node const & node)
|
||||
{
|
||||
std::string const& name = std::get<0>(get_meta(key));
|
||||
boost::optional<std::string> str = node.get_opt_attr<std::string>(name);
|
||||
if (str)
|
||||
{
|
||||
std::vector<double> buf;
|
||||
dash_array dash;
|
||||
if (util::parse_dasharray((*str).begin(),(*str).end(),buf) && add_dashes(buf,dash))
|
||||
{
|
||||
put(sym,key,dash);
|
||||
}
|
||||
else
|
||||
{
|
||||
boost::optional<expression_ptr> val = node.get_opt_attr<expression_ptr>(name);
|
||||
if (val)
|
||||
{
|
||||
// first try pre-evaluate expressions which don't have dynamic properties
|
||||
auto result = pre_evaluate_expression<mapnik::value>(*val);
|
||||
if (std::get<1>(result))
|
||||
{
|
||||
set_property_from_value(sym, key,std::get<0>(result));
|
||||
}
|
||||
else
|
||||
{
|
||||
// expression_ptr
|
||||
put(sym, key, *val);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw config_error(std::string("Failed to parse dasharray ") +
|
||||
"'. Expected a " +
|
||||
"list of floats or 'none' but got '" + (*str) + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Symbolizer, typename T>
|
||||
struct set_symbolizer_property_impl<Symbolizer, T, true>
|
||||
{
|
||||
|
|
|
@ -29,6 +29,9 @@
|
|||
#include <boost/spirit/include/phoenix_stl.hpp>
|
||||
#include <boost/spirit/include/phoenix_function.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace mapnik { namespace util {
|
||||
|
||||
template <typename Iterator>
|
||||
|
@ -57,6 +60,26 @@ bool parse_dasharray(Iterator first, Iterator last, std::vector<double>& dasharr
|
|||
return r;
|
||||
}
|
||||
|
||||
inline bool add_dashes(std::vector<double> & buf, dash_array & dash)
|
||||
{
|
||||
if (buf.empty()) return false;
|
||||
size_t size = buf.size();
|
||||
if (size % 2 == 1)
|
||||
{
|
||||
buf.insert(buf.end(),buf.begin(),buf.end());
|
||||
}
|
||||
std::vector<double>::const_iterator pos = buf.begin();
|
||||
while (pos != buf.end())
|
||||
{
|
||||
if (*pos > 0.0 || *(pos+1) > 0.0) // avoid both dash and gap eq 0.0
|
||||
{
|
||||
dash.emplace_back(*pos,*(pos + 1));
|
||||
}
|
||||
pos +=2;
|
||||
}
|
||||
return !buf.empty();
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif // MAPNIK_UTIL_DASHARRAY_PARSER_HPP
|
||||
|
|
|
@ -149,8 +149,10 @@ struct converter_traits<T, mapnik::dash_tag>
|
|||
static void setup(geometry_type & geom, Args const& args)
|
||||
{
|
||||
typename boost::mpl::at<Args,boost::mpl::int_<2> >::type sym = boost::fusion::at_c<2>(args);
|
||||
auto const& feat = boost::fusion::at_c<6>(args);
|
||||
auto const& vars = boost::fusion::at_c<7>(args);
|
||||
double scale_factor = boost::fusion::at_c<8>(args);
|
||||
auto dash = get_optional<dash_array>(sym, keys::stroke_dasharray);
|
||||
auto dash = get_optional<dash_array>(sym, keys::stroke_dasharray, feat, vars);
|
||||
if (dash)
|
||||
{
|
||||
for (auto const& d : *dash)
|
||||
|
|
|
@ -353,7 +353,7 @@ void cairo_renderer_base::process(line_symbolizer const& sym,
|
|||
double stroke_opacity = get<double>(sym, keys::stroke_opacity, feature, common_.vars_, 1.0);
|
||||
line_join_enum stroke_join = get<line_join_enum>(sym, keys::stroke_linejoin, feature, common_.vars_, MITER_JOIN);
|
||||
line_cap_enum stroke_cap = get<line_cap_enum>(sym, keys::stroke_linecap, feature, common_.vars_, BUTT_CAP);
|
||||
auto dash = get_optional<dash_array>(sym, keys::stroke_dasharray);
|
||||
auto dash = get_optional<dash_array>(sym, keys::stroke_dasharray, feature, common_.vars_);
|
||||
double miterlimit = get<double>(sym, keys::stroke_miterlimit, feature, common_.vars_, 4.0);
|
||||
double width = get<double>(sym, keys::stroke_width, feature, common_.vars_, 1.0);
|
||||
|
||||
|
|
|
@ -1227,44 +1227,7 @@ void map_parser::parse_stroke(symbolizer_base & sym, xml_node const & node)
|
|||
// stroke-miterlimit
|
||||
set_symbolizer_property<symbolizer_base,double>(sym, keys::stroke_miterlimit, node);
|
||||
// stroke-dasharray
|
||||
optional<std::string> str = node.get_opt_attr<std::string>("stroke-dasharray");
|
||||
if (str)
|
||||
{
|
||||
std::vector<double> buf;
|
||||
if (util::parse_dasharray((*str).begin(),(*str).end(),buf))
|
||||
{
|
||||
if (!buf.empty())
|
||||
{
|
||||
size_t size = buf.size();
|
||||
if (size % 2 == 1)
|
||||
{
|
||||
buf.insert(buf.end(),buf.begin(),buf.end());
|
||||
}
|
||||
|
||||
dash_array dash;
|
||||
std::vector<double>::const_iterator pos = buf.begin();
|
||||
while (pos != buf.end())
|
||||
{
|
||||
if (*pos > 0.0 || *(pos+1) > 0.0) // avoid both dash and gap eq 0.0
|
||||
{
|
||||
dash.emplace_back(*pos,*(pos + 1));
|
||||
}
|
||||
pos +=2;
|
||||
}
|
||||
if (dash.size() > 0)
|
||||
{
|
||||
put(sym,keys::stroke_dasharray,dash);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw config_error(std::string("Failed to parse dasharray ") +
|
||||
"'. Expected a " +
|
||||
"list of floats or 'none' but got '" + (*str) + "'");
|
||||
}
|
||||
}
|
||||
|
||||
set_symbolizer_property<symbolizer_base,dash_array>(sym, keys::stroke_dasharray, node);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
</Rule>
|
||||
<Rule>
|
||||
<Filter>[id] = 'stroke-dasharray'</Filter>
|
||||
<LineSymbolizer stroke-width='5' stroke='#ff0000' stroke-dasharray="3,3" />
|
||||
<LineSymbolizer stroke-width='5' stroke='#ff0000' stroke-dasharray="[value]" />
|
||||
</Rule>
|
||||
<Rule>
|
||||
<Filter>[id] = 'stroke-linejoin'</Filter>
|
||||
|
|
Loading…
Add table
Reference in a new issue