Merge branch 'master' of github.com:mapnik/mapnik into geometry_cleanup

This commit is contained in:
Dane Springmeyer 2011-12-12 08:31:23 -08:00
commit 51bd04c448
10 changed files with 367 additions and 204 deletions

View file

@ -23,8 +23,16 @@
#ifndef MAPNIK_FEATURE_STYLE_PROCESSOR_HPP #ifndef MAPNIK_FEATURE_STYLE_PROCESSOR_HPP
#define 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 <set>
#include <string> #include <string>
#include <vector>
namespace mapnik namespace mapnik
{ {
@ -62,11 +70,23 @@ private:
/*! /*!
* @return render a layer given a projection and scale. * @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, projection const& proj0,
double scale_denom, double scale_denom,
std::set<std::string>& names); 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_; Map const& m_;
double scale_factor_; double scale_factor_;
}; };

View file

@ -1,5 +1,5 @@
/***************************************************************************** /*****************************************************************************
* *
* This file is part of Mapnik (c++ mapping toolkit) * This file is part of Mapnik (c++ mapping toolkit)
* *
* Copyright (C) 2011 Artem Pavlenko * Copyright (C) 2011 Artem Pavlenko
@ -23,7 +23,7 @@
#ifndef MAPNIK_FEATURE_TYPE_STYLE_HPP #ifndef MAPNIK_FEATURE_TYPE_STYLE_HPP
#define MAPNIK_FEATURE_TYPE_STYLE_HPP #define MAPNIK_FEATURE_TYPE_STYLE_HPP
// mapnik // mapnik
#include <mapnik/rule.hpp> #include <mapnik/rule.hpp>
#include <mapnik/feature.hpp> #include <mapnik/feature.hpp>
#include <mapnik/enumeration.hpp> #include <mapnik/enumeration.hpp>
@ -43,29 +43,43 @@ enum filter_mode_enum {
DEFINE_ENUM( filter_mode_e, filter_mode_enum ); DEFINE_ENUM( filter_mode_e, filter_mode_enum );
typedef std::vector<rule> rules; typedef std::vector<rule> rules;
typedef std::vector<rule*> rule_ptrs;
class MAPNIK_DECL feature_type_style class MAPNIK_DECL feature_type_style
{ {
private: private:
rules rules_; rules rules_;
filter_mode_e filter_mode_; 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: public:
feature_type_style(); feature_type_style();
feature_type_style(feature_type_style const& rhs, bool deep_copy = false); feature_type_style(feature_type_style const& rhs, bool deep_copy = false);
feature_type_style& operator=(feature_type_style const& rhs); feature_type_style& operator=(feature_type_style const& rhs);
void add_rule(rule const& rule); void add_rule(rule const& rule);
rules const& get_rules() const; 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(); rules &get_rules_nonconst();
void set_filter_mode(filter_mode_e mode); void set_filter_mode(filter_mode_e mode);
filter_mode_e get_filter_mode() const; filter_mode_e get_filter_mode() const;
~feature_type_style() {} ~feature_type_style() {}
private:
void update_rule_cache(double scale_denom);
}; };
} }

View file

@ -180,6 +180,16 @@ public:
*/ */
bool cache_features() const; 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. * @brief Attach a datasource for this layer.
* *
@ -212,6 +222,7 @@ private:
bool queryable_; bool queryable_;
bool clear_label_cache_; bool clear_label_cache_;
bool cache_features_; bool cache_features_;
std::string group_by_;
std::vector<std::string> styles_; std::vector<std::string> styles_;
datasource_ptr ds_; datasource_ptr ds_;
}; };

View file

@ -45,6 +45,7 @@ public:
box2d<double> envelope() const; box2d<double> envelope() const;
layer_descriptor get_descriptor() const; layer_descriptor get_descriptor() const;
size_t size() const; size_t size() const;
void clear();
private: private:
std::vector<feature_ptr> features_; std::vector<feature_ptr> features_;
mapnik::layer_descriptor desc_; mapnik::layer_descriptor desc_;

View file

@ -25,13 +25,10 @@
#include <mapnik/box2d.hpp> #include <mapnik/box2d.hpp>
#include <mapnik/datasource.hpp> #include <mapnik/datasource.hpp>
#include <mapnik/layer.hpp> #include <mapnik/layer.hpp>
#include <mapnik/map.hpp>
#include <mapnik/attribute_collector.hpp> #include <mapnik/attribute_collector.hpp>
#include <mapnik/expression_evaluator.hpp> #include <mapnik/expression_evaluator.hpp>
#include <mapnik/utils.hpp> #include <mapnik/utils.hpp>
#include <mapnik/projection.hpp>
#include <mapnik/scale_denominator.hpp> #include <mapnik/scale_denominator.hpp>
#include <mapnik/memory_datasource.hpp>
#include <mapnik/agg_renderer.hpp> #include <mapnik/agg_renderer.hpp>
#include <mapnik/grid/grid_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 // Don't even try to do more work if there are no active styles.
BOOST_FOREACH(std::string const& name, names) if (active_styles.size() > 0)
{ {
q.add_property_name(name); // push all property names
} BOOST_FOREACH(std::string const& name, names)
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)
{ {
if (r.active(scale_denom)) q.add_property_name(name);
{ }
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));
}
if ( (ds->type() == datasource::Raster) && // Update filter_factor for all enabled raster layers.
(ds->params().get<double>("filter_factor",0.0) == 0.0) ) 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& symbols = r.get_symbolizers();
rule::symbolizers::const_iterator symIter = symbols.begin(); 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 // Also query the group by attribute
featureset_ptr fs; std::string group_by = lay.group_by();
if (first) if (group_by != "")
{ {
if (cache_features) q.add_property_name(group_by);
first = false;
fs = ds->features(q);
}
else
{
fs = cache.features(q);
} }
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; featureset_ptr features = ds->features(q);
while ((feature = fs->next())) if (features) {
{ // Cache all features into the memory_datasource before rendering.
memory_datasource cache;
feature_ptr feature, prev;
#if defined(RENDERING_STATS) while ((feature = features->next()))
feature_count++; {
bool feat_processed = false; if (prev && prev->props()[group_by] != feature->props()[group_by])
#endif {
// 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; int i = 0;
bool do_also=false; BOOST_FOREACH (feature_type_style * style, active_styles)
{
if (cache_features) 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); 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(); render_style(lay, p, style, style_names[i++],
value_type result = boost::apply_visitor(evaluate<Feature,value_type>(*feature),*expr); cache.features(q), prj_trans, scale_denom);
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, 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) // We only have a single style and no grouping.
style_timer.stop(); else
{
// done with style int i = 0;
std::ostringstream s; BOOST_FOREACH (feature_type_style * style, active_styles)
if (feature_count > 0) { {
double perc_processed = ((double)feature_processed_count/(double)feature_count)*100.0; featureset_ptr features = ds->features(q);
if (features) {
s << "percent rendered: " << perc_processed << "% - " << feature_processed_count render_style(lay, p, style, style_names[i++],
<< " rendered for " << feature_count << " queried for "; features, prj_trans, scale_denom);
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();
#endif
} }
#if defined(RENDERING_STATS)
else {
style_timer.discard();
layer_timer.discard();
}
#endif
cache_features = false;
} }
#if defined(RENDERING_STATS) #if defined(RENDERING_STATS)
layer_timer.stop(); layer_timer.stop();
#endif #endif
p.end_layer_processing(lay); 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) #if defined(HAVE_CAIRO)
template class feature_style_processor<cairo_renderer<Cairo::Context> >; template class feature_style_processor<cairo_renderer<Cairo::Context> >;
template class feature_style_processor<cairo_renderer<Cairo::Surface> >; template class feature_style_processor<cairo_renderer<Cairo::Surface> >;

View file

@ -35,10 +35,12 @@ IMPLEMENT_ENUM( filter_mode_e, filter_mode_strings )
feature_type_style::feature_type_style() 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) 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) { if (!deep_copy) {
rules_ = rhs.rules_; rules_ = rhs.rules_;
@ -55,12 +57,14 @@ feature_type_style& feature_type_style::operator=(feature_type_style const& rhs)
{ {
if (this == &rhs) return *this; if (this == &rhs) return *this;
rules_=rhs.rules_; rules_=rhs.rules_;
scale_denom_validity_ = -1;
return *this; return *this;
} }
void feature_type_style::add_rule(rule const& rule) void feature_type_style::add_rule(rule const& rule)
{ {
rules_.push_back(rule); rules_.push_back(rule);
scale_denom_validity_ = -1;
} }
rules const& feature_type_style::get_rules() const 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_; 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_;
}
} }

View file

@ -46,6 +46,7 @@ layer::layer(std::string const& name, std::string const& srs)
queryable_(false), queryable_(false),
clear_label_cache_(false), clear_label_cache_(false),
cache_features_(false), cache_features_(false),
group_by_(""),
ds_() {} ds_() {}
layer::layer(const layer& rhs) layer::layer(const layer& rhs)
@ -59,6 +60,7 @@ layer::layer(const layer& rhs)
queryable_(rhs.queryable_), queryable_(rhs.queryable_),
clear_label_cache_(rhs.clear_label_cache_), clear_label_cache_(rhs.clear_label_cache_),
cache_features_(rhs.cache_features_), cache_features_(rhs.cache_features_),
group_by_(rhs.group_by_),
styles_(rhs.styles_), styles_(rhs.styles_),
ds_(rhs.ds_) {} ds_(rhs.ds_) {}
@ -86,6 +88,7 @@ void layer::swap(const layer& rhs)
queryable_=rhs.queryable_; queryable_=rhs.queryable_;
clear_label_cache_ = rhs.clear_label_cache_; clear_label_cache_ = rhs.clear_label_cache_;
cache_features_ = rhs.cache_features_; cache_features_ = rhs.cache_features_;
group_by_ = rhs.group_by_;
styles_=rhs.styles_; styles_=rhs.styles_;
ds_=rhs.ds_; ds_=rhs.ds_;
} }
@ -228,4 +231,14 @@ bool layer::cache_features() const
return cache_features_; return cache_features_;
} }
void layer::set_group_by(std::string column)
{
group_by_ = column;
}
std::string layer::group_by() const
{
return group_by_;
}
} }

View file

@ -583,7 +583,8 @@ void map_parser::parse_layer( Map & map, ptree const & lay )
<< "maxzoom," << "maxzoom,"
<< "queryable," << "queryable,"
<< "clear-label-cache," << "clear-label-cache,"
<< "cache-features"; << "cache-features,"
<< "group-by";
ensure_attrs(lay, "Layer", s.str()); ensure_attrs(lay, "Layer", s.str());
try try
{ {
@ -644,6 +645,12 @@ void map_parser::parse_layer( Map & map, ptree const & lay )
lyr.set_cache_features( * cache_features ); 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 itr2 = lay.begin();
ptree::const_iterator end2 = lay.end(); ptree::const_iterator end2 = lay.end();

View file

@ -107,6 +107,11 @@ size_t memory_datasource::size() const
return features_.size(); return features_.size();
} }
void memory_datasource::clear()
{
features_.clear();
}
// point_datasource // point_datasource
void point_datasource::add_point(double x, double y, const char* key, const char* value) void point_datasource::add_point(double x, double y, const char* key, const char* value)

View file

@ -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() ); 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(); std::vector<std::string> const& style_names = layer.styles();
for (unsigned i = 0; i < style_names.size(); ++i) for (unsigned i = 0; i < style_names.size(); ++i)
{ {