From efff5f0ef0000b38bfe9bd3ec770bac7e990dae8 Mon Sep 17 00:00:00 2001 From: Alexandre Bonnasseau Date: Mon, 29 Oct 2012 10:50:37 +0100 Subject: [PATCH] Issue #1545 - override buffer-size parameter at layer level - revised --- bindings/python/mapnik_layer.cpp | 34 ++++++++++++-- bindings/python/mapnik_python.cpp | 1 + .../mapnik/feature_style_processor_impl.hpp | 17 ++++++- include/mapnik/layer.hpp | 5 ++- src/agg/agg_renderer.cpp | 10 ----- src/grid/grid_renderer.cpp | 10 ----- src/layer.cpp | 13 ++++-- src/save_map.cpp | 4 +- .../good_maps/layer_buffer_size_reduction.xml | 33 ++++++++++++++ .../mapnik-layer-buffer-size-cairo.png | Bin 0 -> 2425 bytes .../support/mapnik-layer-buffer-size.png | Bin 0 -> 2666 bytes tests/python_tests/layer_buffer_size_test.py | 42 ++++++++++++++++++ tests/python_tests/layer_test.py | 2 +- 13 files changed, 136 insertions(+), 35 deletions(-) create mode 100644 tests/data/good_maps/layer_buffer_size_reduction.xml create mode 100644 tests/python_tests/images/support/mapnik-layer-buffer-size-cairo.png create mode 100644 tests/python_tests/images/support/mapnik-layer-buffer-size.png create mode 100644 tests/python_tests/layer_buffer_size_test.py diff --git a/bindings/python/mapnik_layer.cpp b/bindings/python/mapnik_layer.cpp index 04f442508..f0d28cc28 100644 --- a/bindings/python/mapnik_layer.cpp +++ b/bindings/python/mapnik_layer.cpp @@ -103,6 +103,31 @@ void set_maximum_extent(mapnik::layer & l, boost::optional } } +void set_buffer_size(mapnik::layer & l, boost::optional const& buffer_size) +{ + if (buffer_size) + { + l.set_buffer_size(*buffer_size); + } + else + { + l.reset_buffer_size(); + } +} + +PyObject * get_buffer_size(mapnik::layer & l) +{ + boost::optional buffer_size = l.buffer_size(); + if (buffer_size) + { + return PyInt_FromLong(*buffer_size); + } + else + { + Py_RETURN_NONE; + } +} + void export_layer() { using namespace boost::python; @@ -224,17 +249,18 @@ void export_layer() ) .add_property("buffer_size", - &layer::buffer_size, - &layer::set_buffer_size, + &get_buffer_size, + &set_buffer_size, "Get/Set the size of buffer around layer in pixels.\n" "\n" "Usage:\n" - ">>> l.buffer_size\n" - "0 # zero by default\n" + ">>> print(l.buffer_size)\n" + "None # None by default\n" ">>> l.buffer_size = 2\n" ">>> l.buffer_size\n" "2\n" ) + .add_property("maximum_extent",make_function (&layer::maximum_extent,return_value_policy()), &set_maximum_extent, diff --git a/bindings/python/mapnik_python.cpp b/bindings/python/mapnik_python.cpp index 3f6e76daf..666a02292 100644 --- a/bindings/python/mapnik_python.cpp +++ b/bindings/python/mapnik_python.cpp @@ -736,6 +736,7 @@ BOOST_PYTHON_MODULE(_mapnik) python_optional(); python_optional(); python_optional(); + python_optional(); python_optional(); register_ptr_to_python(); register_ptr_to_python(); diff --git a/include/mapnik/feature_style_processor_impl.hpp b/include/mapnik/feature_style_processor_impl.hpp index 48a4e545e..345016426 100644 --- a/include/mapnik/feature_style_processor_impl.hpp +++ b/include/mapnik/feature_style_processor_impl.hpp @@ -239,7 +239,21 @@ void feature_style_processor::apply_to_layer(layer const& lay, Proces } #endif - box2d buffered_query_ext = m_.get_buffered_extent(); // buffered + + box2d query_ext = m_.get_current_extent(); // unbuffered + box2d buffered_query_ext(query_ext); // buffered + + boost::optional layer_buffer_size = lay.buffer_size(); + if (layer_buffer_size) // if layer overrides buffer size, use this value to compute buffered extent + { + double extra = 2.0 * m_.scale() * *layer_buffer_size; + buffered_query_ext.width(query_ext.width() + extra); + buffered_query_ext.height(query_ext.height() + extra); + } + else + { + buffered_query_ext = m_.get_buffered_extent(); + } // clip buffered extent by maximum extent, if supplied boost::optional > const& maximum_extent = m_.maximum_extent(); @@ -310,7 +324,6 @@ void feature_style_processor::apply_to_layer(layer const& lay, Proces // if we've got this far, now prepare the unbuffered extent // which is used as a bbox for clipping geometries - box2d query_ext = m_.get_current_extent(); // unbuffered if (maximum_extent) { query_ext.clip(*maximum_extent); diff --git a/include/mapnik/layer.hpp b/include/mapnik/layer.hpp index 78a17441c..c102b28f1 100644 --- a/include/mapnik/layer.hpp +++ b/include/mapnik/layer.hpp @@ -194,7 +194,8 @@ public: boost::optional > const& maximum_extent() const; void reset_maximum_extent(); void set_buffer_size(int size); - int buffer_size() const; + boost::optional const& buffer_size() const; + void reset_buffer_size(); ~layer(); private: void swap(const layer& other); @@ -211,7 +212,7 @@ private: std::string group_by_; std::vector styles_; datasource_ptr ds_; - int buffer_size_; + boost::optional buffer_size_; boost::optional > maximum_extent_; }; } diff --git a/src/agg/agg_renderer.cpp b/src/agg/agg_renderer.cpp index b7642a7b3..61a43fce7 100644 --- a/src/agg/agg_renderer.cpp +++ b/src/agg/agg_renderer.cpp @@ -181,16 +181,6 @@ void agg_renderer::start_layer_processing(layer const& lay, box2d con } query_extent_ = query_extent; - int buffer_size = lay.buffer_size(); - if (buffer_size != 0 ) - { - double padding = buffer_size * (double)(query_extent.width()/pixmap_.width()); - double x0 = query_extent_.minx(); - double y0 = query_extent_.miny(); - double x1 = query_extent_.maxx(); - double y1 = query_extent_.maxy(); - query_extent_.init(x0 - padding, y0 - padding, x1 + padding , y1 + padding); - } boost::optional > const& maximum_extent = lay.maximum_extent(); if (maximum_extent) diff --git a/src/grid/grid_renderer.cpp b/src/grid/grid_renderer.cpp index 3cd8bf61a..3862dbfd9 100644 --- a/src/grid/grid_renderer.cpp +++ b/src/grid/grid_renderer.cpp @@ -104,16 +104,6 @@ void grid_renderer::start_layer_processing(layer const& lay, box2d co detector_->clear(); } query_extent_ = query_extent; - int buffer_size = lay.buffer_size(); - if (buffer_size != 0 ) - { - double padding = buffer_size * (double)(query_extent.width()/pixmap_.width()); - double x0 = query_extent_.minx(); - double y0 = query_extent_.miny(); - double x1 = query_extent_.maxx(); - double y1 = query_extent_.maxy(); - query_extent_.init(x0 - padding, y0 - padding, x1 + padding , y1 + padding); - } boost::optional > const& maximum_extent = lay.maximum_extent(); if (maximum_extent) diff --git a/src/layer.cpp b/src/layer.cpp index 44abff6fb..61739c7a7 100644 --- a/src/layer.cpp +++ b/src/layer.cpp @@ -42,8 +42,7 @@ layer::layer(std::string const& name, std::string const& srs) clear_label_cache_(false), cache_features_(false), group_by_(""), - ds_(), - buffer_size_(0) {} + ds_() {} layer::layer(const layer& rhs) : name_(rhs.name_), @@ -198,14 +197,20 @@ void layer::reset_maximum_extent() void layer::set_buffer_size(int size) { - buffer_size_ = size; + buffer_size_.reset(size); } -int layer::buffer_size() const +boost::optional const& layer::buffer_size() const { return buffer_size_; } +void layer::reset_buffer_size() +{ + buffer_size_.reset(); +} + + box2d layer::envelope() const { if (ds_) return ds_->envelope(); diff --git a/src/save_map.cpp b/src/save_map.cpp index 55996e471..da2be65d4 100644 --- a/src/save_map.cpp +++ b/src/save_map.cpp @@ -750,10 +750,10 @@ void serialize_layer( ptree & map_node, const layer & layer, bool explicit_defau set_attr( layer_node, "group-by", layer.group_by() ); } - int buffer_size = layer.buffer_size(); + boost::optional const& buffer_size = layer.buffer_size(); if ( buffer_size || explicit_defaults) { - set_attr( layer_node, "buffer-size", buffer_size ); + set_attr( layer_node, "buffer-size", *buffer_size ); } optional > const& maximum_extent = layer.maximum_extent(); diff --git a/tests/data/good_maps/layer_buffer_size_reduction.xml b/tests/data/good_maps/layer_buffer_size_reduction.xml new file mode 100644 index 000000000..36d160afc --- /dev/null +++ b/tests/data/good_maps/layer_buffer_size_reduction.xml @@ -0,0 +1,33 @@ + + + + + point_style + + sqlite + ../sqlite/qgis_spatiallite.sqlite + point + + + + diff --git a/tests/python_tests/images/support/mapnik-layer-buffer-size-cairo.png b/tests/python_tests/images/support/mapnik-layer-buffer-size-cairo.png new file mode 100644 index 0000000000000000000000000000000000000000..c7899c16cfd72d0dbc6bcd8951c80aec373e0027 GIT binary patch literal 2425 zcmeAS@N?(olHy`uVBq!ia0y~yU;;9k7&t&wwUqN(AjOvC?e4-sxIm2!)o~--yR;Xi{GF4a{IvoCWd0;o&Qhoo>!5P^z2H#eOcLI z)8BD*zt4P~JuOYN=U_U60Xy^kf7)SdB5L2fIOi_E<54@a_Xe(G$_xfqGRnU7rOV5I z`u6|!s>l29{JL|w+luptYzb`+uoE!7?>htSwepgKVcEE;{fyZdp+`FHi ztxlH7yZiT4Q-33?B7?yR(f0lEpFdADJKZO}2o_sodzrX(X;`g@- z6@?fiQtb2#86O-{0c!Xey877uSj&I9I&zE+j(+zyRQ|c`8_d0fMXZbAfP(StW4s44 zOp2Qs3PAdvoGF!Fo`1{k*u#z1<>%tIr5*f!;1AF##!|JPPfSjZd3*os6{R(etO`I6 zUEKZ7ZfEZC82@G4?``s^PMF8Sz$V>mSNrelW%E4AA3r*0=l^~)Q(U}M@Ju_y0hu|o zWA?v)y4}w=_wRl6{`*D0)%D-}D}MVF6h4ptGai`ZduGnOTc3YDv(5kWTEBVT?3n*| zn|Jfw{r=!h>gwrr(md)62Fp5U220!5l;2&*oLz6T<=6Ga>Ff99r9Hm#W!hW!cRSBt zuiK%)!Qe3EJOjfb76t{cQED^@MpFT`GQunUiUkXEdUL9UfNd!TPgg&ebxsLQ0JYjD A4FCWD literal 0 HcmV?d00001 diff --git a/tests/python_tests/images/support/mapnik-layer-buffer-size.png b/tests/python_tests/images/support/mapnik-layer-buffer-size.png new file mode 100644 index 0000000000000000000000000000000000000000..6d53eecef73c3cae024b7dac57747e28c19b04ea GIT binary patch literal 2666 zcmeAS@N?(olHy`uVBq!ia0y~yU;;9k7&zE~)R&4YzZe*}3_V>OLn`LHz3YGCKC{e$ zkLgE!voB9d?QCvt?L6V?7c<44J!p;!JG&}h@r};I8hukVJA=w@R&6tjK0nJhs>?Sz z_*Re1l4CM$Za-gDUeinZ`rFoi->bh?d*01I|MK&{y5C=apUeIIVl^W}#!TsI28IXw z)fpHRJQx@pCNMBGC@?ZGI07Bj#KOS9!pXqEA;iESpfajpG#p0L!?4L0KgwlnEYIl6 z$k+2d$me88NE5qv*LY6Vhm8;0rSoO$qIYIVJbTtwy!txN^89_Z79T%6K0I$NyW4z0 z3x5WN)7zf^{d;)(_dE7H+F?4ff9pRTSDntcT&|+z#@@ddUKl&iWnh?=djIxrpaFXO zUp)N3I)2@rQ@0r;W->4=GdufHobkhd1%`%|IsZSLe)wir_A;w~;(sa*>w4RZ$yAGL z2r(Q8v8(>~G*$LLw_V-SwHM19l^7X(az4KN|9tD~G$DrcYxxqj@*s6b#O~d+o&31| z;JMg#_xqe#EDQ!4{o`tKmoXMR__}uSdlpkBh8Z_Ls?VRB$sluYN9C8f3)~nOgss0_ zIX08+!1CE~vbE|f1cB!8?cI{PjB&&Nvu|OV?tTAu)`X$#jjh!$zW`;1hLf@uhJQ-# z{+cQC|NZ+N*?($51!l12mY=;h_x!uRDfdh40-(TU%Zj3x{x#Ez|LouW`Q69w4H`g~ z=YHJ0FMa*KvQ>}kpZ%KMHg|Vl&pzf5V5mnf>tr}Ce@vaBA@%mhgU=6(``Z}*sk?cq zTkany=-ubvGXcd>ZQ2T9h687G?5^s|{m6e;oAEMu|Ngj*WfprMZhQFpx1403&G$nF v`@i3KVa)V=w8S2*xkhX7k<^k|V9%KCq+9fZ$$uiS4awl?>gTe~DWM4fmcQ`6 literal 0 HcmV?d00001 diff --git a/tests/python_tests/layer_buffer_size_test.py b/tests/python_tests/layer_buffer_size_test.py new file mode 100644 index 000000000..4b6fb1ff4 --- /dev/null +++ b/tests/python_tests/layer_buffer_size_test.py @@ -0,0 +1,42 @@ +#coding=utf8 +import os +import mapnik +import cairo +from utilities import execution_path +from nose.tools import * + +def setup(): + # All of the paths used are relative, if we run the tests + # from another directory we need to chdir() + os.chdir(execution_path('.')) + +def test_layer_buffer_size_1(): + m = mapnik.Map(512,512) + mapnik.load_map(m,'../data/good_maps/layer_buffer_size_reduction.xml') + m.zoom_all() + im = mapnik.Image(m.width,m.height) + mapnik.render(m,im) + actual = '/tmp/mapnik-layer-buffer-size.png' + expected = 'images/support/mapnik-layer-buffer-size.png' + im.save(actual) + expected_im = mapnik.Image.open(expected) + eq_(im.tostring(),expected_im.tostring(), 'failed comparing actual (%s) and expected (%s)' % (actual,'tests/python_tests/'+ expected)) + +def test_layer_buffer_size_2(): + actual = '/tmp/mapnik-layer-buffer-size-cairo.png' + expected = 'images/support/mapnik-layer-buffer-size-cairo.png' + m = mapnik.Map(512,512) + mapnik.load_map(m,'../data/good_maps/layer_buffer_size_reduction.xml') + m.zoom_all() + surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, m.width, m.height) + mapnik.render(m, surface) + surface.write_to_png(actual) + surface.finish() + expected_im = mapnik.Image.open(expected) + actual_im = mapnik.Image.open(actual) + eq_(actual_im.tostring(),expected_im.tostring(), 'failed comparing actual (%s) and expected (%s)' % (actual,'tests/python_tests/'+ expected)) + + +if __name__ == "__main__": + setup() + [eval(run)() for run in dir() if 'test_' in run] diff --git a/tests/python_tests/layer_test.py b/tests/python_tests/layer_test.py index 5e23fd684..e27d4b98f 100644 --- a/tests/python_tests/layer_test.py +++ b/tests/python_tests/layer_test.py @@ -20,7 +20,7 @@ def test_layer_init(): eq_(l.maxzoom > 1e+6,True) eq_(l.group_by,"") eq_(l.maximum_extent,None) - eq_(l.buffer_size,0.0) + eq_(l.buffer_size,None) eq_(len(l.styles),0) if __name__ == "__main__":