Issue #1545 - override buffer-size parameter at layer level - revised
This commit is contained in:
parent
2d0bd726c3
commit
efff5f0ef0
13 changed files with 136 additions and 35 deletions
|
@ -103,6 +103,31 @@ void set_maximum_extent(mapnik::layer & l, boost::optional<mapnik::box2d<double>
|
|||
}
|
||||
}
|
||||
|
||||
void set_buffer_size(mapnik::layer & l, boost::optional<int> 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<int> 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<copy_const_reference>()),
|
||||
&set_maximum_extent,
|
||||
|
|
|
@ -736,6 +736,7 @@ BOOST_PYTHON_MODULE(_mapnik)
|
|||
python_optional<double>();
|
||||
python_optional<float>();
|
||||
python_optional<bool>();
|
||||
python_optional<int>();
|
||||
python_optional<mapnik::text_transform_e>();
|
||||
register_ptr_to_python<mapnik::expression_ptr>();
|
||||
register_ptr_to_python<mapnik::path_expression_ptr>();
|
||||
|
|
|
@ -239,7 +239,21 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
|
|||
}
|
||||
#endif
|
||||
|
||||
box2d<double> buffered_query_ext = m_.get_buffered_extent(); // buffered
|
||||
|
||||
box2d<double> query_ext = m_.get_current_extent(); // unbuffered
|
||||
box2d<double> buffered_query_ext(query_ext); // buffered
|
||||
|
||||
boost::optional<int> 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<box2d<double> > const& maximum_extent = m_.maximum_extent();
|
||||
|
@ -310,7 +324,6 @@ void feature_style_processor<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<double> query_ext = m_.get_current_extent(); // unbuffered
|
||||
if (maximum_extent)
|
||||
{
|
||||
query_ext.clip(*maximum_extent);
|
||||
|
|
|
@ -194,7 +194,8 @@ public:
|
|||
boost::optional<box2d<double> > const& maximum_extent() const;
|
||||
void reset_maximum_extent();
|
||||
void set_buffer_size(int size);
|
||||
int buffer_size() const;
|
||||
boost::optional<int> 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<std::string> styles_;
|
||||
datasource_ptr ds_;
|
||||
int buffer_size_;
|
||||
boost::optional<int> buffer_size_;
|
||||
boost::optional<box2d<double> > maximum_extent_;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -181,16 +181,6 @@ void agg_renderer<T>::start_layer_processing(layer const& lay, box2d<double> 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<box2d<double> > const& maximum_extent = lay.maximum_extent();
|
||||
if (maximum_extent)
|
||||
|
|
|
@ -104,16 +104,6 @@ void grid_renderer<T>::start_layer_processing(layer const& lay, box2d<double> 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<box2d<double> > const& maximum_extent = lay.maximum_extent();
|
||||
if (maximum_extent)
|
||||
|
|
|
@ -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<int> const& layer::buffer_size() const
|
||||
{
|
||||
return buffer_size_;
|
||||
}
|
||||
|
||||
void layer::reset_buffer_size()
|
||||
{
|
||||
buffer_size_.reset();
|
||||
}
|
||||
|
||||
|
||||
box2d<double> layer::envelope() const
|
||||
{
|
||||
if (ds_) return ds_->envelope();
|
||||
|
|
|
@ -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<int> 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<box2d<double> > const& maximum_extent = layer.maximum_extent();
|
||||
|
|
33
tests/data/good_maps/layer_buffer_size_reduction.xml
Normal file
33
tests/data/good_maps/layer_buffer_size_reduction.xml
Normal file
|
@ -0,0 +1,33 @@
|
|||
<Map srs="+init=epsg:4326" background-color="lightsteelblue" >
|
||||
<!--
|
||||
XXX Difference entre rendu sous Debian et Ubuntu !!!!!!!!!!!!!!
|
||||
<Style name="world_borders_style">
|
||||
<Rule>
|
||||
<PolygonSymbolizer fill="#f2eff9"/><LineSymbolizer stroke="rgb(50%,50%,50%)" stroke-width="0.1"/>
|
||||
</Rule>
|
||||
</Style>
|
||||
<Layer name="world_borders2" srs="+init=epsg:4326">
|
||||
<StyleName>world_borders_style</StyleName>
|
||||
<Datasource>
|
||||
<Parameter name="type">sqlite</Parameter>
|
||||
<Parameter name="file">../sqlite/world.sqlite</Parameter>
|
||||
<Parameter name="table">world_merc</Parameter>
|
||||
</Datasource>
|
||||
</Layer>
|
||||
-->
|
||||
<Style name="point_style">
|
||||
<Rule>
|
||||
<PointSymbolizer file="../svg/point_sm.svg"/>
|
||||
<TextSymbolizer size="12" dy="-5" face-name="DejaVu Sans Book" halo-fill="rgba(255,255,255,.5)" halo-radius=".5">[name]</TextSymbolizer>
|
||||
</Rule>
|
||||
</Style>
|
||||
<Layer name="point" srs="+init=epsg:4326" buffer-size="-150">
|
||||
<StyleName>point_style</StyleName>
|
||||
<Datasource>
|
||||
<Parameter name="type">sqlite</Parameter>
|
||||
<Parameter name="file">../sqlite/qgis_spatiallite.sqlite</Parameter>
|
||||
<Parameter name="table">point</Parameter>
|
||||
</Datasource>
|
||||
</Layer>
|
||||
|
||||
</Map>
|
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
BIN
tests/python_tests/images/support/mapnik-layer-buffer-size.png
Normal file
BIN
tests/python_tests/images/support/mapnik-layer-buffer-size.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
42
tests/python_tests/layer_buffer_size_test.py
Normal file
42
tests/python_tests/layer_buffer_size_test.py
Normal file
|
@ -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]
|
|
@ -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__":
|
||||
|
|
Loading…
Reference in a new issue