start experimenting with making the rendering api less dependent on a complex map object and more driven by flexible arrays of styles and layers

This commit is contained in:
Dane Springmeyer 2013-07-16 14:40:10 -04:00
parent 72d88cfd79
commit 2406c0e79d
11 changed files with 86 additions and 336 deletions

View file

@ -34,7 +34,8 @@
#include <mapnik/projection.hpp>
#include <mapnik/ctrans.hpp>
#include <mapnik/feature_type_style.hpp>
//#include <mapnik/util/deepcopy.hpp>
#include <mapnik/scale_denominator.hpp>
#include <mapnik/util/map_query.hpp>
#include "mapnik_enumeration.hpp"
using mapnik::color;
@ -77,8 +78,7 @@ mapnik::featureset_ptr query_point(mapnik::Map const& m, int index, double x, do
PyErr_SetString(PyExc_IndexError, "Please provide a layer index >= 0");
boost::python::throw_error_already_set();
}
unsigned idx = index;
return m.query_point(idx, x, y);
return mapnik::util::query_point(m, static_cast<unsigned>(index), x, y);
}
mapnik::featureset_ptr query_map_point(mapnik::Map const& m, int index, double x, double y)
@ -87,8 +87,23 @@ mapnik::featureset_ptr query_map_point(mapnik::Map const& m, int index, double x
PyErr_SetString(PyExc_IndexError, "Please provide a layer index >= 0");
boost::python::throw_error_already_set();
}
unsigned idx = index;
return m.query_map_point(idx, x, y);
return mapnik::util::query_map_point(m, static_cast<unsigned>(index), x, y);
}
void zoom_all(mapnik::Map & m)
{
m.zoom_to_box(mapnik::util::get_extent(m));
}
mapnik::CoordTransform get_view_transform(mapnik::Map const& map)
{
return mapnik::CoordTransform(map.width(),map.height(),map.get_current_extent());
}
double get_scale_denominator(mapnik::Map const& map)
{
mapnik::projection map_proj(map.srs());
return mapnik::scale_denominator( map.scale(), map_proj.is_geographic());
}
// deepcopy
@ -337,14 +352,14 @@ void export_map()
">>> m.scale()\n"
)
.def("scale_denominator", &Map::scale_denominator,
.def("scale_denominator", get_scale_denominator,
"Return the Map Scale Denominator.\n"
"Usage:\n"
"\n"
">>> m.scale_denominator()\n"
)
.def("view_transform",&Map::view_transform,
.def("view_transform",get_view_transform,
"Return the map ViewTransform object\n"
"which is used internally to convert between\n"
"geographic coordinates and screen coordinates.\n"
@ -364,7 +379,7 @@ void export_map()
">>> m.zoom(0.25)\n"
)
.def("zoom_all",&Map::zoom_all,
.def("zoom_all",&zoom_all,
"Set the geographical extent of the map\n"
"to the combined extents of all active layers.\n"
"\n"

View file

@ -126,8 +126,7 @@ void render(const mapnik::Map& map,
{
python_unblock_auto_block b;
mapnik::agg_renderer<mapnik::image_32> ren(map,image,scale_factor,offset_x, offset_y);
ren.apply();
ren.apply(map.layers(),map.styles());
}
void render_with_detector(
@ -140,7 +139,7 @@ void render_with_detector(
{
python_unblock_auto_block b;
mapnik::agg_renderer<mapnik::image_32> ren(map,image,detector);
ren.apply();
ren.apply(map.layers(),map.styles());
}
void render_layer2(const mapnik::Map& map,
@ -160,7 +159,7 @@ void render_layer2(const mapnik::Map& map,
mapnik::layer const& layer = layers[layer_idx];
mapnik::agg_renderer<mapnik::image_32> ren(map,image,1.0,0,0);
std::set<std::string> names;
ren.apply(layer,names);
ren.apply(layer,map.styles(),names);
}
#if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO)
@ -174,7 +173,7 @@ void render3(const mapnik::Map& map,
python_unblock_auto_block b;
mapnik::cairo_surface_ptr surface(cairo_surface_reference(py_surface->surface), mapnik::cairo_surface_closer());
mapnik::cairo_renderer<mapnik::cairo_surface_ptr> ren(map,surface,scale_factor,offset_x,offset_y);
ren.apply();
ren.apply(map.layers(),map.styles());
}
void render4(const mapnik::Map& map, PycairoSurface* py_surface)
@ -182,7 +181,7 @@ void render4(const mapnik::Map& map, PycairoSurface* py_surface)
python_unblock_auto_block b;
mapnik::cairo_surface_ptr surface(cairo_surface_reference(py_surface->surface), mapnik::cairo_surface_closer());
mapnik::cairo_renderer<mapnik::cairo_surface_ptr> ren(map,surface);
ren.apply();
ren.apply(map.layers(),map.styles());
}
void render5(const mapnik::Map& map,
@ -194,7 +193,7 @@ void render5(const mapnik::Map& map,
python_unblock_auto_block b;
mapnik::cairo_ptr context(py_context->ctx, mapnik::cairo_closer());
mapnik::cairo_renderer<mapnik::cairo_ptr> ren(map,context,scale_factor,offset_x, offset_y);
ren.apply();
ren.apply(map.layers(),map.styles());
}
void render6(const mapnik::Map& map, PycairoContext* py_context)
@ -202,7 +201,7 @@ void render6(const mapnik::Map& map, PycairoContext* py_context)
python_unblock_auto_block b;
mapnik::cairo_ptr context(py_context->ctx, mapnik::cairo_closer());
mapnik::cairo_renderer<mapnik::cairo_ptr> ren(map,context);
ren.apply();
ren.apply(map.layers(),map.styles());
}
void render_with_detector2(
@ -213,7 +212,7 @@ void render_with_detector2(
python_unblock_auto_block b;
mapnik::cairo_ptr context(py_context->ctx, mapnik::cairo_closer());
mapnik::cairo_renderer<mapnik::cairo_ptr> ren(map,context,detector);
ren.apply();
ren.apply(map.layers(),map.styles());
}
void render_with_detector3(
@ -227,7 +226,7 @@ void render_with_detector3(
python_unblock_auto_block b;
mapnik::cairo_ptr context(py_context->ctx, mapnik::cairo_closer());
mapnik::cairo_renderer<mapnik::cairo_ptr> ren(map,context,detector,scale_factor,offset_x,offset_y);
ren.apply();
ren.apply(map.layers(),map.styles());
}
void render_with_detector4(
@ -238,7 +237,7 @@ void render_with_detector4(
python_unblock_auto_block b;
mapnik::cairo_surface_ptr surface(cairo_surface_reference(py_surface->surface), mapnik::cairo_surface_closer());
mapnik::cairo_renderer<mapnik::cairo_surface_ptr> ren(map, surface, detector);
ren.apply();
ren.apply(map.layers(),map.styles());
}
void render_with_detector5(
@ -252,7 +251,7 @@ void render_with_detector5(
python_unblock_auto_block b;
mapnik::cairo_surface_ptr surface(cairo_surface_reference(py_surface->surface), mapnik::cairo_surface_closer());
mapnik::cairo_renderer<mapnik::cairo_surface_ptr> ren(map, surface, detector, scale_factor, offset_x, offset_y);
ren.apply();
ren.apply(map.layers(),map.styles());
}
#endif

View file

@ -392,7 +392,7 @@ void render_layer_for_grid(mapnik::Map const& map,
mapnik::grid_renderer<mapnik::grid> ren(map,grid,1.0,0,0);
mapnik::layer const& layer = layers[layer_idx];
ren.apply(layer,attributes);
ren.apply(layer,map.styles(),attributes);
}
/* old, original impl - to be removed after further testing
@ -455,7 +455,7 @@ boost::python::dict render_grid(mapnik::Map const& map,
{
mapnik::grid_renderer<mapnik::grid> ren(map,grid,1.0,0,0);
mapnik::layer const& layer = layers[layer_idx];
ren.apply(layer,attributes);
ren.apply(layer,map.styles(),attributes);
}
catch (...)
{

View file

@ -262,7 +262,7 @@ int main ( int argc , char** argv)
image_32 buf(m.width(),m.height());
agg_renderer<image_32> ren(m,buf);
ren.apply();
ren.apply(m.layers(),m.styles());
save_to_file(buf,"demo.jpg","jpeg");
save_to_file(buf,"demo.png","png");
@ -294,7 +294,7 @@ int main ( int argc , char** argv)
double scale_factor = 1.0;
cairo_ptr image_context = (create_context(image_surface));
mapnik::cairo_renderer<cairo_ptr> png_render(m,image_context,scale_factor);
png_render.apply();
png_render.apply(m.layers(),m.styles());
// we can now write to png with cairo functionality
cairo_surface_write_to_png(&*image_surface, "cairo-demo.png");
// but we can also benefit from quantization by converting

View file

@ -19,7 +19,7 @@
// qt
#include <QtWidgets/QApplication>
#include <QApplication>
#include <QStringList>
#include <QSettings>
#include <mapnik/datasource_cache.hpp>

View file

@ -34,6 +34,7 @@
#include <mapnik/feature_kv_iterator.hpp>
#include <mapnik/config_error.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/util/map_query.hpp>
#ifdef HAVE_CAIRO
// cairo
@ -176,7 +177,7 @@ void MapWidget::mousePressEvent(QMouseEvent* e)
projection layer_proj(layer.srs());
mapnik::proj_transform prj_trans(map_proj,layer_proj);
//std::auto_ptr<mapnik::memory_datasource> data(new mapnik::memory_datasource);
mapnik::featureset_ptr fs = map_->query_map_point(index,x,y);
mapnik::featureset_ptr fs = mapnik::util::query_map_point(map,index,x,y);
if (fs)
{
@ -483,7 +484,7 @@ void MapWidget::export_to_file(unsigned ,unsigned ,std::string const&,std::strin
{
//image_32 image(width,height);
//agg_renderer renderer(map,image);
//renderer.apply();
//renderer.apply(map.layers(),map.styles());
//image.saveToFile(filename,type);
std::cout << "Export to file .." << std::endl;
}
@ -505,7 +506,7 @@ void render_agg(mapnik::Map const& map, double scaling_factor, QPixmap & pix)
{
{
boost::timer::auto_cpu_timer t;
ren.apply();
ren.apply(map.layers(),map.styles());
}
QImage image((uchar*)buf.raw_data(),width,height,QImage::Format_ARGB32);
pix = QPixmap::fromImage(image.rgbSwapped());
@ -538,7 +539,7 @@ void render_cairo(mapnik::Map const& map, double scaling_factor, QPixmap & pix)
mapnik::cairo_surface_ptr image_surface(cairo_image_surface_create(CAIRO_FORMAT_ARGB32,map.width(),map.height()),
mapnik::cairo_surface_closer());
mapnik::cairo_renderer<mapnik::cairo_surface_ptr> renderer(map, image_surface, scaling_factor);
renderer.apply();
renderer.apply(map.layers(),map.styles());
image_32 buf(image_surface);
QImage image((uchar*)buf.raw_data(),buf.width(),buf.height(),QImage::Format_ARGB32);
pix = QPixmap::fromImage(image.rgbSwapped());

View file

@ -59,18 +59,22 @@ public:
/*!
* \brief apply renderer to all map layers.
*/
void apply(double scale_denom_override=0.0);
void apply(std::vector<mapnik::layer> const& layers,
std::map<std::string,feature_type_style> const& styles,
double scale_denom_override=0.0);
/*!
* \brief apply renderer to a single layer, providing pre-populated set of query attribute names.
*/
void apply(mapnik::layer const& lyr,
std::map<std::string,feature_type_style> const& styles,
std::set<std::string>& names,
double scale_denom_override=0.0);
/*!
* \brief render a layer given a projection and scale.
*/
void apply_to_layer(layer const& lay,
std::map<std::string,feature_type_style> const& styles,
Processor & p,
projection const& proj0,
double scale,
@ -79,14 +83,14 @@ public:
unsigned height,
box2d<double> const& extent,
int buffer_size,
std::set<std::string>& names);
std::set<std::string>& names,
boost::optional<box2d<double> > const& maximum_extent);
private:
/*!
* \brief renders a featureset with the given styles.
*/
void render_style(layer const& lay,
Processor & p,
void render_style(Processor & p,
feature_type_style const* style,
rule_cache const& rules,
std::string const& style_name,

View file

@ -56,12 +56,6 @@
#include <vector>
#include <stdexcept>
#if defined(RENDERING_STATS)
#include <mapnik/timer.hpp>
#include <iomanip>
#include <sstream>
#endif
namespace mapnik
{
@ -150,13 +144,10 @@ feature_style_processor<Processor>::feature_style_processor(Map const& m, double
}
template <typename Processor>
void feature_style_processor<Processor>::apply(double scale_denom)
void feature_style_processor<Processor>::apply(std::vector<mapnik::layer> const& layers,
std::map<std::string,feature_type_style> const& styles,
double scale_denom)
{
#if defined(RENDERING_STATS)
std::clog << "\n//-- starting rendering timer...\n";
mapnik::progress_timer t(std::clog, "total map rendering");
#endif
Processor & p = static_cast<Processor&>(*this);
p.start_map_processing(m_);
@ -165,12 +156,13 @@ void feature_style_processor<Processor>::apply(double scale_denom)
scale_denom = mapnik::scale_denominator(m_.scale(),proj.is_geographic());
scale_denom *= scale_factor_;
BOOST_FOREACH ( layer const& lyr, m_.layers() )
BOOST_FOREACH ( layer const& lyr, layers )
{
if (lyr.visible(scale_denom))
{
std::set<std::string> names;
apply_to_layer(lyr,
styles,
p,
proj,
m_.scale(),
@ -179,22 +171,18 @@ void feature_style_processor<Processor>::apply(double scale_denom)
m_.height(),
m_.get_current_extent(),
m_.buffer_size(),
names);
names,
m_.maximum_extent());
}
}
p.end_map_processing(m_);
#if defined(RENDERING_STATS)
t.stop();
std::clog << "//-- rendering timer stopped...\n\n";
#endif
}
template <typename Processor>
void feature_style_processor<Processor>::apply(mapnik::layer const& lyr,
std::map<std::string,feature_type_style> const& styles,
std::set<std::string>& names,
double scale_denom)
{
@ -208,6 +196,7 @@ void feature_style_processor<Processor>::apply(mapnik::layer const& lyr,
if (lyr.visible(scale_denom))
{
apply_to_layer(lyr,
styles,
p,
proj,
m_.scale(),
@ -216,13 +205,16 @@ void feature_style_processor<Processor>::apply(mapnik::layer const& lyr,
m_.height(),
m_.get_current_extent(),
m_.buffer_size(),
names);
names,
m_.maximum_extent());
}
p.end_map_processing(m_);
}
template <typename Processor>
void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Processor & p,
void feature_style_processor<Processor>::apply_to_layer(layer const& lay,
std::map<std::string,feature_type_style> const& styles,
Processor & p,
projection const& proj0,
double scale,
double scale_denom,
@ -230,7 +222,8 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
unsigned height,
box2d<double> const& extent,
int buffer_size,
std::set<std::string>& names)
std::set<std::string>& names,
boost::optional<box2d<double> > const& maximum_extent)
{
std::vector<std::string> const& style_names = lay.styles();
@ -250,23 +243,9 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
return;
}
#if defined(RENDERING_STATS)
progress_timer layer_timer(std::clog, "rendering total for layer: '" + lay.name() + "'");
#endif
projection proj1(lay.srs(),true);
proj_transform prj_trans(proj0,proj1);
#if defined(RENDERING_STATS)
if (! prj_trans.equal())
{
std::clog << "notice: reprojecting layer: '" << lay.name() << "' from/to:\n\t'"
<< lay.srs() << "'\n\t'"
<< m_.srs() << "'\n";
}
#endif
box2d<double> query_ext = extent; // unbuffered
box2d<double> buffered_query_ext(query_ext); // buffered
@ -284,7 +263,6 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
buffered_query_ext.height(query_ext.height() + buffer_padding);
// clip buffered extent by maximum extent, if supplied
boost::optional<box2d<double> > const& maximum_extent = m_.maximum_extent();
if (maximum_extent) {
buffered_query_ext.clip(*maximum_extent);
}
@ -329,24 +307,23 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
// https://github.com/mapnik/mapnik/issues/1477
BOOST_FOREACH(std::string const& style_name, style_names)
{
boost::optional<feature_type_style const&> style=m_.find_style(style_name);
if (!style)
std::map<std::string,feature_type_style>::const_iterator itr = styles.find(style_name);
if (itr == styles.end())
{
continue;
}
if (style->comp_op() || style->image_filters().size() > 0)
feature_type_style const& style = itr->second;
if (style.comp_op() || style.image_filters().size() > 0)
{
if (style->active(scale_denom))
if (style.active(scale_denom))
{
// trigger any needed compositing ops
p.start_style_processing(*style);
p.end_style_processing(*style);
p.start_style_processing(style);
p.end_style_processing(style);
}
}
}
#if defined(RENDERING_STATS)
layer_timer.discard();
#endif
return;
}
@ -391,17 +368,16 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
// iterate through all named styles collecting active styles and attribute names
BOOST_FOREACH(std::string const& style_name, style_names)
{
boost::optional<feature_type_style const&> style=m_.find_style(style_name);
if (!style)
std::map<std::string,feature_type_style>::const_iterator itr = styles.find(style_name);
if (itr == styles.end())
{
MAPNIK_LOG_DEBUG(feature_style_processor)
<< "feature_style_processor: Style=" << style_name
<< " required for layer=" << lay.name() << " does not exist.";
continue;
}
std::vector<rule> const& rules = style->get_rules();
feature_type_style const& style = itr->second;
std::vector<rule> const& rules = style.get_rules();
bool active_rules = false;
std::auto_ptr<rule_cache> rc(new rule_cache);
BOOST_FOREACH(rule const& r, rules)
@ -420,7 +396,7 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
if (active_rules)
{
rule_caches.push_back(rc);
active_styles.push_back(&(*style));
active_styles.push_back(&style);
}
}
@ -491,7 +467,7 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
int i = 0;
BOOST_FOREACH (feature_type_style const* style, active_styles)
{
render_style(lay, p, style, rule_caches[i], style_names[i],
render_style(p, style, rule_caches[i], style_names[i],
cache.features(q), prj_trans);
i++;
}
@ -504,7 +480,7 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
int i = 0;
BOOST_FOREACH (feature_type_style const* style, active_styles)
{
render_style(lay, p, style, rule_caches[i], style_names[i],
render_style(p, style, rule_caches[i], style_names[i],
cache.features(q), prj_trans);
i++;
}
@ -525,7 +501,7 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
int i = 0;
BOOST_FOREACH (feature_type_style const* style, active_styles)
{
render_style(lay, p, style, rule_caches[i], style_names[i],
render_style(p, style, rule_caches[i], style_names[i],
cache.features(q), prj_trans);
i++;
}
@ -536,24 +512,19 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
int i = 0;
BOOST_FOREACH (feature_type_style const* style, active_styles)
{
render_style(lay, p, style, rule_caches[i], style_names[i],
render_style(p, style, rule_caches[i], style_names[i],
ds->features(q), prj_trans);
i++;
}
}
}
#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 const* style,
rule_cache const& rc,
@ -568,24 +539,9 @@ void feature_style_processor<Processor>::render_style(
return;
}
#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;
@ -595,10 +551,6 @@ void feature_style_processor<Processor>::render_style(
value_type result = boost::apply_visitor(evaluate<feature_impl,value_type>(*feature),*expr);
if (result.to_bool())
{
#if defined(RENDERING_STATS)
feat_processed = true;
#endif
p.painted(true);
do_else=false;
@ -627,10 +579,6 @@ void feature_style_processor<Processor>::render_style(
{
BOOST_FOREACH( rule const* r, rc.get_else_rules() )
{
#if defined(RENDERING_STATS)
feat_processed = true;
#endif
p.painted(true);
rule::symbolizers const& symbols = r->get_symbolizers();
@ -649,10 +597,6 @@ void feature_style_processor<Processor>::render_style(
{
BOOST_FOREACH( rule const* r, rc.get_also_rules() )
{
#if defined(RENDERING_STATS)
feat_processed = true;
#endif
p.painted(true);
rule::symbolizers const& symbols = r->get_symbolizers();
@ -667,32 +611,7 @@ void feature_style_processor<Processor>::render_style(
}
}
}
#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 '" << style_name << "'\n";
}
else
{
s << "" << std::setw(15) << "- no features returned from query for layer '" << lay.name() << "' and style '" << style_name << "'\n";
}
std::clog << s.str();
style_timer.discard();
#endif
p.end_style_processing(*style);
}

View file

@ -329,10 +329,6 @@ public:
*/
void zoom_to_box(box2d<double> const& box);
/*! \brief Zoom the map to show all data.
*/
void zoom_all();
void pan(int x,int y);
void pan_and_zoom(int x,int y,double zoom);
@ -352,36 +348,6 @@ public:
*/
double scale() const;
double scale_denominator() const;
CoordTransform view_transform() const;
/*!
* @brief Query a Map layer (by layer index) for features
*
* Intersecting the given x,y location in the coordinates
* of map projection.
*
* @param index The index of the layer to query from.
* @param x The x coordinate where to query.
* @param y The y coordinate where to query.
* @return A Mapnik Featureset if successful otherwise will return NULL.
*/
featureset_ptr query_point(unsigned index, double x, double y) const;
/*!
* @brief Query a Map layer (by layer index) for features
*
* Intersecting the given x,y location in the coordinates
* of the pixmap or map surface.
*
* @param index The index of the layer to query from.
* @param x The x coordinate where to query.
* @param y The y coordinate where to query.
* @return A Mapnik Featureset if successful otherwise will return NULL.
*/
featureset_ptr query_map_point(unsigned index, double x, double y) const;
~Map();
inline void set_aspect_fix_mode(aspect_fix_mode afm) { aspectFixMode_ = afm; }

View file

@ -468,7 +468,7 @@ void save_to_cairo_file(mapnik::Map const& map,
*/
mapnik::cairo_renderer<cairo_ptr> ren(map, create_context(surface), scale_factor);
ren.apply(scale_denominator);
ren.apply(map.layers(),map.styles(),scale_denominator);
if (type == "ARGB32" || type == "RGB24")
{

View file

@ -29,13 +29,8 @@
#include <mapnik/feature_type_style.hpp>
#include <mapnik/debug.hpp>
#include <mapnik/map.hpp>
#include <mapnik/datasource.hpp>
#include <mapnik/projection.hpp>
#include <mapnik/proj_transform.hpp>
#include <mapnik/ctrans.hpp>
#include <mapnik/filter_featureset.hpp>
#include <mapnik/hit_test_filter.hpp>
#include <mapnik/scale_denominator.hpp>
#include <mapnik/config_error.hpp>
#include <mapnik/config.hpp> // for PROJ_ENVELOPE_POINTS
@ -357,78 +352,6 @@ void Map::zoom(double factor)
fixAspectRatio();
}
void Map::zoom_all()
{
try
{
if (layers_.empty())
{
return;
}
projection proj0(srs_);
box2d<double> ext;
bool success = false;
bool first = true;
std::vector<layer>::const_iterator itr = layers_.begin();
std::vector<layer>::const_iterator end = layers_.end();
while (itr != end)
{
if (itr->active())
{
std::string const& layer_srs = itr->srs();
projection proj1(layer_srs);
proj_transform prj_trans(proj0,proj1);
box2d<double> layer_ext = itr->envelope();
if (prj_trans.backward(layer_ext, PROJ_ENVELOPE_POINTS))
{
success = true;
MAPNIK_LOG_DEBUG(map) << "map: Layer " << itr->name() << " original ext=" << itr->envelope();
MAPNIK_LOG_DEBUG(map) << "map: Layer " << itr->name() << " transformed to map srs=" << layer_ext;
if (first)
{
ext = layer_ext;
first = false;
}
else
{
ext.expand_to_include(layer_ext);
}
}
}
++itr;
}
if (success)
{
if (maximum_extent_) {
ext.clip(*maximum_extent_);
}
zoom_to_box(ext);
}
else
{
if (maximum_extent_)
{
MAPNIK_LOG_ERROR(map) << "could not zoom to combined layer extents"
<< " so falling back to maximum-extent for zoom_all result";
zoom_to_box(*maximum_extent_);
}
else
{
std::ostringstream s;
s << "could not zoom to combined layer extents "
<< "using zoom_all because proj4 could not "
<< "back project any layer extents into the map srs "
<< "(set map 'maximum-extent' to override layer extents)";
throw std::runtime_error(s.str());
}
}
}
catch (proj_init_error const& ex)
{
throw mapnik::config_error(std::string("Projection error during map.zoom_all: ") + ex.what());
}
}
void Map::zoom_to_box(box2d<double> const& box)
{
current_extent_=box;
@ -530,83 +453,6 @@ double Map::scale() const
return current_extent_.width();
}
double Map::scale_denominator() const
{
projection map_proj(srs_);
return mapnik::scale_denominator( scale(), map_proj.is_geographic());
}
CoordTransform Map::view_transform() const
{
return CoordTransform(width_,height_,current_extent_);
}
featureset_ptr Map::query_point(unsigned index, double x, double y) const
{
if (!current_extent_.valid())
{
throw std::runtime_error("query_point: map extent is not intialized, you need to set a valid extent before querying");
}
if (!current_extent_.intersects(x,y))
{
throw std::runtime_error("query_point: x,y coords do not intersect map extent");
}
if (index < layers_.size())
{
mapnik::layer const& layer = layers_[index];
mapnik::datasource_ptr ds = layer.datasource();
if (ds)
{
mapnik::projection dest(srs_);
mapnik::projection source(layer.srs());
proj_transform prj_trans(source,dest);
double z = 0;
if (!prj_trans.equal() && !prj_trans.backward(x,y,z))
{
throw std::runtime_error("query_point: could not project x,y into layer srs");
}
// calculate default tolerance
mapnik::box2d<double> map_ex = current_extent_;
if (maximum_extent_)
{
map_ex.clip(*maximum_extent_);
}
if (!prj_trans.backward(map_ex,PROJ_ENVELOPE_POINTS))
{
std::ostringstream s;
s << "query_point: could not project map extent '" << map_ex
<< "' into layer srs for tolerance calculation";
throw std::runtime_error(s.str());
}
double tol = (map_ex.maxx() - map_ex.minx()) / width_ * 3;
featureset_ptr fs = ds->features_at_point(mapnik::coord2d(x,y), tol);
MAPNIK_LOG_DEBUG(map) << "map: Query at point tol=" << tol << "(" << x << "," << y << ")";
if (fs)
{
return boost::make_shared<filter_featureset<hit_test_filter> >(fs,
hit_test_filter(x,y,tol));
}
}
}
else
{
std::ostringstream s;
s << "Invalid layer index passed to query_point: '" << index << "'";
if (!layers_.empty()) s << " for map with " << layers_.size() << " layers(s)";
else s << " (map has no layers)";
throw std::out_of_range(s.str());
}
return featureset_ptr();
}
featureset_ptr Map::query_map_point(unsigned index, double x, double y) const
{
CoordTransform tr = view_transform();
tr.backward(&x,&y);
return query_point(index,x,y);
}
parameters const& Map::get_extra_parameters() const
{
return extra_params_;