From b2dc2fa6d2eb54b3aa7cfecccdd9a9d3035c229c Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 1 Sep 2011 00:44:27 +0000 Subject: [PATCH] move feature_style_processor to cpp --- include/mapnik/feature_style_processor.hpp | 407 +------------------- src/build.py | 1 + src/feature_style_processor.cpp | 427 +++++++++++++++++++++ 3 files changed, 442 insertions(+), 393 deletions(-) create mode 100644 src/feature_style_processor.cpp diff --git a/include/mapnik/feature_style_processor.hpp b/include/mapnik/feature_style_processor.hpp index 6cc311cc5..6c944d979 100644 --- a/include/mapnik/feature_style_processor.hpp +++ b/include/mapnik/feature_style_processor.hpp @@ -25,156 +25,41 @@ #ifndef FEATURE_STYLE_PROCESSOR_HPP #define FEATURE_STYLE_PROCESSOR_HPP -// mapnik -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef MAPNIK_DEBUG -//#include -#endif -// boost -#include -//stl -#include +#include +#include namespace mapnik -{ +{ + +class Map; +class layer; +class projection; template class feature_style_processor { - /** Calls the renderer's process function, - * \param output Renderer - * \param f Feature to process - * \param prj_trans Projection - * \param sym Symbolizer object - */ - struct symbol_dispatch : public boost::static_visitor<> - { - symbol_dispatch (Processor & output, - Feature const& f, - proj_transform const& prj_trans) - : output_(output), - f_(f), - prj_trans_(prj_trans) {} - - template - void operator () (T const& sym) const - { - output_.process(sym,f_,prj_trans_); - } - - Processor & output_; - Feature const& f_; - proj_transform const& prj_trans_; - }; - + struct symbol_dispatch; public: - - explicit feature_style_processor(Map const& m, double scale_factor = 1.0) - : m_(m), - scale_factor_(scale_factor) {} + explicit feature_style_processor(Map const& m, double scale_factor = 1.0); /*! * @return apply renderer to all map layers. */ - void apply() - { -#ifdef MAPNIK_DEBUG - //mapnik::wall_clock_progress_timer t(std::clog, "map rendering took: "); -#endif - Processor & p = static_cast(*this); - p.start_map_processing(m_); - - try - { - projection proj(m_.srs()); - - start_metawriters(m_,proj); - - double scale_denom = mapnik::scale_denominator(m_,proj.is_geographic()); - scale_denom *= scale_factor_; -#ifdef MAPNIK_DEBUG - std::clog << "scale denominator = " << scale_denom << "\n"; -#endif - BOOST_FOREACH ( layer const& lyr, m_.layers() ) - { - if (lyr.isVisible(scale_denom)) - { - std::set names; - apply_to_layer(lyr, p, proj, scale_denom, names); - } - } - - stop_metawriters(m_); - } - catch (proj_init_error& ex) - { - std::clog << "proj_init_error:" << ex.what() << "\n"; - } - - p.end_map_processing(m_); - } + void apply(); /*! * @return apply renderer to a single layer, providing pre-populated set of query attribute names. */ - void apply(mapnik::layer const& lyr, std::set& names) - { - Processor & p = static_cast(*this); - p.start_map_processing(m_); - try - { - projection proj(m_.srs()); - double scale_denom = mapnik::scale_denominator(m_,proj.is_geographic()); - scale_denom *= scale_factor_; - - if (lyr.isVisible(scale_denom)) - { - apply_to_layer(lyr, p, proj, scale_denom, names); - } - } - catch (proj_init_error& ex) - { - std::clog << "proj_init_error:" << ex.what() << "\n"; - } - p.end_map_processing(m_); - } + void apply(mapnik::layer const& lyr, std::set& names); private: /*! * @return initialize metawriters for a given map and projection. */ - void start_metawriters(Map const& m_, projection const& proj) - { - Map::const_metawriter_iterator metaItr = m_.begin_metawriters(); - Map::const_metawriter_iterator metaItrEnd = m_.end_metawriters(); - for (;metaItr!=metaItrEnd; ++metaItr) - { - metaItr->second->set_size(m_.width(), m_.height()); - metaItr->second->set_map_srs(proj); - metaItr->second->start(m_.metawriter_output_properties); - } - } + void start_metawriters(Map const& m_, projection const& proj); /*! * @return stop metawriters that were previously initialized. */ - void stop_metawriters(Map const& m_) - { - Map::const_metawriter_iterator metaItr = m_.begin_metawriters(); - Map::const_metawriter_iterator metaItrEnd = m_.end_metawriters(); - for (;metaItr!=metaItrEnd; ++metaItr) - { - metaItr->second->stop(); - } - } + void stop_metawriters(Map const& m_); /*! * @return render a layer given a projection and scale. @@ -182,272 +67,8 @@ private: void apply_to_layer(layer const& lay, Processor & p, projection const& proj0, double scale_denom, - std::set& names) - { -#ifdef MAPNIK_DEBUG - //wall_clock_progress_timer timer(clog, "end layer rendering: "); -#endif + std::set& names); - std::vector const& style_names = lay.styles(); - - unsigned int num_styles = style_names.size(); - if (!num_styles) - return; - - mapnik::datasource_ptr ds = lay.datasource(); - if (!ds) - { - std::clog << "WARNING: No datasource for layer '" << lay.name() << "'\n"; - return; - } - - p.start_layer_processing(lay); - - if (ds) - { - - projection proj1(lay.srs()); - proj_transform prj_trans(proj0,proj1); - - // todo: only display raster if src and dest proj are matched - // todo: add raster re-projection as an optional feature - if (ds->type() == datasource::Raster && !prj_trans.equal()) - { - std::clog << "WARNING: Map srs does not match layer srs, skipping raster layer '" << lay.name() - << "' as raster re-projection is not currently supported (http://trac.mapnik.org/ticket/663)\n" - << "map srs: '" << m_.srs() << "'\nlayer srs: '" << lay.srs() << "' \n"; - return; - } - - box2d map_ext = m_.get_buffered_extent(); - - // clip buffered extent by maximum extent, if supplied - boost::optional > const& maximum_extent = m_.maximum_extent(); - if (maximum_extent) { - map_ext.clip(*maximum_extent); - } - - box2d layer_ext = lay.envelope(); - - // first, try intersection of map extent forward projected into layer srs - if (prj_trans.forward(map_ext) && map_ext.intersects(layer_ext)) - { - layer_ext.clip(map_ext); - } - // if no intersection and projections are also equal, early return - else if (prj_trans.equal()) - { - return; - } - // next try intersection of layer extent back projected into map srs - else if (prj_trans.backward(layer_ext) && map_ext.intersects(layer_ext)) - { - layer_ext.clip(map_ext); - // forward project layer extent back into native projection - if (!prj_trans.forward(layer_ext)) - std::clog << "WARNING: layer " << lay.name() - << " extent " << layer_ext << " in map projection " - << " did not reproject properly back to layer projection\n"; - } - else - { - // if no intersection then nothing to do for layer - return; - } - - query::resolution_type res(m_.width()/m_.get_current_extent().width(), - m_.height()/m_.get_current_extent().height()); - query q(layer_ext,res,scale_denom); //BBOX query - - std::vector active_styles; - attribute_collector collector(names); - double filt_factor = 1; - directive_collector d_collector(&filt_factor); - - // iterate through all named styles collecting active styles and attribute names - BOOST_FOREACH(std::string const& style_name, style_names) - { - boost::optional style=m_.find_style(style_name); - if (!style) - { - std::clog << "WARNING: style '" << style_name << "' required for layer '" - << lay.name() << "' does not exist.\n"; - continue; - } - - const std::vector& rules=(*style).get_rules(); - bool active_rules=false; - - BOOST_FOREACH(rule const& r, rules) - { - if (r.active(scale_denom)) - { - active_rules = true; - if (ds->type() == datasource::Vector) - { - collector(r); - } - // TODO - in the future rasters should be able to be filtered. - } - } - if (active_rules) - { - active_styles.push_back(const_cast(&(*style))); - } - } - - // push all property names - BOOST_FOREACH(std::string const& name, names) - { - q.add_property_name(name); - } - - memory_datasource cache; - bool cache_features = lay.cache_features() && num_styles>1?true:false; - bool first = true; - - BOOST_FOREACH (feature_type_style * style, active_styles) - { - std::vector if_rules; - std::vector else_rules; - std::vector also_rules; - - std::vector const& rules=style->get_rules(); - - BOOST_FOREACH(rule const& r, rules) - { - if (r.active(scale_denom)) - { - if (r.has_else_filter()) - { - else_rules.push_back(const_cast(&r)); - } - else if (r.has_also_filter()) - { - also_rules.push_back(const_cast(&r)); - } - else - { - if_rules.push_back(const_cast(&r)); - } - - if ( (ds->type() == datasource::Raster) && - (ds->params().get("filter_factor",0.0) == 0.0) ) - { - rule::symbolizers const& symbols = r.get_symbolizers(); - rule::symbolizers::const_iterator symIter = symbols.begin(); - rule::symbolizers::const_iterator symEnd = symbols.end(); - while (symIter != symEnd) - { - // if multiple raster symbolizers, last will be respected - // should we warn or throw? - boost::apply_visitor(d_collector,*symIter++); - } - q.set_filter_factor(filt_factor); - } - } - } - - // process features - featureset_ptr fs; - if (first) - { - if (cache_features) - first = false; - fs = ds->features(q); - } - else - { - fs = cache.features(q); - } - - if (fs) - { - feature_ptr feature; - while ((feature = fs->next())) - { - bool do_else=true; - bool do_also=false; - - if (cache_features) - { - cache.push(feature); - } - - BOOST_FOREACH(rule * r, if_rules ) - { - expression_ptr const& expr=r->get_filter(); - value_type result = boost::apply_visitor(evaluate(*feature),*expr); - if (result.to_bool()) - { - 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. -#ifdef 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 ) - { - 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. -#ifdef 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 ) - { - 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. -#ifdef 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); - } - } - } - } - } - } - cache_features = false; - } - } - - p.end_layer_processing(lay); - } - Map const& m_; double scale_factor_; }; diff --git a/src/build.py b/src/build.py index 2aa9c20bb..3fe50d7bc 100644 --- a/src/build.py +++ b/src/build.py @@ -104,6 +104,7 @@ source = Split( box2d.cpp expression_string.cpp filter_factory.cpp + feature_style_processor.cpp feature_type_style.cpp font_engine_freetype.cpp font_set.cpp diff --git a/src/feature_style_processor.cpp b/src/feature_style_processor.cpp new file mode 100644 index 000000000..b59673c26 --- /dev/null +++ b/src/feature_style_processor.cpp @@ -0,0 +1,427 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 Artem Pavlenko + * + * 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 + * + *****************************************************************************/ +#include + +//mapnik +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef MAPNIK_DEBUG +//#include +#endif +// boost +#include +//stl +#include + +#if defined(HAVE_CAIRO) +#include +#endif + +namespace mapnik +{ + +/** Calls the renderer's process function, + * \param output Renderer + * \param f Feature to process + * \param prj_trans Projection + * \param sym Symbolizer object + */ +template +struct feature_style_processor::symbol_dispatch : public boost::static_visitor<> +{ + symbol_dispatch (Processor & output, + Feature const& f, + proj_transform const& prj_trans) + : output_(output), + f_(f), + prj_trans_(prj_trans) {} + + template + void operator () (T const& sym) const + { + output_.process(sym,f_,prj_trans_); + } + + Processor & output_; + Feature const& f_; + proj_transform const& prj_trans_; +}; + +template +feature_style_processor::feature_style_processor(Map const& m, double scale_factor) + : m_(m), scale_factor_(scale_factor) +{ +} + +template +void feature_style_processor::apply() +{ +#ifdef MAPNIK_DEBUG + //mapnik::wall_clock_progress_timer t(std::clog, "map rendering took: "); +#endif + Processor & p = static_cast(*this); + p.start_map_processing(m_); + + try + { + projection proj(m_.srs()); + + start_metawriters(m_,proj); + + double scale_denom = mapnik::scale_denominator(m_,proj.is_geographic()); + scale_denom *= scale_factor_; +#ifdef MAPNIK_DEBUG + std::clog << "scale denominator = " << scale_denom << "\n"; +#endif + BOOST_FOREACH ( layer const& lyr, m_.layers() ) + { + if (lyr.isVisible(scale_denom)) + { + std::set names; + apply_to_layer(lyr, p, proj, scale_denom, names); + } + } + + stop_metawriters(m_); + } + catch (proj_init_error& ex) + { + std::clog << "proj_init_error:" << ex.what() << "\n"; + } + + p.end_map_processing(m_); +} + +template +void feature_style_processor::apply(mapnik::layer const& lyr, std::set& names) +{ + Processor & p = static_cast(*this); + p.start_map_processing(m_); + try + { + projection proj(m_.srs()); + double scale_denom = mapnik::scale_denominator(m_,proj.is_geographic()); + scale_denom *= scale_factor_; + + if (lyr.isVisible(scale_denom)) + { + apply_to_layer(lyr, p, proj, scale_denom, names); + } + } + catch (proj_init_error& ex) + { + std::clog << "proj_init_error:" << ex.what() << "\n"; + } + p.end_map_processing(m_); +} + +template +void feature_style_processor::start_metawriters(Map const& m_, projection const& proj) +{ + Map::const_metawriter_iterator metaItr = m_.begin_metawriters(); + Map::const_metawriter_iterator metaItrEnd = m_.end_metawriters(); + for (;metaItr!=metaItrEnd; ++metaItr) + { + metaItr->second->set_size(m_.width(), m_.height()); + metaItr->second->set_map_srs(proj); + metaItr->second->start(m_.metawriter_output_properties); + } +} + +template +void feature_style_processor::stop_metawriters(Map const& m_) +{ + Map::const_metawriter_iterator metaItr = m_.begin_metawriters(); + Map::const_metawriter_iterator metaItrEnd = m_.end_metawriters(); + for (;metaItr!=metaItrEnd; ++metaItr) + { + metaItr->second->stop(); + } +} + +template +void feature_style_processor::apply_to_layer(layer const& lay, Processor & p, + projection const& proj0, + double scale_denom, + std::set& names) +{ +#ifdef MAPNIK_DEBUG + //wall_clock_progress_timer timer(clog, "end layer rendering: "); +#endif + + std::vector const& style_names = lay.styles(); + + unsigned int num_styles = style_names.size(); + if (!num_styles) + return; + + mapnik::datasource_ptr ds = lay.datasource(); + if (!ds) + { + std::clog << "WARNING: No datasource for layer '" << lay.name() << "'\n"; + return; + } + + p.start_layer_processing(lay); + + if (ds) + { + + projection proj1(lay.srs()); + proj_transform prj_trans(proj0,proj1); + + // todo: only display raster if src and dest proj are matched + // todo: add raster re-projection as an optional feature + if (ds->type() == datasource::Raster && !prj_trans.equal()) + { + std::clog << "WARNING: Map srs does not match layer srs, skipping raster layer '" << lay.name() + << "' as raster re-projection is not currently supported (http://trac.mapnik.org/ticket/663)\n" + << "map srs: '" << m_.srs() << "'\nlayer srs: '" << lay.srs() << "' \n"; + return; + } + + box2d map_ext = m_.get_buffered_extent(); + + // clip buffered extent by maximum extent, if supplied + boost::optional > const& maximum_extent = m_.maximum_extent(); + if (maximum_extent) { + map_ext.clip(*maximum_extent); + } + + box2d layer_ext = lay.envelope(); + + // first, try intersection of map extent forward projected into layer srs + if (prj_trans.forward(map_ext) && map_ext.intersects(layer_ext)) + { + layer_ext.clip(map_ext); + } + // if no intersection and projections are also equal, early return + else if (prj_trans.equal()) + { + return; + } + // next try intersection of layer extent back projected into map srs + else if (prj_trans.backward(layer_ext) && map_ext.intersects(layer_ext)) + { + layer_ext.clip(map_ext); + // forward project layer extent back into native projection + if (!prj_trans.forward(layer_ext)) + std::clog << "WARNING: layer " << lay.name() + << " extent " << layer_ext << " in map projection " + << " did not reproject properly back to layer projection\n"; + } + else + { + // if no intersection then nothing to do for layer + return; + } + + query::resolution_type res(m_.width()/m_.get_current_extent().width(), + m_.height()/m_.get_current_extent().height()); + query q(layer_ext,res,scale_denom); //BBOX query + + std::vector active_styles; + attribute_collector collector(names); + double filt_factor = 1; + directive_collector d_collector(&filt_factor); + + // iterate through all named styles collecting active styles and attribute names + BOOST_FOREACH(std::string const& style_name, style_names) + { + boost::optional style=m_.find_style(style_name); + if (!style) + { + std::clog << "WARNING: style '" << style_name << "' required for layer '" + << lay.name() << "' does not exist.\n"; + continue; + } + + const std::vector& rules=(*style).get_rules(); + bool active_rules=false; + + BOOST_FOREACH(rule const& r, rules) + { + if (r.active(scale_denom)) + { + active_rules = true; + if (ds->type() == datasource::Vector) + { + collector(r); + } + // TODO - in the future rasters should be able to be filtered. + } + } + if (active_rules) + { + active_styles.push_back(const_cast(&(*style))); + } + } + + // push all property names + BOOST_FOREACH(std::string const& name, names) + { + q.add_property_name(name); + } + + memory_datasource cache; + bool cache_features = lay.cache_features() && num_styles>1?true:false; + bool first = true; + + BOOST_FOREACH (feature_type_style * style, active_styles) + { + std::vector if_rules; + std::vector else_rules; + + std::vector const& rules=style->get_rules(); + + BOOST_FOREACH(rule const& r, rules) + { + if (r.active(scale_denom)) + { + if (r.has_else_filter()) + { + else_rules.push_back(const_cast(&r)); + } + else + { + if_rules.push_back(const_cast(&r)); + } + + if ( (ds->type() == datasource::Raster) && + (ds->params().get("filter_factor",0.0) == 0.0) ) + { + rule::symbolizers const& symbols = r.get_symbolizers(); + rule::symbolizers::const_iterator symIter = symbols.begin(); + rule::symbolizers::const_iterator symEnd = symbols.end(); + while (symIter != symEnd) + { + // if multiple raster symbolizers, last will be respected + // should we warn or throw? + boost::apply_visitor(d_collector,*symIter++); + } + q.set_filter_factor(filt_factor); + } + } + } + + // process features + featureset_ptr fs; + if (first) + { + if (cache_features) + first = false; + fs = ds->features(q); + } + else + { + fs = cache.features(q); + } + + if (fs) + { + feature_ptr feature; + while ((feature = fs->next())) + { + bool do_else=true; + + if (cache_features) + { + cache.push(feature); + } + + BOOST_FOREACH(rule * r, if_rules ) + { + expression_ptr const& expr=r->get_filter(); + value_type result = boost::apply_visitor(evaluate(*feature),*expr); + if (result.to_bool()) + { + do_else=false; + 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. +#ifdef 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 ) + { + 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. +#ifdef 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); + } + } + } + } + } + } + cache_features = false; + } + } + + p.end_layer_processing(lay); +} + +#if defined(HAVE_CAIRO) +template class feature_style_processor >; +template class feature_style_processor >; +#endif + +template class feature_style_processor >; +template class feature_style_processor >; + +} +