Skip to content
This repository

Issue #1545 - override buffer-size parameter at layer level - revised #1566

Closed
wants to merge 2 commits into from

2 participants

Bonnasseau Dane Springmeyer
Bonnasseau

No description provided.

Bonnasseau

This pull request is a correction of former one : #1545

Dane Springmeyer
Owner

Thanks. So, I need more time to review this. I'm not convinced that the layer object is the best spot for this parameter. I'd like to give thought to it being on a style. Thanks for your patience. I'll report back once I've had time to play with the patch.

Bonnasseau

Beware, if you link the buffer-size parameter to styles, it might not play well with cache-features.

Bonnasseau

Hello, did you manage to think about this ? Do you still think overinding of biuffer-size should be on a style ?

Dane Springmeyer
Owner

Thanks, merged! Apologies for the epic wait, patch was excellent. I touched up the tests a bit is all (preferred not to use pycairo since I rarely have it built).

PetrDlouhy PetrDlouhy referenced this pull request from a commit in PetrDlouhy/mapnik
Dane Springmeyer springmeyer Add layer buffer-size to changelog - refs #1566,#1545,#781 ecb9e59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
34 bindings/python/mapnik_layer.cpp
@@ -103,6 +103,31 @@ void set_maximum_extent(mapnik::layer & l, boost::optional<mapnik::box2d<double>
103 103 }
104 104 }
105 105
  106 +void set_buffer_size(mapnik::layer & l, boost::optional<int> const& buffer_size)
  107 +{
  108 + if (buffer_size)
  109 + {
  110 + l.set_buffer_size(*buffer_size);
  111 + }
  112 + else
  113 + {
  114 + l.reset_buffer_size();
  115 + }
  116 +}
  117 +
  118 +PyObject * get_buffer_size(mapnik::layer & l)
  119 +{
  120 + boost::optional<int> buffer_size = l.buffer_size();
  121 + if (buffer_size)
  122 + {
  123 + return PyInt_FromLong(*buffer_size);
  124 + }
  125 + else
  126 + {
  127 + Py_RETURN_NONE;
  128 + }
  129 +}
  130 +
106 131 void export_layer()
107 132 {
108 133 using namespace boost::python;
@@ -224,17 +249,18 @@ void export_layer()
224 249 )
225 250
226 251 .add_property("buffer_size",
227   - &layer::buffer_size,
228   - &layer::set_buffer_size,
  252 + &get_buffer_size,
  253 + &set_buffer_size,
229 254 "Get/Set the size of buffer around layer in pixels.\n"
230 255 "\n"
231 256 "Usage:\n"
232   - ">>> l.buffer_size\n"
233   - "0 # zero by default\n"
  257 + ">>> print(l.buffer_size)\n"
  258 + "None # None by default\n"
234 259 ">>> l.buffer_size = 2\n"
235 260 ">>> l.buffer_size\n"
236 261 "2\n"
237 262 )
  263 +
238 264 .add_property("maximum_extent",make_function
239 265 (&layer::maximum_extent,return_value_policy<copy_const_reference>()),
240 266 &set_maximum_extent,
1  bindings/python/mapnik_python.cpp
@@ -736,6 +736,7 @@ BOOST_PYTHON_MODULE(_mapnik)
736 736 python_optional<double>();
737 737 python_optional<float>();
738 738 python_optional<bool>();
  739 + python_optional<int>();
739 740 python_optional<mapnik::text_transform_e>();
740 741 register_ptr_to_python<mapnik::expression_ptr>();
741 742 register_ptr_to_python<mapnik::path_expression_ptr>();
17 include/mapnik/feature_style_processor_impl.hpp
@@ -239,7 +239,21 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
239 239 }
240 240 #endif
241 241
242   - box2d<double> buffered_query_ext = m_.get_buffered_extent(); // buffered
  242 +
  243 + box2d<double> query_ext = m_.get_current_extent(); // unbuffered
  244 + box2d<double> buffered_query_ext(query_ext); // buffered
  245 +
  246 + boost::optional<int> layer_buffer_size = lay.buffer_size();
  247 + if (layer_buffer_size) // if layer overrides buffer size, use this value to compute buffered extent
  248 + {
  249 + double extra = 2.0 * m_.scale() * *layer_buffer_size;
  250 + buffered_query_ext.width(query_ext.width() + extra);
  251 + buffered_query_ext.height(query_ext.height() + extra);
  252 + }
  253 + else
  254 + {
  255 + buffered_query_ext = m_.get_buffered_extent();
  256 + }
243 257
244 258 // clip buffered extent by maximum extent, if supplied
245 259 boost::optional<box2d<double> > const& maximum_extent = m_.maximum_extent();
@@ -310,7 +324,6 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
310 324
311 325 // if we've got this far, now prepare the unbuffered extent
312 326 // which is used as a bbox for clipping geometries
313   - box2d<double> query_ext = m_.get_current_extent(); // unbuffered
314 327 if (maximum_extent)
315 328 {
316 329 query_ext.clip(*maximum_extent);
5 include/mapnik/layer.hpp
@@ -194,7 +194,8 @@ class MAPNIK_DECL layer
194 194 boost::optional<box2d<double> > const& maximum_extent() const;
195 195 void reset_maximum_extent();
196 196 void set_buffer_size(int size);
197   - int buffer_size() const;
  197 + boost::optional<int> const& buffer_size() const;
  198 + void reset_buffer_size();
198 199 ~layer();
199 200 private:
200 201 void swap(const layer& other);
@@ -211,7 +212,7 @@ class MAPNIK_DECL layer
211 212 std::string group_by_;
212 213 std::vector<std::string> styles_;
213 214 datasource_ptr ds_;
214   - int buffer_size_;
  215 + boost::optional<int> buffer_size_;
215 216 boost::optional<box2d<double> > maximum_extent_;
216 217 };
217 218 }
10 src/agg/agg_renderer.cpp
@@ -181,16 +181,6 @@ void agg_renderer<T>::start_layer_processing(layer const& lay, box2d<double> con
181 181 }
182 182
183 183 query_extent_ = query_extent;
184   - int buffer_size = lay.buffer_size();
185   - if (buffer_size != 0 )
186   - {
187   - double padding = buffer_size * (double)(query_extent.width()/pixmap_.width());
188   - double x0 = query_extent_.minx();
189   - double y0 = query_extent_.miny();
190   - double x1 = query_extent_.maxx();
191   - double y1 = query_extent_.maxy();
192   - query_extent_.init(x0 - padding, y0 - padding, x1 + padding , y1 + padding);
193   - }
194 184
195 185 boost::optional<box2d<double> > const& maximum_extent = lay.maximum_extent();
196 186 if (maximum_extent)
10 src/grid/grid_renderer.cpp
@@ -104,16 +104,6 @@ void grid_renderer<T>::start_layer_processing(layer const& lay, box2d<double> co
104 104 detector_->clear();
105 105 }
106 106 query_extent_ = query_extent;
107   - int buffer_size = lay.buffer_size();
108   - if (buffer_size != 0 )
109   - {
110   - double padding = buffer_size * (double)(query_extent.width()/pixmap_.width());
111   - double x0 = query_extent_.minx();
112   - double y0 = query_extent_.miny();
113   - double x1 = query_extent_.maxx();
114   - double y1 = query_extent_.maxy();
115   - query_extent_.init(x0 - padding, y0 - padding, x1 + padding , y1 + padding);
116   - }
117 107
118 108 boost::optional<box2d<double> > const& maximum_extent = lay.maximum_extent();
119 109 if (maximum_extent)
13 src/layer.cpp
@@ -42,8 +42,7 @@ layer::layer(std::string const& name, std::string const& srs)
42 42 clear_label_cache_(false),
43 43 cache_features_(false),
44 44 group_by_(""),
45   - ds_(),
46   - buffer_size_(0) {}
  45 + ds_() {}
47 46
48 47 layer::layer(const layer& rhs)
49 48 : name_(rhs.name_),
@@ -198,14 +197,20 @@ void layer::reset_maximum_extent()
198 197
199 198 void layer::set_buffer_size(int size)
200 199 {
201   - buffer_size_ = size;
  200 + buffer_size_.reset(size);
202 201 }
203 202
204   -int layer::buffer_size() const
  203 +boost::optional<int> const& layer::buffer_size() const
205 204 {
206 205 return buffer_size_;
207 206 }
208 207
  208 +void layer::reset_buffer_size()
  209 +{
  210 + buffer_size_.reset();
  211 +}
  212 +
  213 +
209 214 box2d<double> layer::envelope() const
210 215 {
211 216 if (ds_) return ds_->envelope();
4 src/save_map.cpp
@@ -750,10 +750,10 @@ void serialize_layer( ptree & map_node, const layer & layer, bool explicit_defau
750 750 set_attr( layer_node, "group-by", layer.group_by() );
751 751 }
752 752
753   - int buffer_size = layer.buffer_size();
  753 + boost::optional<int> const& buffer_size = layer.buffer_size();
754 754 if ( buffer_size || explicit_defaults)
755 755 {
756   - set_attr( layer_node, "buffer-size", buffer_size );
  756 + set_attr( layer_node, "buffer-size", *buffer_size );
757 757 }
758 758
759 759 optional<box2d<double> > const& maximum_extent = layer.maximum_extent();
33 tests/data/good_maps/layer_buffer_size_reduction.xml
... ... @@ -0,0 +1,33 @@
  1 +<Map srs="+init=epsg:4326" background-color="lightsteelblue" >
  2 +<!--
  3 + XXX Difference entre rendu sous Debian et Ubuntu !!!!!!!!!!!!!!
  4 + <Style name="world_borders_style">
  5 + <Rule>
  6 + <PolygonSymbolizer fill="#f2eff9"/><LineSymbolizer stroke="rgb(50%,50%,50%)" stroke-width="0.1"/>
  7 + </Rule>
  8 + </Style>
  9 + <Layer name="world_borders2" srs="+init=epsg:4326">
  10 + <StyleName>world_borders_style</StyleName>
  11 + <Datasource>
  12 + <Parameter name="type">sqlite</Parameter>
  13 + <Parameter name="file">../sqlite/world.sqlite</Parameter>
  14 + <Parameter name="table">world_merc</Parameter>
  15 + </Datasource>
  16 + </Layer>
  17 + -->
  18 + <Style name="point_style">
  19 + <Rule>
  20 + <PointSymbolizer file="../svg/point_sm.svg"/>
  21 + <TextSymbolizer size="12" dy="-5" face-name="DejaVu Sans Book" halo-fill="rgba(255,255,255,.5)" halo-radius=".5">[name]</TextSymbolizer>
  22 + </Rule>
  23 + </Style>
  24 + <Layer name="point" srs="+init=epsg:4326" buffer-size="-150">
  25 + <StyleName>point_style</StyleName>
  26 + <Datasource>
  27 + <Parameter name="type">sqlite</Parameter>
  28 + <Parameter name="file">../sqlite/qgis_spatiallite.sqlite</Parameter>
  29 + <Parameter name="table">point</Parameter>
  30 + </Datasource>
  31 + </Layer>
  32 +
  33 +</Map>
BIN  tests/python_tests/images/support/mapnik-layer-buffer-size-cairo.png
BIN  tests/python_tests/images/support/mapnik-layer-buffer-size.png
42 tests/python_tests/layer_buffer_size_test.py
... ... @@ -0,0 +1,42 @@
  1 +#coding=utf8
  2 +import os
  3 +import mapnik
  4 +import cairo
  5 +from utilities import execution_path
  6 +from nose.tools import *
  7 +
  8 +def setup():
  9 + # All of the paths used are relative, if we run the tests
  10 + # from another directory we need to chdir()
  11 + os.chdir(execution_path('.'))
  12 +
  13 +def test_layer_buffer_size_1():
  14 + m = mapnik.Map(512,512)
  15 + mapnik.load_map(m,'../data/good_maps/layer_buffer_size_reduction.xml')
  16 + m.zoom_all()
  17 + im = mapnik.Image(m.width,m.height)
  18 + mapnik.render(m,im)
  19 + actual = '/tmp/mapnik-layer-buffer-size.png'
  20 + expected = 'images/support/mapnik-layer-buffer-size.png'
  21 + im.save(actual)
  22 + expected_im = mapnik.Image.open(expected)
  23 + eq_(im.tostring(),expected_im.tostring(), 'failed comparing actual (%s) and expected (%s)' % (actual,'tests/python_tests/'+ expected))
  24 +
  25 +def test_layer_buffer_size_2():
  26 + actual = '/tmp/mapnik-layer-buffer-size-cairo.png'
  27 + expected = 'images/support/mapnik-layer-buffer-size-cairo.png'
  28 + m = mapnik.Map(512,512)
  29 + mapnik.load_map(m,'../data/good_maps/layer_buffer_size_reduction.xml')
  30 + m.zoom_all()
  31 + surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, m.width, m.height)
  32 + mapnik.render(m, surface)
  33 + surface.write_to_png(actual)
  34 + surface.finish()
  35 + expected_im = mapnik.Image.open(expected)
  36 + actual_im = mapnik.Image.open(actual)
  37 + eq_(actual_im.tostring(),expected_im.tostring(), 'failed comparing actual (%s) and expected (%s)' % (actual,'tests/python_tests/'+ expected))
  38 +
  39 +
  40 +if __name__ == "__main__":
  41 + setup()
  42 + [eval(run)() for run in dir() if 'test_' in run]
2  tests/python_tests/layer_test.py
@@ -20,7 +20,7 @@ def test_layer_init():
20 20 eq_(l.maxzoom > 1e+6,True)
21 21 eq_(l.group_by,"")
22 22 eq_(l.maximum_extent,None)
23   - eq_(l.buffer_size,0.0)
  23 + eq_(l.buffer_size,None)
24 24 eq_(len(l.styles),0)
25 25
26 26 if __name__ == "__main__":

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.