Merge pull request #916 from kkaefer/grouped-rendering
Grouped rendering
This commit is contained in:
commit
1c4b67ba98
10 changed files with 367 additions and 204 deletions
|
@ -23,8 +23,16 @@
|
|||
#ifndef MAPNIK_FEATURE_STYLE_PROCESSOR_HPP
|
||||
#define MAPNIK_FEATURE_STYLE_PROCESSOR_HPP
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/map.hpp>
|
||||
#include <mapnik/projection.hpp>
|
||||
#include <mapnik/memory_datasource.hpp>
|
||||
|
||||
|
||||
// stl
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace mapnik
|
||||
{
|
||||
|
@ -62,11 +70,23 @@ private:
|
|||
/*!
|
||||
* @return render a layer given a projection and scale.
|
||||
*/
|
||||
void apply_to_layer(layer const& lay, Processor & p,
|
||||
void apply_to_layer(layer const& lay,
|
||||
Processor & p,
|
||||
projection const& proj0,
|
||||
double scale_denom,
|
||||
std::set<std::string>& names);
|
||||
|
||||
/*!
|
||||
* @return renders a featureset with the given styles.
|
||||
*/
|
||||
void render_style(layer const& lay,
|
||||
Processor & p,
|
||||
feature_type_style* style,
|
||||
std::string const& style_name,
|
||||
featureset_ptr features,
|
||||
proj_transform const& prj_trans,
|
||||
double scale_denom);
|
||||
|
||||
Map const& m_;
|
||||
double scale_factor_;
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
*
|
||||
* This file is part of Mapnik (c++ mapping toolkit)
|
||||
*
|
||||
* Copyright (C) 2011 Artem Pavlenko
|
||||
|
@ -23,7 +23,7 @@
|
|||
#ifndef MAPNIK_FEATURE_TYPE_STYLE_HPP
|
||||
#define MAPNIK_FEATURE_TYPE_STYLE_HPP
|
||||
|
||||
// mapnik
|
||||
// mapnik
|
||||
#include <mapnik/rule.hpp>
|
||||
#include <mapnik/feature.hpp>
|
||||
#include <mapnik/enumeration.hpp>
|
||||
|
@ -43,29 +43,43 @@ enum filter_mode_enum {
|
|||
DEFINE_ENUM( filter_mode_e, filter_mode_enum );
|
||||
|
||||
typedef std::vector<rule> rules;
|
||||
typedef std::vector<rule*> rule_ptrs;
|
||||
|
||||
class MAPNIK_DECL feature_type_style
|
||||
{
|
||||
private:
|
||||
rules rules_;
|
||||
filter_mode_e filter_mode_;
|
||||
|
||||
// The rule_ptrs vectors are only valid for the scale_denom_validity_.
|
||||
double scale_denom_validity_;
|
||||
rule_ptrs if_rules_;
|
||||
rule_ptrs else_rules_;
|
||||
rule_ptrs also_rules_;
|
||||
public:
|
||||
feature_type_style();
|
||||
|
||||
feature_type_style(feature_type_style const& rhs, bool deep_copy = false);
|
||||
|
||||
|
||||
feature_type_style& operator=(feature_type_style const& rhs);
|
||||
|
||||
|
||||
void add_rule(rule const& rule);
|
||||
|
||||
|
||||
rules const& get_rules() const;
|
||||
rule_ptrs const& get_if_rules(double scale_denom);
|
||||
rule_ptrs const& get_else_rules(double scale_denom);
|
||||
rule_ptrs const& get_also_rules(double scale_denom);
|
||||
|
||||
rules &get_rules_nonconst();
|
||||
|
||||
|
||||
void set_filter_mode(filter_mode_e mode);
|
||||
|
||||
filter_mode_e get_filter_mode() const;
|
||||
|
||||
|
||||
~feature_type_style() {}
|
||||
|
||||
private:
|
||||
void update_rule_cache(double scale_denom);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -180,6 +180,16 @@ public:
|
|||
*/
|
||||
bool cache_features() const;
|
||||
|
||||
/*!
|
||||
* @param group_by Set the field rendering of this layer is grouped by.
|
||||
*/
|
||||
void set_group_by(std::string column);
|
||||
|
||||
/*!
|
||||
* @return The field rendering of this layer is grouped by.
|
||||
*/
|
||||
std::string group_by() const;
|
||||
|
||||
/*!
|
||||
* @brief Attach a datasource for this layer.
|
||||
*
|
||||
|
@ -212,6 +222,7 @@ private:
|
|||
bool queryable_;
|
||||
bool clear_label_cache_;
|
||||
bool cache_features_;
|
||||
std::string group_by_;
|
||||
std::vector<std::string> styles_;
|
||||
datasource_ptr ds_;
|
||||
};
|
||||
|
|
|
@ -45,6 +45,7 @@ public:
|
|||
box2d<double> envelope() const;
|
||||
layer_descriptor get_descriptor() const;
|
||||
size_t size() const;
|
||||
void clear();
|
||||
private:
|
||||
std::vector<feature_ptr> features_;
|
||||
mapnik::layer_descriptor desc_;
|
||||
|
|
|
@ -25,13 +25,10 @@
|
|||
#include <mapnik/box2d.hpp>
|
||||
#include <mapnik/datasource.hpp>
|
||||
#include <mapnik/layer.hpp>
|
||||
#include <mapnik/map.hpp>
|
||||
#include <mapnik/attribute_collector.hpp>
|
||||
#include <mapnik/expression_evaluator.hpp>
|
||||
#include <mapnik/utils.hpp>
|
||||
#include <mapnik/projection.hpp>
|
||||
#include <mapnik/scale_denominator.hpp>
|
||||
#include <mapnik/memory_datasource.hpp>
|
||||
|
||||
#include <mapnik/agg_renderer.hpp>
|
||||
#include <mapnik/grid/grid_renderer.hpp>
|
||||
|
@ -308,65 +305,23 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
|
|||
}
|
||||
}
|
||||
|
||||
// push all property names
|
||||
BOOST_FOREACH(std::string const& name, names)
|
||||
// Don't even try to do more work if there are no active styles.
|
||||
if (active_styles.size() > 0)
|
||||
{
|
||||
q.add_property_name(name);
|
||||
}
|
||||
|
||||
memory_datasource cache;
|
||||
bool cache_features = lay.cache_features() && num_styles>1?true:false;
|
||||
bool first = true;
|
||||
|
||||
#if defined(RENDERING_STATS)
|
||||
int style_index = 0;
|
||||
if (!active_styles.size() > 0) {
|
||||
layer_timer.discard();
|
||||
}
|
||||
#endif
|
||||
BOOST_FOREACH (feature_type_style * style, active_styles)
|
||||
{
|
||||
#if defined(RENDERING_STATS)
|
||||
std::string s_name = style_names[style_index];
|
||||
std::ostringstream s1;
|
||||
s1 << "rendering style #" << style_index+1
|
||||
<< " for layer: '" << lay.name() << "' and style '" << s_name << "'";
|
||||
mapnik::progress_timer style_timer(std::clog, s1.str());
|
||||
if (!num_styles>1)
|
||||
style_timer.discard();
|
||||
style_index++;
|
||||
#endif
|
||||
|
||||
std::vector<rule*> if_rules;
|
||||
std::vector<rule*> else_rules;
|
||||
std::vector<rule*> also_rules;
|
||||
|
||||
std::vector<rule> const& rules=style->get_rules();
|
||||
|
||||
#if defined(RENDERING_STATS)
|
||||
int feature_count = 0;
|
||||
int feature_processed_count = 0;
|
||||
#endif
|
||||
|
||||
BOOST_FOREACH(rule const& r, rules)
|
||||
// push all property names
|
||||
BOOST_FOREACH(std::string const& name, names)
|
||||
{
|
||||
if (r.active(scale_denom))
|
||||
{
|
||||
if (r.has_else_filter())
|
||||
{
|
||||
else_rules.push_back(const_cast<rule*>(&r));
|
||||
}
|
||||
else if (r.has_also_filter())
|
||||
{
|
||||
also_rules.push_back(const_cast<rule*>(&r));
|
||||
}
|
||||
else
|
||||
{
|
||||
if_rules.push_back(const_cast<rule*>(&r));
|
||||
}
|
||||
q.add_property_name(name);
|
||||
}
|
||||
|
||||
if ( (ds->type() == datasource::Raster) &&
|
||||
(ds->params().get<double>("filter_factor",0.0) == 0.0) )
|
||||
// Update filter_factor for all enabled raster layers.
|
||||
BOOST_FOREACH (feature_type_style * style, active_styles)
|
||||
{
|
||||
BOOST_FOREACH(rule const& r, style->get_rules())
|
||||
{
|
||||
if (r.active(scale_denom) &&
|
||||
ds->type() == datasource::Raster &&
|
||||
ds->params().get<double>("filter_factor",0.0) == 0.0)
|
||||
{
|
||||
rule::symbolizers const& symbols = r.get_symbolizers();
|
||||
rule::symbolizers::const_iterator symIter = symbols.begin();
|
||||
|
@ -382,163 +337,235 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
|
|||
}
|
||||
}
|
||||
|
||||
// process features
|
||||
featureset_ptr fs;
|
||||
if (first)
|
||||
// Also query the group by attribute
|
||||
std::string group_by = lay.group_by();
|
||||
if (group_by != "")
|
||||
{
|
||||
if (cache_features)
|
||||
first = false;
|
||||
fs = ds->features(q);
|
||||
}
|
||||
else
|
||||
{
|
||||
fs = cache.features(q);
|
||||
q.add_property_name(group_by);
|
||||
}
|
||||
|
||||
if (fs)
|
||||
bool cache_features = lay.cache_features() && active_styles.size() > 1;
|
||||
|
||||
// Render incrementally when the column that we group by
|
||||
// changes value.
|
||||
if (group_by != "")
|
||||
{
|
||||
feature_ptr feature;
|
||||
while ((feature = fs->next()))
|
||||
{
|
||||
featureset_ptr features = ds->features(q);
|
||||
if (features) {
|
||||
// Cache all features into the memory_datasource before rendering.
|
||||
memory_datasource cache;
|
||||
feature_ptr feature, prev;
|
||||
|
||||
#if defined(RENDERING_STATS)
|
||||
feature_count++;
|
||||
bool feat_processed = false;
|
||||
#endif
|
||||
while ((feature = features->next()))
|
||||
{
|
||||
if (prev && prev->props()[group_by] != feature->props()[group_by])
|
||||
{
|
||||
// We're at a value boundary, so render what we have
|
||||
// up to this point.
|
||||
int i = 0;
|
||||
BOOST_FOREACH (feature_type_style * style, active_styles)
|
||||
{
|
||||
render_style(lay, p, style, style_names[i++],
|
||||
cache.features(q), prj_trans, scale_denom);
|
||||
}
|
||||
cache.clear();
|
||||
}
|
||||
cache.push(feature);
|
||||
prev = feature;
|
||||
}
|
||||
|
||||
bool do_else=true;
|
||||
bool do_also=false;
|
||||
|
||||
if (cache_features)
|
||||
int i = 0;
|
||||
BOOST_FOREACH (feature_type_style * style, active_styles)
|
||||
{
|
||||
render_style(lay, p, style, style_names[i++],
|
||||
cache.features(q), prj_trans, scale_denom);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (cache_features)
|
||||
{
|
||||
featureset_ptr features = ds->features(q);
|
||||
if (features) {
|
||||
// Cache all features into the memory_datasource before rendering.
|
||||
memory_datasource cache;
|
||||
feature_ptr feature;
|
||||
while ((feature = features->next()))
|
||||
{
|
||||
cache.push(feature);
|
||||
}
|
||||
|
||||
BOOST_FOREACH(rule * r, if_rules )
|
||||
int i = 0;
|
||||
BOOST_FOREACH (feature_type_style * style, active_styles)
|
||||
{
|
||||
expression_ptr const& expr=r->get_filter();
|
||||
value_type result = boost::apply_visitor(evaluate<Feature,value_type>(*feature),*expr);
|
||||
if (result.to_bool())
|
||||
{
|
||||
#if defined(RENDERING_STATS)
|
||||
feat_processed = true;
|
||||
#endif
|
||||
|
||||
p.painted(true);
|
||||
|
||||
do_else=false;
|
||||
do_also=true;
|
||||
rule::symbolizers const& symbols = r->get_symbolizers();
|
||||
|
||||
// if the underlying renderer is not able to process the complete set of symbolizers,
|
||||
// process one by one.
|
||||
#if defined(SVG_RENDERER)
|
||||
if(!p.process(symbols,*feature,prj_trans))
|
||||
#endif
|
||||
{
|
||||
|
||||
BOOST_FOREACH (symbolizer const& sym, symbols)
|
||||
{
|
||||
boost::apply_visitor(symbol_dispatch(p,*feature,prj_trans),sym);
|
||||
}
|
||||
}
|
||||
if (style->get_filter_mode() == FILTER_FIRST)
|
||||
{
|
||||
// Stop iterating over rules and proceed with next feature.
|
||||
break;
|
||||
}
|
||||
}
|
||||
render_style(lay, p, style, style_names[i++],
|
||||
cache.features(q), prj_trans, scale_denom);
|
||||
}
|
||||
if (do_else)
|
||||
{
|
||||
BOOST_FOREACH( rule * r, else_rules )
|
||||
{
|
||||
#if defined(RENDERING_STATS)
|
||||
feat_processed = true;
|
||||
#endif
|
||||
|
||||
p.painted(true);
|
||||
|
||||
rule::symbolizers const& symbols = r->get_symbolizers();
|
||||
// if the underlying renderer is not able to process the complete set of symbolizers,
|
||||
// process one by one.
|
||||
#if defined(SVG_RENDERER)
|
||||
if(!p.process(symbols,*feature,prj_trans))
|
||||
#endif
|
||||
{
|
||||
BOOST_FOREACH (symbolizer const& sym, symbols)
|
||||
{
|
||||
boost::apply_visitor(symbol_dispatch(p,*feature,prj_trans),sym);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (do_also)
|
||||
{
|
||||
BOOST_FOREACH( rule * r, also_rules )
|
||||
{
|
||||
#if defined(RENDERING_STATS)
|
||||
feat_processed = true;
|
||||
#endif
|
||||
|
||||
p.painted(true);
|
||||
|
||||
rule::symbolizers const& symbols = r->get_symbolizers();
|
||||
// if the underlying renderer is not able to process the complete set of symbolizers,
|
||||
// process one by one.
|
||||
#if defined(SVG_RENDERER)
|
||||
if(!p.process(symbols,*feature,prj_trans))
|
||||
#endif
|
||||
{
|
||||
BOOST_FOREACH (symbolizer const& sym, symbols)
|
||||
{
|
||||
boost::apply_visitor(symbol_dispatch(p,*feature,prj_trans),sym);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#if defined(RENDERING_STATS)
|
||||
if (feat_processed)
|
||||
feature_processed_count++;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(RENDERING_STATS)
|
||||
style_timer.stop();
|
||||
|
||||
// done with style
|
||||
std::ostringstream s;
|
||||
if (feature_count > 0) {
|
||||
double perc_processed = ((double)feature_processed_count/(double)feature_count)*100.0;
|
||||
|
||||
s << "percent rendered: " << perc_processed << "% - " << feature_processed_count
|
||||
<< " rendered for " << feature_count << " queried for ";
|
||||
s << std::setw(15 - (int)s.tellp()) << " layer '" << lay.name() << "' and style '" << s_name << "'\n";
|
||||
|
||||
} else {
|
||||
s << "" << std::setw(15) << "- no features returned from query for layer '" << lay.name() << "' and style '" << s_name << "'\n";
|
||||
}
|
||||
// We only have a single style and no grouping.
|
||||
else
|
||||
{
|
||||
int i = 0;
|
||||
BOOST_FOREACH (feature_type_style * style, active_styles)
|
||||
{
|
||||
featureset_ptr features = ds->features(q);
|
||||
if (features) {
|
||||
render_style(lay, p, style, style_names[i++],
|
||||
features, prj_trans, scale_denom);
|
||||
}
|
||||
}
|
||||
std::clog << s.str();
|
||||
#endif
|
||||
|
||||
}
|
||||
#if defined(RENDERING_STATS)
|
||||
else {
|
||||
style_timer.discard();
|
||||
layer_timer.discard();
|
||||
}
|
||||
#endif
|
||||
cache_features = false;
|
||||
}
|
||||
|
||||
|
||||
#if defined(RENDERING_STATS)
|
||||
layer_timer.stop();
|
||||
#endif
|
||||
|
||||
|
||||
p.end_layer_processing(lay);
|
||||
}
|
||||
|
||||
|
||||
template <typename Processor>
|
||||
void feature_style_processor<Processor>::render_style(
|
||||
layer const& lay,
|
||||
Processor & p,
|
||||
feature_type_style* style,
|
||||
std::string const& style_name,
|
||||
featureset_ptr features,
|
||||
proj_transform const& prj_trans,
|
||||
double scale_denom)
|
||||
{
|
||||
#if defined(RENDERING_STATS)
|
||||
std::ostringstream s1;
|
||||
s1 << "rendering style for layer: '" << lay.name()
|
||||
<< "' and style '" << style_name << "'";
|
||||
mapnik::progress_timer style_timer(std::clog, s1.str());
|
||||
|
||||
int feature_processed_count = 0;
|
||||
int feature_count = 0;
|
||||
#endif
|
||||
|
||||
feature_ptr feature;
|
||||
while ((feature = features->next()))
|
||||
{
|
||||
#if defined(RENDERING_STATS)
|
||||
feature_count++;
|
||||
bool feat_processed = false;
|
||||
#endif
|
||||
|
||||
bool do_else = true;
|
||||
bool do_also = false;
|
||||
|
||||
BOOST_FOREACH(rule * r, style->get_if_rules(scale_denom) )
|
||||
{
|
||||
expression_ptr const& expr=r->get_filter();
|
||||
value_type result = boost::apply_visitor(evaluate<Feature,value_type>(*feature),*expr);
|
||||
if (result.to_bool())
|
||||
{
|
||||
#if defined(RENDERING_STATS)
|
||||
feat_processed = true;
|
||||
#endif
|
||||
|
||||
p.painted(true);
|
||||
|
||||
do_else=false;
|
||||
do_also=true;
|
||||
rule::symbolizers const& symbols = r->get_symbolizers();
|
||||
|
||||
// if the underlying renderer is not able to process the complete set of symbolizers,
|
||||
// process one by one.
|
||||
#if defined(SVG_RENDERER)
|
||||
if(!p.process(symbols,*feature,prj_trans))
|
||||
#endif
|
||||
{
|
||||
|
||||
BOOST_FOREACH (symbolizer const& sym, symbols)
|
||||
{
|
||||
boost::apply_visitor(symbol_dispatch(p,*feature,prj_trans),sym);
|
||||
}
|
||||
}
|
||||
if (style->get_filter_mode() == FILTER_FIRST)
|
||||
{
|
||||
// Stop iterating over rules and proceed with next feature.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (do_else)
|
||||
{
|
||||
BOOST_FOREACH( rule * r, style->get_else_rules(scale_denom) )
|
||||
{
|
||||
#if defined(RENDERING_STATS)
|
||||
feat_processed = true;
|
||||
#endif
|
||||
|
||||
p.painted(true);
|
||||
|
||||
rule::symbolizers const& symbols = r->get_symbolizers();
|
||||
// if the underlying renderer is not able to process the complete set of symbolizers,
|
||||
// process one by one.
|
||||
#if defined(SVG_RENDERER)
|
||||
if(!p.process(symbols,*feature,prj_trans))
|
||||
#endif
|
||||
{
|
||||
BOOST_FOREACH (symbolizer const& sym, symbols)
|
||||
{
|
||||
boost::apply_visitor(symbol_dispatch(p,*feature,prj_trans),sym);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (do_also)
|
||||
{
|
||||
BOOST_FOREACH( rule * r, style->get_also_rules(scale_denom) )
|
||||
{
|
||||
#if defined(RENDERING_STATS)
|
||||
feat_processed = true;
|
||||
#endif
|
||||
|
||||
p.painted(true);
|
||||
|
||||
rule::symbolizers const& symbols = r->get_symbolizers();
|
||||
// if the underlying renderer is not able to process the complete set of symbolizers,
|
||||
// process one by one.
|
||||
#if defined(SVG_RENDERER)
|
||||
if(!p.process(symbols,*feature,prj_trans))
|
||||
#endif
|
||||
{
|
||||
BOOST_FOREACH (symbolizer const& sym, symbols)
|
||||
{
|
||||
boost::apply_visitor(symbol_dispatch(p,*feature,prj_trans),sym);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#if defined(RENDERING_STATS)
|
||||
if (feat_processed)
|
||||
feature_processed_count++;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(RENDERING_STATS)
|
||||
style_timer.stop();
|
||||
|
||||
// done with style
|
||||
std::ostringstream s;
|
||||
if (feature_count > 0) {
|
||||
double perc_processed = ((double)feature_processed_count/(double)feature_count)*100.0;
|
||||
|
||||
s << "percent rendered: " << perc_processed << "% - " << feature_processed_count
|
||||
<< " rendered for " << feature_count << " queried for ";
|
||||
s << std::setw(15 - (int)s.tellp()) << " layer '" << lay.name() << "' and style '" << s_name << "'\n";
|
||||
|
||||
} else {
|
||||
s << "" << std::setw(15) << "- no features returned from query for layer '" << lay.name() << "' and style '" << s_name << "'\n";
|
||||
}
|
||||
std::clog << s.str();
|
||||
style_timer.discard();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if defined(HAVE_CAIRO)
|
||||
template class feature_style_processor<cairo_renderer<Cairo::Context> >;
|
||||
template class feature_style_processor<cairo_renderer<Cairo::Surface> >;
|
||||
|
|
|
@ -35,10 +35,12 @@ IMPLEMENT_ENUM( filter_mode_e, filter_mode_strings )
|
|||
|
||||
|
||||
feature_type_style::feature_type_style()
|
||||
: filter_mode_(FILTER_ALL) {}
|
||||
: filter_mode_(FILTER_ALL),
|
||||
scale_denom_validity_(-1) {}
|
||||
|
||||
feature_type_style::feature_type_style(feature_type_style const& rhs, bool deep_copy)
|
||||
: filter_mode_(rhs.filter_mode_)
|
||||
: filter_mode_(rhs.filter_mode_),
|
||||
scale_denom_validity_(-1)
|
||||
{
|
||||
if (!deep_copy) {
|
||||
rules_ = rhs.rules_;
|
||||
|
@ -55,12 +57,14 @@ feature_type_style& feature_type_style::operator=(feature_type_style const& rhs)
|
|||
{
|
||||
if (this == &rhs) return *this;
|
||||
rules_=rhs.rules_;
|
||||
scale_denom_validity_ = -1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void feature_type_style::add_rule(rule const& rule)
|
||||
{
|
||||
rules_.push_back(rule);
|
||||
scale_denom_validity_ = -1;
|
||||
}
|
||||
|
||||
rules const& feature_type_style::get_rules() const
|
||||
|
@ -83,4 +87,60 @@ filter_mode_e feature_type_style::get_filter_mode() const
|
|||
return filter_mode_;
|
||||
}
|
||||
|
||||
|
||||
void feature_type_style::update_rule_cache(double scale_denom)
|
||||
{
|
||||
if_rules_.clear();
|
||||
else_rules_.clear();
|
||||
also_rules_.clear();
|
||||
|
||||
BOOST_FOREACH(rule const& r, rules_)
|
||||
{
|
||||
if (r.active(scale_denom))
|
||||
{
|
||||
if (r.has_else_filter())
|
||||
{
|
||||
else_rules_.push_back(const_cast<rule*>(&r));
|
||||
}
|
||||
else if (r.has_also_filter())
|
||||
{
|
||||
also_rules_.push_back(const_cast<rule*>(&r));
|
||||
}
|
||||
else
|
||||
{
|
||||
if_rules_.push_back(const_cast<rule*>(&r));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scale_denom_validity_ = scale_denom;
|
||||
}
|
||||
|
||||
rule_ptrs const& feature_type_style::get_if_rules(double scale_denom)
|
||||
{
|
||||
if (scale_denom_validity_ != scale_denom)
|
||||
{
|
||||
update_rule_cache(scale_denom);
|
||||
}
|
||||
return if_rules_;
|
||||
}
|
||||
|
||||
rule_ptrs const& feature_type_style::get_else_rules(double scale_denom)
|
||||
{
|
||||
if (scale_denom_validity_ != scale_denom)
|
||||
{
|
||||
update_rule_cache(scale_denom);
|
||||
}
|
||||
return else_rules_;
|
||||
}
|
||||
|
||||
rule_ptrs const& feature_type_style::get_also_rules(double scale_denom)
|
||||
{
|
||||
if (scale_denom_validity_ != scale_denom)
|
||||
{
|
||||
update_rule_cache(scale_denom);
|
||||
}
|
||||
return also_rules_;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ layer::layer(std::string const& name, std::string const& srs)
|
|||
queryable_(false),
|
||||
clear_label_cache_(false),
|
||||
cache_features_(false),
|
||||
group_by_(""),
|
||||
ds_() {}
|
||||
|
||||
layer::layer(const layer& rhs)
|
||||
|
@ -59,6 +60,7 @@ layer::layer(const layer& rhs)
|
|||
queryable_(rhs.queryable_),
|
||||
clear_label_cache_(rhs.clear_label_cache_),
|
||||
cache_features_(rhs.cache_features_),
|
||||
group_by_(rhs.group_by_),
|
||||
styles_(rhs.styles_),
|
||||
ds_(rhs.ds_) {}
|
||||
|
||||
|
@ -86,6 +88,7 @@ void layer::swap(const layer& rhs)
|
|||
queryable_=rhs.queryable_;
|
||||
clear_label_cache_ = rhs.clear_label_cache_;
|
||||
cache_features_ = rhs.cache_features_;
|
||||
group_by_ = rhs.group_by_;
|
||||
styles_=rhs.styles_;
|
||||
ds_=rhs.ds_;
|
||||
}
|
||||
|
@ -228,4 +231,14 @@ bool layer::cache_features() const
|
|||
return cache_features_;
|
||||
}
|
||||
|
||||
void layer::set_group_by(std::string column)
|
||||
{
|
||||
group_by_ = column;
|
||||
}
|
||||
|
||||
std::string layer::group_by() const
|
||||
{
|
||||
return group_by_;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -583,7 +583,8 @@ void map_parser::parse_layer( Map & map, ptree const & lay )
|
|||
<< "maxzoom,"
|
||||
<< "queryable,"
|
||||
<< "clear-label-cache,"
|
||||
<< "cache-features";
|
||||
<< "cache-features,"
|
||||
<< "group-by";
|
||||
ensure_attrs(lay, "Layer", s.str());
|
||||
try
|
||||
{
|
||||
|
@ -644,6 +645,12 @@ void map_parser::parse_layer( Map & map, ptree const & lay )
|
|||
lyr.set_cache_features( * cache_features );
|
||||
}
|
||||
|
||||
optional<std::string> group_by =
|
||||
get_opt_attr<std::string>(lay, "group-by");
|
||||
if (group_by)
|
||||
{
|
||||
lyr.set_group_by( * group_by );
|
||||
}
|
||||
|
||||
ptree::const_iterator itr2 = lay.begin();
|
||||
ptree::const_iterator end2 = lay.end();
|
||||
|
|
|
@ -107,6 +107,11 @@ size_t memory_datasource::size() const
|
|||
return features_.size();
|
||||
}
|
||||
|
||||
void memory_datasource::clear()
|
||||
{
|
||||
features_.clear();
|
||||
}
|
||||
|
||||
// point_datasource
|
||||
|
||||
void point_datasource::add_point(double x, double y, const char* key, const char* value)
|
||||
|
|
|
@ -865,6 +865,11 @@ void serialize_layer( ptree & map_node, const layer & layer, bool explicit_defau
|
|||
set_attr/*<bool>*/( layer_node, "cache-features", layer.cache_features() );
|
||||
}
|
||||
|
||||
if ( layer.group_by() != "" || explicit_defaults )
|
||||
{
|
||||
set_attr( layer_node, "group-by", layer.group_by() );
|
||||
}
|
||||
|
||||
std::vector<std::string> const& style_names = layer.styles();
|
||||
for (unsigned i = 0; i < style_names.size(); ++i)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue