Merge commit '57aa6dd05230876bf7c022d3554436e4d35de77f' into harfbuzz

Conflicts:
	tests/visual_tests/test.py
This commit is contained in:
Hermann Kraus 2013-03-16 12:46:01 +01:00
commit df7c2b5c0e
211 changed files with 7348 additions and 1040 deletions

View file

@ -8,6 +8,19 @@ For a complete change history, see the git log.
## Future
- Enabled default input plugin directory and fonts path to be set inherited from environment settings in
python bindings to make it easier to run tests locally (#1594). New environment settings are:
- MAPNIK_INPUT_PLUGINS_DIRECTORY
- MAPNIK_FONT_DIRECTORY
- Added support for controlling rendering behavior of markers on multi-geometries `marker-multi-policy` (#1555,#1573)
- Added alternative PNG/ZLIB implementation (`miniz`) that can be enabled with `e=miniz` (#1554)
- Added support for setting zlib `Z_FIXED` strategy with format string: `png:z=fixed`
- Fixed handling of transparency level option in Octree-based PNG encoding (#1556)
- Faster rendering of rasters by reducing memory allocation of temporary buffers (#1516)
- Added ability to pass a pre-created collision detector to the cairo renderer (#1444)

View file

@ -1,3 +1,10 @@
UNAME := $(shell uname)
LINK_FIX=LD_LIBRARY_PATH
ifeq ($(UNAME), Darwin)
LINK_FIX=DYLD_LIBRARY_PATH
else
endif
all: mapnik
install:
@ -31,6 +38,14 @@ test:
@echo "*** Running python tests..."
@python tests/run_tests.py -q
test-local:
@echo "*** boostrapping local test environment..."
export ${LINK_FIX}=`pwd`/src:${${LINK_FIX}} && \
export PYTHONPATH=`pwd`/bindings/python/:${PYTHONPATH} && \
export MAPNIK_FONT_DIRECTORY=`pwd`/fonts/dejavu-fonts-ttf-2.33/ttf/ && \
export MAPNIK_INPUT_PLUGINS_DIRECTORY=`pwd`/plugins/input/ && \
make test
demo:
@echo "*** Running rundemo.cpp…"
cd demo/c++; ./rundemo `mapnik-config --prefix`/lib/mapnik

View file

@ -329,7 +329,7 @@ opts.AddVariables(
BoolVariable('RENDERING_STATS', 'Output rendering statistics during style processing', 'False'),
#BoolVariable('SVG_RENDERER', 'build support for native svg renderer', 'False'),
BoolVariable('SVG_RENDERER', 'build support for native svg renderer', 'False'),
# Variables for optional dependencies
('GEOS_CONFIG', 'The path to the geos-config executable.', 'geos-config'),
@ -430,7 +430,7 @@ pickle_store = [# Scons internal variables
'CAIROMM_LIBPATHS',
'CAIROMM_LINKFLAGS',
'CAIROMM_CPPPATHS',
#'SVG_RENDERER',
'SVG_RENDERER',
'SQLITE_LINKFLAGS',
'BOOST_LIB_VERSION_FROM_HEADER'
]
@ -1750,8 +1750,8 @@ if not HELP_REQUESTED:
# not currently maintained
# https://github.com/mapnik/mapnik/issues/1438
#if env['SVG_RENDERER']:
# SConscript('tests/cpp_tests/svg_renderer_tests/build.py')
if env['SVG_RENDERER']:
SConscript('tests/cpp_tests/svg_renderer_tests/build.py')
# install pkg-config script and mapnik-config script
SConscript('utils/mapnik-config/build.py')

View file

@ -67,7 +67,8 @@ def bootstrap_env():
bootstrap_env()
from _mapnik import *
from paths import inputpluginspath, fontscollectionpath
from paths import inputpluginspath
from paths import fontscollectionpath
import printing
printing.renderer = render
@ -991,20 +992,27 @@ class _TextSymbolizer(TextSymbolizer,_injector):
self.properties.wrap_width = wrap_width
def mapnik_version_from_string(version_string):
"""Return the Mapnik version from a string."""
n = version_string.split('.')
return (int(n[0]) * 100000) + (int(n[1]) * 100) + (int(n[2]));
def register_plugins(path=inputpluginspath):
def register_plugins(path=None):
"""Register plugins located by specified path"""
if not path:
if os.environ.has_key('MAPNIK_INPUT_PLUGINS_DIRECTORY'):
path = os.environ.get('MAPNIK_INPUT_PLUGINS_DIRECTORY')
else:
path = inputpluginspath
DatasourceCache.register_datasources(path)
def register_fonts(path=fontscollectionpath,valid_extensions=['.ttf','.otf','.ttc','.pfa','.pfb','.ttc','.dfont']):
def register_fonts(path=None,valid_extensions=['.ttf','.otf','.ttc','.pfa','.pfb','.ttc','.dfont']):
"""Recursively register fonts using path argument as base directory"""
if not path:
if os.environ.has_key('MAPNIK_FONT_DIRECTORY'):
path = os.environ.get('MAPNIK_FONT_DIRECTORY')
else:
path = fontscollectionpath
for dirpath, _, filenames in os.walk(path):
for filename in filenames:
if os.path.splitext(filename.lower())[1] in valid_extensions:

View file

@ -66,6 +66,7 @@ void export_grid()
.def("height",&mapnik::grid::height)
.def("view",&mapnik::grid::get_view)
.def("get_pixel",&get_pixel)
.def("clear",&mapnik::grid::clear)
.def("encode",encode,
( boost::python::arg("encoding")="utf", boost::python::arg("features")=true,boost::python::arg("resolution")=4 ),
"Encode the grid as as optimized json\n"

View file

@ -235,6 +235,7 @@ void export_image()
.def("demultiply",&image_32::demultiply)
.def("set_pixel",&set_pixel)
.def("get_pixel",&get_pixel)
.def("clear",&image_32::clear)
//TODO(haoyu) The method name 'tostring' might be confusing since they actually return bytes in Python 3
.def("tostring",&tostring1)

View file

@ -89,6 +89,12 @@ void export_markers_symbolizer()
.value("LINE_PLACEMENT",mapnik::MARKER_LINE_PLACEMENT)
;
mapnik::enumeration_<mapnik::marker_multi_policy_e>("marker_multi_policy")
.value("EACH",mapnik::MARKER_EACH_MULTI)
.value("WHOLE",mapnik::MARKER_WHOLE_MULTI)
.value("LARGEST",mapnik::MARKER_LARGEST_MULTI)
;
class_<markers_symbolizer>("MarkersSymbolizer",
init<>("Default Markers Symbolizer - circle"))
.def (init<mapnik::path_expression_ptr>("<path expression ptr>"))
@ -143,6 +149,10 @@ void export_markers_symbolizer()
&markers_symbolizer::get_marker_placement,
&markers_symbolizer::set_marker_placement,
"Set/get the marker placement")
.add_property("multi_policy",
&markers_symbolizer::get_marker_multi_policy,
&markers_symbolizer::set_marker_multi_policy,
"Set/get the marker multi geometry rendering policy")
.add_property("comp_op",
&markers_symbolizer::comp_op,
&markers_symbolizer::set_comp_op,

View file

@ -121,8 +121,7 @@ void grid2utf(T const& grid_type,
// start counting at utf8 codepoint 32, aka space character
boost::uint16_t codepoint = 32;
// TODO - use double?
unsigned array_size = static_cast<unsigned int>(grid_type.width()/resolution);
unsigned array_size = std::ceil(grid_type.width()/static_cast<float>(resolution));
for (unsigned y = 0; y < grid_type.height(); y=y+resolution)
{
boost::uint16_t idx = 0;

View file

@ -59,9 +59,18 @@ struct default_color_converter_impl< rgb_t, hsl_t >
bits32f temp_blue = channel_convert<bits32f>( get_color( src, blue_t() ));
bits32f hue, saturation, lightness;
bits32f min_color, max_color;
bits32f min_color = std::min( temp_red, std::min( temp_green, temp_blue ));
bits32f max_color = std::max( temp_red, std::max( temp_green, temp_blue ));
if( temp_red < temp_green )
{
min_color = std::min( temp_blue, temp_red );
max_color = std::max( temp_blue, temp_green );
}
else
{
min_color = std::min( temp_blue, temp_green );
max_color = std::max( temp_blue, temp_red );
}
if ( max_color - min_color < 0.001 )
{

View file

@ -62,11 +62,13 @@ struct default_color_converter_impl< rgb_t, hsv_t >
bits32f hue, saturation, value;
bits32f min_color, max_color;
if( temp_red < temp_green ) {
if( temp_red < temp_green )
{
min_color = std::min( temp_blue, temp_red );
max_color = std::max( temp_blue, temp_green );
}
else {
else
{
min_color = std::min( temp_blue, temp_green );
max_color = std::max( temp_blue, temp_red );
}

View file

@ -29,6 +29,7 @@ namespace agg
void rewind(unsigned) {}
unsigned vertex(double*, double*) { return path_cmd_stop; }
unsigned type() const { return 0; }
};
@ -64,6 +65,7 @@ namespace agg
}
unsigned vertex(double* x, double* y);
unsigned type() const { return m_source->type(); }
private:
// Prohibit copying

View file

@ -33,6 +33,7 @@ namespace agg
void rewind(unsigned path_id);
unsigned vertex(double* x, double* y);
unsigned type() const { return m_source->type(); }
private:
conv_adaptor_vpgen(const conv_adaptor_vpgen<VertexSource, VPGen>&);

View file

@ -51,6 +51,7 @@ namespace agg
double y1() const { return base_type::vpgen().y1(); }
double x2() const { return base_type::vpgen().x2(); }
double y2() const { return base_type::vpgen().y2(); }
unsigned type() const { return base_type::type(); }
private:
conv_clip_polygon(const conv_clip_polygon<VertexSource>&);

View file

@ -51,6 +51,7 @@ namespace agg
double y1() const { return base_type::vpgen().y1(); }
double x2() const { return base_type::vpgen().x2(); }
double y2() const { return base_type::vpgen().y2(); }
unsigned type() const { return base_type::type(); }
private:
conv_clip_polyline(const conv_clip_polyline<VertexSource>&);

View file

@ -42,6 +42,7 @@ namespace agg
void smooth_value(double v) { base_type::generator().smooth_value(v); }
double smooth_value() const { return base_type::generator().smooth_value(); }
unsigned type() const { return base_type::type(); }
private:
conv_smooth_poly1(const conv_smooth_poly1<VertexSource>&);
@ -64,6 +65,7 @@ namespace agg
void smooth_value(double v) { m_smooth.generator().smooth_value(v); }
double smooth_value() const { return m_smooth.generator().smooth_value(); }
unsigned type() const { return m_smooth.type(); }
private:
conv_smooth_poly1_curve(const conv_smooth_poly1_curve<VertexSource>&);

View file

@ -6,8 +6,8 @@ Import('env')
base = './mapnik/'
subdirs = ['','svg','wkt','grid','json','util','text','text/placements','text/formatting']
#if env['SVG_RENDERER']:
# subdirs.append('svg/output')
if env['SVG_RENDERER']:
subdirs.append('svg/output')
if 'install' in COMMAND_LINE_TARGETS:
for subdir in subdirs:

View file

@ -38,8 +38,27 @@ namespace mapnik
template <typename Transform, typename Geometry>
struct MAPNIK_DECL coord_transform
{
// SFINAE value_type detector
template <typename T>
struct void_type
{
typedef void type;
};
template <typename T, typename D, typename _ = void>
struct select_value_type
{
typedef D type;
};
template <typename T, typename D>
struct select_value_type<T, D, typename void_type<typename T::value_type>::type>
{
typedef typename T::value_type type;
};
typedef std::size_t size_type;
//typedef typename Geometry::value_type value_type;
typedef typename select_value_type<Geometry, void>::type value_type;
coord_transform(Transform const& t,
Geometry & geom,
@ -81,6 +100,11 @@ struct MAPNIK_DECL coord_transform
geom_.rewind(pos);
}
unsigned type() const
{
return static_cast<unsigned>(geom_.type());
}
Geometry const& geom() const
{
return geom_;

View file

@ -296,7 +296,6 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
{
if (style->active(scale_denom))
{
std::clog << "triggering\n";
// trigger any needed compositing ops
p.start_style_processing(*style);
p.end_style_processing(*style);
@ -459,7 +458,7 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
}
else if (cache_features)
{
memory_datasource cache;
memory_datasource cache(ds->type());
featureset_ptr features = ds->features(q);
if (features) {
// Cache all features into the memory_datasource before rendering.

View file

@ -329,6 +329,70 @@ bool centroid(PathType & path, double & x, double & y)
return true;
}
// Compute centroid over a set of paths
template <typename Iter>
bool centroid_geoms(Iter start, Iter end, double & x, double & y)
{
double x0 = 0.0;
double y0 = 0.0;
double x1 = 0.0;
double y1 = 0.0;
double start_x = x0;
double start_y = y0;
bool empty = true;
double atmp = 0.0;
double xtmp = 0.0;
double ytmp = 0.0;
unsigned count = 1;
while (start!=end)
{
typename Iter::value_type & path = *start++;
path.rewind(0);
unsigned command = path.vertex(&x0, &y0);
if (command == SEG_END) continue;
empty = false;
while (SEG_END != (command = path.vertex(&x1, &y1)))
{
double dx0 = x0 - start_x;
double dy0 = y0 - start_y;
double dx1 = x1 - start_x;
double dy1 = y1 - start_y;
double ai = dx0 * dy1 - dx1 * dy0;
atmp += ai;
xtmp += (dx1 + dx0) * ai;
ytmp += (dy1 + dy0) * ai;
x0 = x1;
y0 = y1;
++count;
}
}
if ( empty ) return false;
if (count <= 2) {
x = (start_x + x0) * 0.5;
y = (start_y + y0) * 0.5;
return true;
}
if (atmp != 0)
{
x = (xtmp/(3*atmp)) + start_x;
y = (ytmp/(3*atmp)) + start_y;
}
else
{
x = x0;
y = y0;
}
return true;
}
template <typename PathType>
bool hit_test(PathType & path, double x, double y, double tol)
{

View file

@ -72,6 +72,11 @@ public:
return painted_;
}
inline void clear()
{
std::memset(data_.getData(),0,sizeof(mapnik::image_data_32::pixel_type)*data_.width()*data_.height());
}
boost::optional<color> const& get_background() const;
void set_background(const color& c);

View file

@ -82,6 +82,8 @@ public:
~hit_grid() {}
void clear();
inline void painted(bool painted)
{
painted_ = painted;

View file

@ -112,8 +112,6 @@
//convolve_rows_fixed<rgba32f_pixel_t>(src_view,kernel,src_view);
// convolve_cols_fixed<rgba32f_pixel_t>(src_view,kernel,dst_view);
using namespace boost::gil;
namespace mapnik { namespace filter { namespace detail {
static const float blur_matrix[] = {0.1111,0.1111,0.1111,0.1111,0.1111,0.1111,0.1111,0.1111,0.1111};
@ -123,12 +121,42 @@ static const float edge_detect_matrix[] = {0,1,0,1,-4,1,0,1,0 };
}
using boost::gil::rgba8_image_t;
using boost::gil::rgba8_view_t;
template <typename Image>
boost::gil::rgba8_view_t rgba8_view(Image & img)
{
using boost::gil::interleaved_view;
using boost::gil::rgba8_pixel_t;
return interleaved_view(img.width(), img.height(),
reinterpret_cast<rgba8_pixel_t*>(img.raw_data()),
img.width() * sizeof(rgba8_pixel_t));
}
template <typename Image>
struct double_buffer
{
boost::gil::rgba8_image_t dst_buffer;
boost::gil::rgba8_view_t dst_view;
boost::gil::rgba8_view_t src_view;
explicit double_buffer(Image & src)
: dst_buffer(src.width(), src.height())
, dst_view(view(dst_buffer))
, src_view(rgba8_view(src)) {}
~double_buffer()
{
copy_pixels(dst_view, src_view);
}
};
template <typename Src, typename Dst, typename Conv>
void process_channel_impl (Src const& src, Dst & dst, Conv const& k)
{
using namespace boost::gil;
typedef boost::gil::bits32f bits_type;
using boost::gil::bits32f;
bits32f out_value =
k[0]*src[0] + k[1]*src[1] + k[2]*src[2] +
k[3]*src[3] + k[4]*src[4] + k[5]*src[5] +
@ -175,8 +203,7 @@ void process_channel (Src const& src, Dst & dst, mapnik::filter::edge_detect)
template <typename Src, typename Dst>
void process_channel (Src const& src, Dst & dst, mapnik::filter::sobel)
{
using namespace boost::gil;
typedef boost::gil::bits32f bits_type;
using boost::gil::bits32f;
bits32f x_gradient = (src[2] + 2*src[5] + src[8])
- (src[0] + 2*src[3] + src[6]);
@ -193,9 +220,12 @@ void process_channel (Src const& src, Dst & dst, mapnik::filter::sobel)
template <typename Src, typename Dst, typename FilterTag>
void apply_convolution_3x3(Src const& src_view, Dst & dst_view, FilterTag filter_tag)
template <typename Src, typename Dst, typename Filter>
void apply_convolution_3x3(Src const& src_view, Dst & dst_view, Filter const& filter)
{
using boost::gil::bits32f;
using boost::gil::point2;
// p0 p1 p2
// p3 p4 p5
// p6 p7 p8
@ -251,7 +281,7 @@ void apply_convolution_3x3(Src const& src_view, Dst & dst_view, FilterTag filter
p[1] = p[7];
p[2] = p[8];
process_channel(p, (*dst_it)[i], filter_tag);
process_channel(p, (*dst_it)[i], filter);
}
++src_loc.x();
++dst_it;
@ -298,7 +328,7 @@ void apply_convolution_3x3(Src const& src_view, Dst & dst_view, FilterTag filter
p[5] = src_loc[loc21][i];
p[8] = src_loc[loc22][i];
}
process_channel(p, (*dst_it)[i], filter_tag);
process_channel(p, (*dst_it)[i], filter);
}
++dst_it;
++src_loc.x();
@ -346,36 +376,18 @@ void apply_convolution_3x3(Src const& src_view, Dst & dst_view, FilterTag filter
p[7] = p[1];
p[8] = p[2];
process_channel(p, (*dst_it)[i], filter_tag);
process_channel(p, (*dst_it)[i], filter);
}
++src_loc.x();
++dst_it;
}
}
template <typename Src, typename Dst,typename FilterTag>
void apply_filter(Src const& src, Dst & dst, FilterTag filter_tag)
template <typename Src, typename Filter>
void apply_filter(Src & src, Filter const& filter)
{
using namespace boost::gil;
rgba8_view_t src_view = interleaved_view(src.width(),src.height(),
(rgba8_pixel_t*) src.raw_data(),
src.width()*4);
rgba8_view_t dst_view = interleaved_view(dst.width(),dst.height(),
(rgba8_pixel_t*) dst.raw_data(),
dst.width()*4);
apply_convolution_3x3(src_view,dst_view,filter_tag);
}
template <typename Src, typename FilterTag>
void apply_filter(Src & src, FilterTag filter_tag)
{
using namespace boost::gil;
rgba8_view_t src_view = interleaved_view(src.width(),src.height(),
(rgba8_pixel_t*) src.raw_data(),
src.width()*4);
rgba8_image_t temp_buffer(src_view.dimensions());
apply_convolution_3x3(src_view,boost::gil::view(temp_buffer), filter_tag);
boost::gil::copy_pixels(view(temp_buffer), src_view);
double_buffer<Src> tb(src);
apply_convolution_3x3(tb.src_view, tb.dst_view, filter);
}
template <typename Src>
@ -386,17 +398,26 @@ void apply_filter(Src & src, agg_stack_blur const& op)
agg::stack_blur_rgba32(pixf,op.rx,op.ry);
}
template <typename Src>
void apply_filter(Src & src, gray)
void apply_filter(Src & src, gray const& op)
{
using namespace boost::gil;
typedef pixel<channel_type<rgba8_view_t>::type, gray_layout_t> gray_pixel_t;
rgba8_view_t src_view = interleaved_view(src.width(),src.height(),
(rgba8_pixel_t*) src.raw_data(),
src.width()*4);
boost::gil::copy_and_convert_pixels(color_converted_view<gray_pixel_t>(src_view), src_view);
rgba8_view_t src_view = rgba8_view(src);
for (int y=0; y<src_view.height(); ++y)
{
rgba8_view_t::x_iterator src_it = src_view.row_begin(y);
for (int x=0; x<src_view.width(); ++x)
{
// formula taken from boost/gil/color_convert.hpp:rgb_to_luminance
uint8_t & r = get_color(src_it[x], red_t());
uint8_t & g = get_color(src_it[x], green_t());
uint8_t & b = get_color(src_it[x], blue_t());
uint8_t v = uint8_t((4915 * r + 9667 * g + 1802 * b + 8192) >> 14);
r = g = b = v;
}
}
}
template <typename Src, typename Dst>
@ -428,51 +449,41 @@ void x_gradient_impl(Src const& src_view, Dst const& dst_view)
}
template <typename Src>
void apply_filter(Src & src, x_gradient)
void apply_filter(Src & src, x_gradient const& op)
{
using namespace boost::gil;
rgba8_view_t src_view = interleaved_view(src.width(),src.height(),
(rgba8_pixel_t*) src.raw_data(),
src.width()*4);
rgba8_image_t temp_buffer(src_view.dimensions());
rgba8_view_t dst_view = view(temp_buffer);
x_gradient_impl(src_view, dst_view);
boost::gil::copy_pixels(view(temp_buffer), src_view);
double_buffer<Src> tb(src);
x_gradient_impl(tb.src_view, tb.dst_view);
}
template <typename Src>
void apply_filter(Src & src, y_gradient)
void apply_filter(Src & src, y_gradient const& op)
{
using namespace boost::gil;
rgba8_view_t src_view = interleaved_view(src.width(),src.height(),
(rgba8_pixel_t*) src.raw_data(),
src.width()*4);
rgba8_image_t temp_buffer(src_view.dimensions());
rgba8_view_t dst_view = view(temp_buffer);
x_gradient_impl(rotated90ccw_view(src_view), rotated90ccw_view(dst_view));
boost::gil::copy_pixels(view(temp_buffer), src_view);
double_buffer<Src> tb(src);
x_gradient_impl(rotated90ccw_view(tb.src_view),
rotated90ccw_view(tb.dst_view));
}
template <typename Src>
void apply_filter(Src & src, invert)
void apply_filter(Src & src, invert const& op)
{
using namespace boost::gil;
rgba8_view_t src_view = interleaved_view(src.width(),src.height(),
(rgba8_pixel_t*) src.raw_data(),
src.width()*4);
rgba8_view_t src_view = rgba8_view(src);
for (int y=0; y<src_view.height(); ++y)
{
rgba8_view_t::x_iterator src_itr = src_view.row_begin(y);
rgba8_view_t::x_iterator src_it = src_view.row_begin(y);
for (int x=0; x<src_view.width(); ++x)
{
get_color(src_itr[x],red_t()) = channel_invert(get_color(src_itr[x],red_t()));
get_color(src_itr[x],green_t()) = channel_invert(get_color(src_itr[x],green_t()));
get_color(src_itr[x],blue_t()) = channel_invert(get_color(src_itr[x],blue_t()));
get_color(src_itr[x],alpha_t()) = get_color(src_itr[x],alpha_t());
// we only work with premultiplied source,
// thus all color values must be <= alpha
uint8_t a = get_color(src_it[x], alpha_t());
uint8_t & r = get_color(src_it[x], red_t());
uint8_t & g = get_color(src_it[x], green_t());
uint8_t & b = get_color(src_it[x], blue_t());
r = a - r;
g = a - g;
b = a - b;
}
}
}
@ -484,9 +495,9 @@ struct filter_visitor : boost::static_visitor<void>
: src_(src) {}
template <typename T>
void operator () (T const& filter_tag)
void operator () (T const& filter)
{
apply_filter(src_,filter_tag);
apply_filter(src_, filter);
}
Src & src_;

View file

@ -91,7 +91,12 @@ struct vector_markers_rasterizer_dispatch
{
double x = 0;
double y = 0;
if (placement_method == MARKER_INTERIOR_PLACEMENT)
if (path.type() == LineString)
{
if (!label::middle_point(path, x, y))
return;
}
else if (placement_method == MARKER_INTERIOR_PLACEMENT)
{
if (!label::interior_position(path, x, y))
return;
@ -187,7 +192,12 @@ struct raster_markers_rasterizer_dispatch
{
double x = 0;
double y = 0;
if (placement_method == MARKER_INTERIOR_PLACEMENT)
if (path.type() == LineString)
{
if (!label::middle_point(path, x, y))
return;
}
else if (placement_method == MARKER_INTERIOR_PLACEMENT)
{
if (!label::interior_position(path, x, y))
return;
@ -398,6 +408,68 @@ void setup_transform_scaling(agg::trans_affine & tr, box2d<double> const& bbox,
}
}
// Apply markers to a feature with multiple geometries
template <typename Converter>
void apply_markers_multi(feature_impl & feature, Converter& converter, markers_symbolizer const& sym)
{
std::size_t geom_count = feature.paths().size();
if (geom_count == 1)
{
converter.apply(feature.paths()[0]);
}
else if (geom_count > 1)
{
marker_multi_policy_e multi_policy = sym.get_marker_multi_policy();
marker_placement_e placement = sym.get_marker_placement();
if (placement == MARKER_POINT_PLACEMENT &&
multi_policy == MARKER_WHOLE_MULTI)
{
double x, y;
if (label::centroid_geoms(feature.paths().begin(), feature.paths().end(), x, y))
{
geometry_type pt(Point);
pt.move_to(x, y);
// unset any clipping since we're now dealing with a point
converter.template unset<clip_poly_tag>();
converter.apply(pt);
}
}
else if ((placement == MARKER_POINT_PLACEMENT || placement == MARKER_INTERIOR_PLACEMENT) &&
multi_policy == MARKER_LARGEST_MULTI)
{
// Only apply to path with largest envelope area
// TODO: consider using true area for polygon types
double maxarea = 0;
geometry_type* largest = 0;
BOOST_FOREACH(geometry_type & geom, feature.paths())
{
const box2d<double>& env = geom.envelope();
double area = env.width() * env.height();
if (area > maxarea)
{
maxarea = area;
largest = &geom;
}
}
if (largest)
{
converter.apply(*largest);
}
}
else
{
if (multi_policy != MARKER_EACH_MULTI && placement != MARKER_POINT_PLACEMENT)
{
MAPNIK_LOG_WARN(marker_symbolizer) << "marker_multi_policy != 'each' has no effect with marker_placement != 'point'";
}
BOOST_FOREACH(geometry_type & path, feature.paths())
{
converter.apply(path);
}
}
}
}
}
#endif //MAPNIK_MARKER_HELPERS_HPP

View file

@ -60,19 +60,34 @@ public:
* converted to a positive value with similar magnitude, but
* choosen to optimize marker placement. 0 = no markers
*/
markers_placement(Locator &locator, box2d<double> const& size, agg::trans_affine const& tr, Detector &detector, double spacing, double max_error, bool allow_overlap)
markers_placement(Locator &locator,
box2d<double> const& size,
agg::trans_affine const& tr,
Detector &detector,
double spacing,
double max_error,
bool allow_overlap)
: locator_(locator),
size_(size),
tr_(tr),
detector_(detector),
max_error_(max_error),
allow_overlap_(allow_overlap)
allow_overlap_(allow_overlap),
marker_width_((size_ * tr_).width()),
done_(false),
last_x(.0),
last_y(.0),
next_x(.0),
next_y(.0),
error_(.0),
spacing_left_(.0),
marker_nr_(0)
{
marker_width_ = (size_ * tr_).width();
if (spacing >= 0)
{
spacing_ = spacing;
} else if (spacing < 0)
}
else if (spacing < 0)
{
spacing_ = find_optimal_spacing(-spacing);
}
@ -104,7 +119,10 @@ public:
*/
bool get_point(double & x, double & y, double & angle, bool add_to_detector = true)
{
if (done_) return false;
if (done_)
{
return false;
}
unsigned cmd;
/* This functions starts at the position of the previous marker,
walks along the path, counting how far it has to go in spacing_left.
@ -120,7 +138,8 @@ public:
{
//First marker
spacing_left_ = spacing_ / 2;
} else
}
else
{
spacing_left_ = spacing_;
}
@ -150,7 +169,7 @@ public:
double segment_length = std::sqrt(dx * dx + dy * dy);
if (segment_length <= spacing_left_)
{
//Segment is to short to place marker. Find next segment
//Segment is too short to place marker. Find next segment
spacing_left_ -= segment_length;
last_x = next_x;
last_y = next_y;
@ -178,7 +197,8 @@ public:
//Segment to short => Skip this segment
set_spacing_left(segment_length + marker_width_/2); //Only moves forward
continue;
} else if (segment_length - spacing_left_ < marker_width_/2)
}
else if (segment_length - spacing_left_ < marker_width_/2)
{
//Segment is long enough, but we are to close to the end
//Note: This function moves backwards. This could lead to an infinite
@ -187,7 +207,8 @@ public:
if (error_ == 0)
{
set_spacing_left(segment_length - marker_width_/2, true);
} else
}
else
{
//Skip this segment
set_spacing_left(segment_length + marker_width_/2); //Only moves forward
@ -217,13 +238,15 @@ private:
agg::trans_affine tr_;
Detector &detector_;
double spacing_;
double marker_width_;
double max_error_;
bool allow_overlap_;
double marker_width_;
bool done_;
double last_x, last_y;
double next_x, next_y;
double last_x;
double last_y;
double next_x;
double next_y;
/** If a marker could not be placed at the exact point where it should
* go the next marker's distance will be a bit lower. */
double error_;

View file

@ -46,6 +46,15 @@ enum marker_placement_enum {
DEFINE_ENUM( marker_placement_e, marker_placement_enum );
enum marker_multi_policy_enum {
MARKER_EACH_MULTI, // each component in a multi gets its marker
MARKER_WHOLE_MULTI, // consider all components of a multi as a whole
MARKER_LARGEST_MULTI, // only the largest component of a multi gets a marker
marker_multi_policy_enum_MAX
};
DEFINE_ENUM( marker_multi_policy_e, marker_multi_policy_enum );
struct MAPNIK_DECL markers_symbolizer :
public symbolizer_with_image, public symbolizer_base
{
@ -74,6 +83,8 @@ public:
boost::optional<stroke> get_stroke() const;
void set_marker_placement(marker_placement_e marker_p);
marker_placement_e get_marker_placement() const;
void set_marker_multi_policy(marker_multi_policy_e marker_p);
marker_multi_policy_e get_marker_multi_policy() const;
private:
expression_ptr width_;
expression_ptr height_;
@ -86,6 +97,7 @@ private:
boost::optional<float> opacity_;
boost::optional<stroke> stroke_;
marker_placement_e marker_p_;
marker_multi_policy_e marker_mp_;
};
}

View file

@ -36,7 +36,7 @@ class MAPNIK_DECL memory_datasource : public datasource
{
friend class memory_featureset;
public:
memory_datasource();
memory_datasource(datasource::datasource_t type=datasource::Vector);
virtual ~memory_datasource();
void push(feature_ptr feature);
datasource::datasource_t type() const;
@ -50,6 +50,7 @@ public:
private:
std::vector<feature_ptr> features_;
mapnik::layer_descriptor desc_;
datasource::datasource_t type_;
};
}

View file

@ -24,7 +24,6 @@
#define MAPNIK_MEMORY_FEATURESET_HPP
// mapnik
#include <mapnik/debug.hpp>
#include <mapnik/memory_datasource.hpp>
// boost
@ -38,13 +37,15 @@ public:
memory_featureset(box2d<double> const& bbox, memory_datasource const& ds)
: bbox_(bbox),
pos_(ds.features_.begin()),
end_(ds.features_.end())
end_(ds.features_.end()),
type_(ds.type())
{}
memory_featureset(box2d<double> const& bbox, std::vector<feature_ptr> const& features)
: bbox_(bbox),
pos_(features.begin()),
end_(features.end())
end_(features.end()),
type_(datasource::Vector)
{}
virtual ~memory_featureset() {}
@ -53,20 +54,23 @@ public:
{
while (pos_ != end_)
{
for (unsigned i=0; i<(*pos_)->num_geometries();++i)
if (type_ == datasource::Raster)
{
geometry_type & geom = (*pos_)->get_geometry(i);
MAPNIK_LOG_DEBUG(memory_featureset) << "memory_featureset: BBox=" << bbox_ << ",Envelope=" << geom.envelope();
if (bbox_.intersects(geom.envelope()))
return *pos_++;
}
else
{
for (unsigned i=0; i<(*pos_)->num_geometries();++i)
{
return *pos_++;
geometry_type & geom = (*pos_)->get_geometry(i);
if (bbox_.intersects(geom.envelope()))
{
return *pos_++;
}
}
}
++pos_;
}
return feature_ptr();
}
@ -74,6 +78,7 @@ private:
box2d<double> bbox_;
std::vector<feature_ptr>::const_iterator pos_;
std::vector<feature_ptr>::const_iterator end_;
datasource::datasource_t type_;
};
}

View file

@ -0,0 +1,83 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2012 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
*
*****************************************************************************/
#ifndef MAPNIK_MINIZ_PNG_HPP
#define MAPNIK_MINIZ_PNG_HPP
// mapnik
#include <mapnik/palette.hpp>
// stl
#include <vector>
#include <iostream>
#include <stdexcept>
/* miniz.c porting issues:
- duplicate symbols in python bindings require moving miniz.c include to just cpp file
- due to http://code.google.com/p/miniz/issues/detail?id=7
- avoiding including miniz.c here requires fwd declaring the two structs below
- being able to fwd declare requires removing typedef from struct declarations in miniz.c
- being able to fwd declare also requires using pointers to structs
*/
// TODO: try using #define MINIZ_HEADER_FILE_ONLY
struct tdefl_output_buffer;
struct tdefl_compressor;
namespace mapnik { namespace MiniZ {
using mapnik::rgb;
class PNGWriter {
public:
PNGWriter(int level, int strategy);
~PNGWriter();
private:
inline void writeUInt32BE(unsigned char *target, unsigned int value);
size_t startChunk(const unsigned char header[], size_t length);
void finishChunk(size_t start);
public:
void writeIHDR(unsigned int width, unsigned int height, unsigned char pixel_depth);
void writePLTE(std::vector<rgb> const& palette);
void writetRNS(std::vector<unsigned> const& alpha);
template<typename T>
void writeIDAT(T const& image);
template<typename T>
void writeIDATStripAlpha(T const& image);
void writeIEND();
void toStream(std::ostream& stream);
private:
tdefl_compressor *compressor;
tdefl_output_buffer *buffer;
static const unsigned char preamble[];
static const unsigned char IHDR_tpl[];
static const unsigned char PLTE_tpl[];
static const unsigned char tRNS_tpl[];
static const unsigned char IDAT_tpl[];
static const unsigned char IEND_tpl[];
};
}}
#endif // MAPNIK_MINIZ_PNG_HPP

View file

@ -56,7 +56,7 @@ class octree : private boost::noncopyable
{
struct node
{
node ()
node()
: reds(0),
greens(0),
blues(0),
@ -68,14 +68,22 @@ class octree : private boost::noncopyable
memset(&children_[0],0,sizeof(children_));
}
~node ()
~node()
{
for (unsigned i = 0;i < 8; ++i) {
if (children_[i] != 0) delete children_[i],children_[i]=0;
for (unsigned i = 0;i < 8; ++i)
{
if (children_[i] != 0)
{
delete children_[i];
children_[i]=0;
}
}
}
bool is_leaf() const { return count == 0; }
bool is_leaf() const
{
return count == 0;
}
node * children_[8];
boost::uint64_t reds;
boost::uint64_t greens;
@ -83,8 +91,8 @@ class octree : private boost::noncopyable
unsigned count;
double reduce_cost;
unsigned count_cum;
byte children_count;
byte index;
byte children_count;
byte index;
};
struct node_cmp
{
@ -99,7 +107,6 @@ class octree : private boost::noncopyable
unsigned colors_;
unsigned offset_;
unsigned leaf_level_;
bool has_alfa_;
public:
explicit octree(unsigned max_colors=256)
@ -107,11 +114,13 @@ public:
colors_(0),
offset_(0),
leaf_level_(InsertPolicy::MAX_LEVELS),
has_alfa_(false),
root_(new node())
{}
~octree() { delete root_;}
~octree()
{
delete root_;
}
unsigned colors()
{
@ -133,21 +142,12 @@ public:
return offset_;
}
void hasAlfa(bool v)
{
has_alfa_=v;
}
bool hasAlfa()
{
return has_alfa_;
}
void insert(T const& data)
{
unsigned level = 0;
node * cur_node = root_;
while (true) {
while (true)
{
cur_node->count_cum++;
cur_node->reds += data.r;
cur_node->greens += data.g;
@ -163,7 +163,8 @@ public:
}
unsigned idx = InsertPolicy::index_from_level(level,data);
if (cur_node->children_[idx] == 0) {
if (cur_node->children_[idx] == 0)
{
cur_node->children_count++;
cur_node->children_[idx] = new node();
if (level < leaf_level_-1)
@ -183,7 +184,9 @@ public:
while (cur_node)
{
if (cur_node->children_count == 0)
{
return cur_node->index + offset_;
}
unsigned idx = InsertPolicy::index_from_level(level,c);
cur_node = cur_node->children_[idx];
++level;
@ -193,11 +196,6 @@ public:
void create_palette(std::vector<rgb> & palette)
{
if (has_alfa_)
{
max_colors_--;
palette.push_back(rgb(0,0,0));
}
reduce();
palette.reserve(colors_);
create_palette(palette, root_);
@ -207,23 +205,26 @@ public:
{
r->reduce_cost = 0;
if (r->children_count==0)
{
return;
}
double mean_r = static_cast<double>(r->reds / r->count_cum);
double mean_g = static_cast<double>(r->greens / r->count_cum);
double mean_b = static_cast<double>(r->blues / r->count_cum);
for (unsigned idx=0; idx < 8; ++idx) if (r->children_[idx] != 0)
{
double dr,dg,db;
computeCost(r->children_[idx]);
dr = r->children_[idx]->reds / r->children_[idx]->count_cum - mean_r;
dg = r->children_[idx]->greens / r->children_[idx]->count_cum - mean_g;
db = r->children_[idx]->blues / r->children_[idx]->count_cum - mean_b;
r->reduce_cost += r->children_[idx]->reduce_cost;
r->reduce_cost += (dr*dr + dg*dg + db*db) * r->children_[idx]->count_cum;
}
for (unsigned idx=0; idx < 8; ++idx)
{
if (r->children_[idx] != 0)
{
double dr,dg,db;
computeCost(r->children_[idx]);
dr = r->children_[idx]->reds / r->children_[idx]->count_cum - mean_r;
dg = r->children_[idx]->greens / r->children_[idx]->count_cum - mean_g;
db = r->children_[idx]->blues / r->children_[idx]->count_cum - mean_b;
r->reduce_cost += r->children_[idx]->reduce_cost;
r->reduce_cost += (dr*dr + dg*dg + db*db) * r->children_[idx]->count_cum;
}
}
}
void reduce()
@ -236,30 +237,39 @@ public:
{
std::sort(reducible_[i].begin(), reducible_[i].end(),node_cmp());
}
while ( colors_ > max_colors_ && colors_ > 1)
while (colors_ > max_colors_ && colors_ > 1)
{
while (leaf_level_ >0 && reducible_[leaf_level_-1].size() == 0)
{
--leaf_level_;
}
if (leaf_level_ <= 0) return;
if (leaf_level_ <= 0)
{
return;
}
// select best of all reducible:
unsigned red_idx = leaf_level_-1;
unsigned bestv = (*reducible_[red_idx].begin())->reduce_cost;
for(unsigned i=red_idx; i>=InsertPolicy::MIN_LEVELS; i--) if (!reducible_[i].empty()){
for(unsigned i=red_idx; i>=InsertPolicy::MIN_LEVELS; i--)
{
if (!reducible_[i].empty())
{
node *nd = *reducible_[i].begin();
unsigned gch = 0;
for(unsigned idx=0; idx<8; idx++){
for(unsigned idx=0; idx<8; idx++)
{
if (nd->children_[idx])
gch += nd->children_[idx]->children_count;
}
if (gch==0 && nd->reduce_cost < bestv){
if (gch==0 && nd->reduce_cost < bestv)
{
bestv = static_cast<unsigned>(nd->reduce_cost);
red_idx = i;
}
}
}
typename std::deque<node*>::iterator pos = reducible_[red_idx].begin();
node * cur_node = *pos;
@ -297,7 +307,9 @@ public:
for (unsigned i=0; i < 8 ;++i)
{
if (itr->children_[i] != 0)
{
create_palette(palette, itr->children_[i]);
}
}
}
private:

View file

@ -137,8 +137,8 @@ public:
const std::vector<rgb>& palette() const;
const std::vector<unsigned>& alphaTable() const;
unsigned quantize(rgba const& c) const;
inline unsigned quantize(unsigned const& c) const
unsigned char quantize(rgba const& c) const;
inline unsigned char quantize(unsigned const& c) const
{
rgba_hash_table::const_iterator it = color_hashmap_.find(c);
if (it != color_hashmap_.end())

View file

@ -28,6 +28,7 @@
#include <mapnik/palette.hpp>
#include <mapnik/octree.hpp>
#include <mapnik/hextree.hpp>
#include <mapnik/miniz_png.hpp>
#include <mapnik/image_data.hpp>
// zlib
#include <zlib.h>
@ -56,8 +57,32 @@ void flush_data (png_structp png_ptr)
}
template <typename T1, typename T2>
void save_as_png(T1 & file , T2 const& image, int compression = Z_DEFAULT_COMPRESSION, int strategy = Z_DEFAULT_STRATEGY)
void save_as_png(T1 & file,
T2 const& image,
int compression = Z_DEFAULT_COMPRESSION,
int strategy = Z_DEFAULT_STRATEGY,
int trans_mode = -1,
bool use_miniz = false)
{
if (use_miniz)
{
MiniZ::PNGWriter writer(compression,strategy);
if (trans_mode == 0)
{
writer.writeIHDR(image.width(), image.height(), 24);
writer.writeIDATStripAlpha(image);
}
else
{
writer.writeIHDR(image.width(), image.height(), 32);
writer.writeIDAT(image);
}
writer.writeIEND();
writer.toStream(file);
return;
}
png_voidp error_ptr=0;
png_structp png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING,
error_ptr,0, 0);
@ -91,32 +116,35 @@ void save_as_png(T1 & file , T2 const& image, int compression = Z_DEFAULT_COMPRE
png_set_compression_buffer_size(png_ptr, 32768);
png_set_IHDR(png_ptr, info_ptr,image.width(),image.height(),8,
PNG_COLOR_TYPE_RGB_ALPHA,PNG_INTERLACE_NONE,
(trans_mode == 0) ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA,PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT);
png_write_info(png_ptr, info_ptr);
for (unsigned i=0;i<image.height();i++)
png_bytep row_pointers[image.height()];
for (unsigned int i = 0; i < image.height(); i++)
{
png_write_row(png_ptr,(png_bytep)image.getRow(i));
row_pointers[i] = (png_bytep)image.getRow(i);
}
png_write_end(png_ptr, info_ptr);
png_set_rows(png_ptr, info_ptr, (png_bytepp)&row_pointers);
png_write_png(png_ptr, info_ptr, (trans_mode == 0) ? PNG_TRANSFORM_STRIP_FILLER_AFTER : PNG_TRANSFORM_IDENTITY, NULL);
png_destroy_write_struct(&png_ptr, &info_ptr);
}
template <typename T>
void reduce_8 (T const& in, image_data_8 & out, octree<rgb> trees[], unsigned limits[], unsigned levels, std::vector<unsigned> & alpha)
void reduce_8(T const& in,
image_data_8 & out,
octree<rgb> trees[],
unsigned limits[],
unsigned levels,
std::vector<unsigned> & alpha)
{
unsigned width = in.width();
unsigned height = in.height();
//unsigned alphaCount[alpha.size()];
std::vector<unsigned> alphaCount(alpha.size());
for(unsigned i=0; i<alpha.size(); i++)
{
alpha[i] = 0;
alphaCount[i] = 0;
}
for (unsigned y = 0; y < height; ++y)
{
mapnik::image_data_32::pixel_type const * row = in.getRow(y);
@ -127,8 +155,10 @@ void reduce_8 (T const& in, image_data_8 & out, octree<rgb> trees[], unsigned l
mapnik::rgb c(U2RED(val), U2GREEN(val), U2BLUE(val));
byte index = 0;
int idx = -1;
for(int j=levels-1; j>0; j--){
if (U2ALPHA(val)>=limits[j] && trees[j].colors()>0) {
for(int j=levels-1; j>0; j--)
{
if (U2ALPHA(val)>=limits[j] && trees[j].colors()>0)
{
index = idx = trees[j].quantize(c);
break;
}
@ -144,37 +174,43 @@ void reduce_8 (T const& in, image_data_8 & out, octree<rgb> trees[], unsigned l
for(unsigned i=0; i<alpha.size(); i++)
{
if (alphaCount[i]!=0)
{
alpha[i] /= alphaCount[i];
}
}
}
template <typename T>
void reduce_4 (T const& in, image_data_8 & out, octree<rgb> trees[], unsigned limits[], unsigned levels, std::vector<unsigned> & alpha)
void reduce_4(T const& in,
image_data_8 & out,
octree<rgb> trees[],
unsigned limits[],
unsigned levels,
std::vector<unsigned> & alpha)
{
unsigned width = in.width();
unsigned height = in.height();
//unsigned alphaCount[alpha.size()];
std::vector<unsigned> alphaCount(alpha.size());
for(unsigned i=0; i<alpha.size(); i++)
{
alpha[i] = 0;
alphaCount[i] = 0;
}
for (unsigned y = 0; y < height; ++y)
{
mapnik::image_data_32::pixel_type const * row = in.getRow(y);
mapnik::image_data_8::pixel_type * row_out = out.getRow(y);
for (unsigned x = 0; x < width; ++x)
{
unsigned val = row[x];
mapnik::rgb c(U2RED(val), U2GREEN(val), U2BLUE(val));
byte index = 0;
int idx=-1;
for(int j=levels-1; j>0; j--){
if (U2ALPHA(val)>=limits[j] && trees[j].colors()>0) {
for(int j=levels-1; j>0; j--)
{
if (U2ALPHA(val)>=limits[j] && trees[j].colors()>0)
{
index = idx = trees[j].quantize(c);
break;
}
@ -184,20 +220,29 @@ void reduce_4 (T const& in, image_data_8 & out, octree<rgb> trees[], unsigned li
alpha[idx]+=U2ALPHA(val);
alphaCount[idx]++;
}
if (x%2 == 0) index = index<<4;
if (x%2 == 0)
{
index = index<<4;
}
row_out[x>>1] |= index;
}
}
for(unsigned i=0; i<alpha.size(); i++)
{
if (alphaCount[i]!=0)
{
alpha[i] /= alphaCount[i];
}
}
}
// 1-bit but only one color.
template <typename T>
void reduce_1(T const&, image_data_8 & out, octree<rgb> /*trees*/[], unsigned /*limits*/[], std::vector<unsigned> & /*alpha*/)
void reduce_1(T const&,
image_data_8 & out,
octree<rgb> /*trees*/[],
unsigned /*limits*/[],
std::vector<unsigned> & /*alpha*/)
{
out.set(0); // only one color!!!
}
@ -210,13 +255,31 @@ void save_as_png(T & file, std::vector<mapnik::rgb> const& palette,
unsigned color_depth,
int compression,
int strategy,
std::vector<unsigned> const&alpha)
std::vector<unsigned> const&alpha,
bool use_miniz)
{
if (use_miniz)
{
MiniZ::PNGWriter writer(compression,strategy);
// image.width()/height() does not reflect the actual image dimensions; it
// refers to the quantized scanlines.
writer.writeIHDR(width, height, color_depth);
writer.writePLTE(palette);
writer.writetRNS(alpha);
writer.writeIDAT(image);
writer.writeIEND();
writer.toStream(file);
return;
}
png_voidp error_ptr=0;
png_structp png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING,
error_ptr,0, 0);
if (!png_ptr) return;
if (!png_ptr)
{
return;
}
// switch on optimization only if supported
#if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) && defined(PNG_MMX_CODE_SUPPORTED)
@ -260,10 +323,14 @@ void save_as_png(T & file, std::vector<mapnik::rgb> const& palette,
{
trans[i]=alpha[i];
if (alpha[i]<255)
{
alphaSize = i+1;
}
}
if (alphaSize>0)
{
png_set_tRNS(png_ptr, info_ptr, (png_bytep)&trans[0], alphaSize, 0);
}
}
png_write_info(png_ptr, info_ptr);
@ -277,8 +344,13 @@ void save_as_png(T & file, std::vector<mapnik::rgb> const& palette,
}
template <typename T1,typename T2>
void save_as_png8_oct(T1 & file, T2 const& image, const unsigned max_colors = 256,
int compression = Z_DEFAULT_COMPRESSION, int strategy = Z_DEFAULT_STRATEGY, int trans_mode = -1)
void save_as_png8_oct(T1 & file,
T2 const& image,
const unsigned max_colors = 256,
int compression = Z_DEFAULT_COMPRESSION,
int strategy = Z_DEFAULT_STRATEGY,
int trans_mode = -1,
bool use_miniz = false)
{
// number of alpha ranges in png8 format; 2 results in smallest image with binary transparency
// 3 is minimum for semitransparency, 4 is recommended, anything else is worse
@ -288,70 +360,117 @@ void save_as_png8_oct(T1 & file, T2 const& image, const unsigned max_colors = 25
unsigned alphaHist[256];//transparency histogram
unsigned semiCount = 0;//sum of semitransparent pixels
unsigned meanAlpha = 0;
for(int i=0; i<256; i++){
alphaHist[i] = 0;
if (trans_mode == 0)
{
meanAlpha = 255;
}
for (unsigned y = 0; y < height; ++y){
for (unsigned x = 0; x < width; ++x){
unsigned val = U2ALPHA((unsigned)image.getRow(y)[x]);
if (trans_mode==0)
val=255;
alphaHist[val]++;
meanAlpha += val;
if (val>0 && val<255)
semiCount++;
else
{
for(int i=0; i<256; i++)
{
alphaHist[i] = 0;
}
for (unsigned y = 0; y < height; ++y)
{
for (unsigned x = 0; x < width; ++x)
{
unsigned val = U2ALPHA((unsigned)image.getRow(y)[x]);
alphaHist[val]++;
meanAlpha += val;
if (val>0 && val<255)
{
semiCount++;
}
}
}
meanAlpha /= width*height;
}
meanAlpha /= width*height;
// transparency ranges division points
unsigned limits[MAX_OCTREE_LEVELS+1];
limits[0] = 0;
limits[1] = (alphaHist[0]>0)?1:0;
limits[1] = (trans_mode!=0 && alphaHist[0]>0)?1:0;
limits[TRANSPARENCY_LEVELS] = 256;
unsigned alphaHistSum = 0;
for(unsigned j=1; j<TRANSPARENCY_LEVELS; j++)
for(unsigned j=2; j<TRANSPARENCY_LEVELS; j++)
{
limits[j] = limits[1];
for(unsigned i=1; i<256; i++){
alphaHistSum += alphaHist[i];
for(unsigned j=1; j<TRANSPARENCY_LEVELS; j++){
if (alphaHistSum<semiCount*(j)/4)
limits[j] = i;
}
if (trans_mode != 0)
{
unsigned alphaHistSum = 0;
for(unsigned i=1; i<256; i++)
{
alphaHistSum += alphaHist[i];
for(unsigned j=1; j<TRANSPARENCY_LEVELS; j++)
{
if (alphaHistSum<semiCount*(j)/4)
{
limits[j] = i;
}
}
}
}
// avoid too wide full transparent range
if (limits[1]>256/(TRANSPARENCY_LEVELS-1))
{
limits[1]=256/(TRANSPARENCY_LEVELS-1);
}
// avoid too wide full opaque range
if (limits[TRANSPARENCY_LEVELS-1]<212)
{
limits[TRANSPARENCY_LEVELS-1]=212;
if (TRANSPARENCY_LEVELS==2) {
}
if (TRANSPARENCY_LEVELS==2)
{
limits[1]=127;
}
// estimated number of colors from palette assigned to chosen ranges
unsigned cols[MAX_OCTREE_LEVELS];
// count colors
for(unsigned j=1; j<=TRANSPARENCY_LEVELS; j++) {
cols[j-1] = 0;
for(unsigned i=limits[j-1]; i<limits[j]; i++){
cols[j-1] += alphaHist[i];
if (trans_mode == 0)
{
for (unsigned j=0; j<TRANSPARENCY_LEVELS; j++)
{
cols[j] = 0;
}
cols[TRANSPARENCY_LEVELS-1] = width * height;
}
else
{
for (unsigned j=0; j<TRANSPARENCY_LEVELS; j++)
{
cols[j] = 0;
for (unsigned i=limits[j]; i<limits[j+1]; i++)
{
cols[j] += alphaHist[i];
}
}
}
unsigned divCoef = width*height-cols[0];
if (divCoef==0) divCoef = 1;
if (divCoef==0)
{
divCoef = 1;
}
cols[0] = cols[0]>0?1:0; // fully transparent color (one or not at all)
if (max_colors>=64) {
if (max_colors>=64)
{
// give chance less populated but not empty cols to have at least few colors(12)
unsigned minCols = (12+1)*divCoef/(max_colors-cols[0]);
for(unsigned j=1; j<TRANSPARENCY_LEVELS; j++) if (cols[j]>12 && cols[j]<minCols) {
for(unsigned j=1; j<TRANSPARENCY_LEVELS; j++)
{
if (cols[j]>12 && cols[j]<minCols)
{
divCoef += minCols-cols[j];
cols[j] = minCols;
}
}
}
unsigned usedColors = cols[0];
for(unsigned j=1; j<TRANSPARENCY_LEVELS-1; j++){
for(unsigned j=1; j<TRANSPARENCY_LEVELS-1; j++)
{
cols[j] = cols[j]*(max_colors-cols[0])/divCoef;
usedColors += cols[j];
}
@ -369,17 +488,20 @@ void save_as_png8_oct(T1 & file, T2 const& image, const unsigned max_colors = 25
// octree table for separate alpha range with 1-based index (0 is fully transparent: no color)
octree<rgb> trees[MAX_OCTREE_LEVELS];
for(unsigned j=1; j<TRANSPARENCY_LEVELS; j++)
{
trees[j].setMaxColors(cols[j]);
}
for (unsigned y = 0; y < height; ++y)
{
typename T2::pixel_type const * row = image.getRow(y);
for (unsigned x = 0; x < width; ++x)
{
unsigned val = row[x];
// insert to proper tree based on alpha range
for(unsigned j=TRANSPARENCY_LEVELS-1; j>0; j--){
if (cols[j]>0 && U2ALPHA(val)>=limits[j]) {
for(unsigned j=TRANSPARENCY_LEVELS-1; j>0; j--)
{
if (cols[j]>0 && U2ALPHA(val)>=limits[j])
{
trees[j].insert(mapnik::rgb(U2RED(val), U2GREEN(val), U2BLUE(val)));
break;
}
@ -390,11 +512,16 @@ void save_as_png8_oct(T1 & file, T2 const& image, const unsigned max_colors = 25
std::vector<rgb> palette;
palette.reserve(max_colors);
if (cols[0])
{
palette.push_back(rgb(0,0,0));
}
for(unsigned j=1; j<TRANSPARENCY_LEVELS; j++) {
if (cols[j]>0) {
if (leftovers>0) {
for(unsigned j=1; j<TRANSPARENCY_LEVELS; j++)
{
if (cols[j]>0)
{
if (leftovers>0)
{
cols[j] += leftovers;
trees[j].setMaxColors(cols[j]);
leftovers = 0;
@ -405,7 +532,8 @@ void save_as_png8_oct(T1 & file, T2 const& image, const unsigned max_colors = 25
assert(pal.size() <= max_colors);
leftovers = cols[j]-pal.size();
cols[j] = pal.size();
for(unsigned i=0; i<pal.size(); i++){
for(unsigned i=0; i<pal.size(); i++)
{
palette.push_back(pal[i]);
}
assert(palette.size() <= 256);
@ -416,14 +544,16 @@ void save_as_png8_oct(T1 & file, T2 const& image, const unsigned max_colors = 25
std::vector<unsigned> alphaTable;
//alphaTable.resize(palette.size());//allow semitransparency also in almost opaque range
if (trans_mode != 0)
{
alphaTable.resize(palette.size() - cols[TRANSPARENCY_LEVELS-1]);
}
if (palette.size() > 16 )
{
// >16 && <=256 colors -> write 8-bit color depth
image_data_8 reduced_image(width,height);
reduce_8(image, reduced_image, trees, limits, TRANSPARENCY_LEVELS, alphaTable);
save_as_png(file,palette,reduced_image,width,height,8,compression,strategy,alphaTable);
save_as_png(file,palette,reduced_image,width,height,8,compression,strategy,alphaTable,use_miniz);
}
else if (palette.size() == 1)
{
@ -432,11 +562,12 @@ void save_as_png8_oct(T1 & file, T2 const& image, const unsigned max_colors = 25
unsigned image_height = height;
image_data_8 reduced_image(image_width,image_height);
reduce_1(image,reduced_image,trees, limits, alphaTable);
if (meanAlpha<255 && cols[0]==0) {
if (meanAlpha<255 && cols[0]==0)
{
alphaTable.resize(1);
alphaTable[0] = meanAlpha;
}
save_as_png(file,palette,reduced_image,width,height,1,compression,strategy,alphaTable);
save_as_png(file,palette,reduced_image,width,height,1,compression,strategy,alphaTable,use_miniz);
}
else
{
@ -445,15 +576,20 @@ void save_as_png8_oct(T1 & file, T2 const& image, const unsigned max_colors = 25
unsigned image_height = height;
image_data_8 reduced_image(image_width,image_height);
reduce_4(image, reduced_image, trees, limits, TRANSPARENCY_LEVELS, alphaTable);
save_as_png(file,palette,reduced_image,width,height,4,compression,strategy,alphaTable);
save_as_png(file,palette,reduced_image,width,height,4,compression,strategy,alphaTable,use_miniz);
}
}
template <typename T1, typename T2, typename T3>
void save_as_png8(T1 & file, T2 const& image, T3 const & tree,
std::vector<mapnik::rgb> const& palette, std::vector<unsigned> const& alphaTable,
int compression = Z_DEFAULT_COMPRESSION, int strategy = Z_DEFAULT_STRATEGY)
void save_as_png8(T1 & file,
T2 const& image,
T3 const & tree,
std::vector<mapnik::rgb> const& palette,
std::vector<unsigned> const& alphaTable,
int compression = Z_DEFAULT_COMPRESSION,
int strategy = Z_DEFAULT_STRATEGY,
bool use_miniz = false)
{
unsigned width = image.width();
unsigned height = image.height();
@ -462,18 +598,16 @@ void save_as_png8(T1 & file, T2 const& image, T3 const & tree,
{
// >16 && <=256 colors -> write 8-bit color depth
image_data_8 reduced_image(width, height);
for (unsigned y = 0; y < height; ++y)
{
mapnik::image_data_32::pixel_type const * row = image.getRow(y);
mapnik::image_data_8::pixel_type * row_out = reduced_image.getRow(y);
for (unsigned x = 0; x < width; ++x)
{
row_out[x] = tree.quantize(row[x]);
}
}
save_as_png(file, palette, reduced_image, width, height, 8, compression, strategy, alphaTable);
save_as_png(file, palette, reduced_image, width, height, 8, compression, strategy, alphaTable, use_miniz);
}
else if (palette.size() == 1)
{
@ -482,7 +616,7 @@ void save_as_png8(T1 & file, T2 const& image, T3 const & tree,
unsigned image_height = height;
image_data_8 reduced_image(image_width, image_height);
reduced_image.set(0);
save_as_png(file, palette, reduced_image, width, height, 1, compression, strategy, alphaTable);
save_as_png(file, palette, reduced_image, width, height, 1, compression, strategy, alphaTable, use_miniz);
}
else
{
@ -495,23 +629,30 @@ void save_as_png8(T1 & file, T2 const& image, T3 const & tree,
mapnik::image_data_32::pixel_type const * row = image.getRow(y);
mapnik::image_data_8::pixel_type * row_out = reduced_image.getRow(y);
byte index = 0;
for (unsigned x = 0; x < width; ++x)
{
index = tree.quantize(row[x]);
if (x%2 == 0) index = index<<4;
if (x%2 == 0)
{
index = index<<4;
}
row_out[x>>1] |= index;
}
}
save_as_png(file, palette, reduced_image, width, height, 4, compression, strategy, alphaTable);
save_as_png(file, palette, reduced_image, width, height, 4, compression, strategy, alphaTable, use_miniz);
}
}
template <typename T1,typename T2>
void save_as_png8_hex(T1 & file, T2 const& image, int colors = 256,
int compression = Z_DEFAULT_COMPRESSION, int strategy = Z_DEFAULT_STRATEGY,
int trans_mode = -1, double gamma = 2.0)
void save_as_png8_hex(T1 & file,
T2 const& image,
int colors = 256,
int compression = Z_DEFAULT_COMPRESSION,
int strategy = Z_DEFAULT_STRATEGY,
int trans_mode = -1,
double gamma = 2.0,
bool use_miniz = false)
{
unsigned width = image.width();
unsigned height = image.height();
@ -519,9 +660,13 @@ void save_as_png8_hex(T1 & file, T2 const& image, int colors = 256,
// structure for color quantization
hextree<mapnik::rgba> tree(colors);
if (trans_mode >= 0)
{
tree.setTransMode(trans_mode);
}
if (gamma > 0)
{
tree.setGamma(gamma);
}
for (unsigned y = 0; y < height; ++y)
{
@ -537,7 +682,6 @@ void save_as_png8_hex(T1 & file, T2 const& image, int colors = 256,
std::vector<mapnik::rgba> pal;
tree.create_palette(pal);
assert(int(pal.size()) <= colors);
std::vector<mapnik::rgb> palette;
std::vector<unsigned> alphaTable;
for(unsigned i=0; i<pal.size(); i++)
@ -546,14 +690,18 @@ void save_as_png8_hex(T1 & file, T2 const& image, int colors = 256,
alphaTable.push_back(pal[i].a);
}
save_as_png8<T1, T2, hextree<mapnik::rgba> >(file, image, tree, palette, alphaTable, compression, strategy);
save_as_png8<T1, T2, hextree<mapnik::rgba> >(file, image, tree, palette, alphaTable, compression, strategy, use_miniz);
}
template <typename T1, typename T2>
void save_as_png8_pal(T1 & file, T2 const& image, rgba_palette const& pal,
int compression = Z_DEFAULT_COMPRESSION, int strategy = Z_DEFAULT_STRATEGY)
void save_as_png8_pal(T1 & file,
T2 const& image,
rgba_palette const& pal,
int compression = Z_DEFAULT_COMPRESSION,
int strategy = Z_DEFAULT_STRATEGY,
bool use_miniz = false)
{
save_as_png8<T1, T2, rgba_palette>(file, image, pal, pal.palette(), pal.alphaTable(), compression, strategy);
save_as_png8<T1, T2, rgba_palette>(file, image, pal, pal.palette(), pal.alphaTable(), compression, strategy, use_miniz);
}
}

View file

@ -39,6 +39,7 @@
#include <map>
#include <deque>
#include <ctime>
#include <cassert>
namespace mapnik
{
@ -71,8 +72,8 @@ class Pool : private boost::noncopyable
typedef std::deque<HolderType> ContType;
Creator<T> creator_;
const unsigned initialSize_;
const unsigned maxSize_;
unsigned initialSize_;
unsigned maxSize_;
ContType usedPool_;
ContType unusedPool_;
#ifdef MAPNIK_THREADSAFE
@ -80,7 +81,7 @@ class Pool : private boost::noncopyable
#endif
public:
Pool(const Creator<T>& creator,unsigned initialSize=1, unsigned maxSize=10)
Pool(const Creator<T>& creator,unsigned initialSize, unsigned maxSize)
:creator_(creator),
initialSize_(initialSize),
maxSize_(maxSize)
@ -107,7 +108,7 @@ public:
{
usedPool_.push_back(*itr);
unusedPool_.erase(itr);
return usedPool_[usedPool_.size()-1];
return usedPool_.back();
}
else
{
@ -116,6 +117,7 @@ public:
itr=unusedPool_.erase(itr);
}
}
// all connection have been taken, check if we allowed to grow pool
if (usedPool_.size() < maxSize_)
{
HolderType conn(creator_());
@ -159,6 +161,54 @@ public:
std::pair<unsigned,unsigned> size(unusedPool_.size(),usedPool_.size());
return size;
}
unsigned max_size() const
{
#ifdef MAPNIK_THREADSAFE
mutex::scoped_lock lock(mutex_);
#endif
return maxSize_;
}
void set_max_size(unsigned size)
{
#ifdef MAPNIK_THREADSAFE
mutex::scoped_lock lock(mutex_);
#endif
maxSize_ = std::max(maxSize_,size);
}
unsigned initial_size() const
{
#ifdef MAPNIK_THREADSAFE
mutex::scoped_lock lock(mutex_);
#endif
return initialSize_;
}
void set_initial_size(unsigned size)
{
#ifdef MAPNIK_THREADSAFE
mutex::scoped_lock lock(mutex_);
#endif
if (size > initialSize_)
{
initialSize_ = size;
unsigned total_size = usedPool_.size() + unusedPool_.size();
// ensure we don't have ghost obj's in the pool.
if (total_size < initialSize_)
{
unsigned grow_size = initialSize_ - total_size ;
for (unsigned i=0; i < grow_size; ++i)
{
HolderType conn(creator_());
if (conn->isOK())
unusedPool_.push_back(conn);
}
}
}
}
};
}

View file

@ -27,8 +27,9 @@
#include <mapnik/ctrans.hpp>
#include <mapnik/color.hpp>
#include <mapnik/geometry.hpp>
#include <mapnik/svg/svg_output_grammars.hpp>
#include <mapnik/svg/svg_output_attributes.hpp>
#include <mapnik/util/geometry_svg_generator.hpp>
#include <mapnik/svg/output/svg_output_grammars.hpp>
#include <mapnik/svg/output/svg_output_attributes.hpp>
// boost
#include <boost/utility.hpp>
@ -44,11 +45,8 @@ namespace mapnik { namespace svg {
template <typename OutputIterator>
class svg_generator : private boost::noncopyable
{
typedef coord_transform<CoordTransform, geometry_type> path_type;
typedef svg::svg_root_attributes_grammar<OutputIterator> root_attributes_grammar;
typedef svg::svg_rect_attributes_grammar<OutputIterator> rect_attributes_grammar;
typedef svg::svg_path_data_grammar<OutputIterator, path_type> path_data_grammar;
typedef svg::svg_path_attributes_grammar<OutputIterator> path_attributes_grammar;
typedef svg::svg_path_dash_array_grammar<OutputIterator> path_dash_array_grammar;
@ -60,7 +58,16 @@ namespace mapnik { namespace svg {
void generate_opening_root(root_output_attributes const& root_attributes);
void generate_closing_root();
void generate_rect(rect_output_attributes const& rect_attributes);
void generate_path(path_type const& path, path_output_attributes const& path_attributes);
template <typename PathType>
void generate_path(PathType const& path, path_output_attributes const& path_attributes)
{
util::svg_generator<OutputIterator,PathType> svg_path_grammer;
karma::generate(output_iterator_, lit("<path ") << svg_path_grammer, path);
path_attributes_grammar attributes_grammar;
path_dash_array_grammar dash_array_grammar;
karma::generate(output_iterator_, lit(" ") << dash_array_grammar, path_attributes.stroke_dasharray());
karma::generate(output_iterator_, lit(" ") << attributes_grammar << lit("/>\n"), path_attributes);
}
private:
OutputIterator& output_iterator_;

View file

@ -87,84 +87,11 @@ BOOST_FUSION_ADAPT_STRUCT(
(std::string, svg_namespace_url_)
)
/*!
* mapnik::geometry_type is adapted to conform to the concepts
* required by Karma to be recognized as a container of
* attributes for output generation.
*/
namespace boost { namespace spirit { namespace traits {
typedef mapnik::coord_transform<mapnik::CoordTransform, mapnik::geometry_type> path_type;
template <>
struct is_container<path_type const>
: mpl::true_ {};
template <>
struct container_iterator<path_type const>
{
typedef mapnik::svg::path_iterator_type type;
};
template <>
struct begin_container<path_type const>
{
static mapnik::svg::path_iterator_type
call(path_type const& path)
{
return mapnik::svg::path_iterator_type(0, path);
}
};
template <>
struct end_container<path_type const>
{
static mapnik::svg::path_iterator_type
call(path_type const& path)
{
return mapnik::svg::path_iterator_type(path);
}
};
}}}
namespace mapnik { namespace svg {
using namespace boost::spirit;
using namespace boost::phoenix;
template <typename OutputIterator, typename PathType>
struct svg_path_data_grammar : karma::grammar<OutputIterator, PathType&()>
{
typedef path_iterator_type::value_type vertex_type;
explicit svg_path_data_grammar(PathType const& path_type)
: svg_path_data_grammar::base_type(svg_path),
path_type_(path_type)
{
using karma::int_;
using karma::double_;
using repository::confix;
svg_path =
lit("d=")
<< confix('"', '"')[
-(path_vertex % lit(' '))];
path_vertex =
path_vertex_command
<< double_
<< lit(' ')
<< double_;
path_vertex_command = &int_(1) << lit('M') | lit('L');
}
karma::rule<OutputIterator, PathType&()> svg_path;
karma::rule<OutputIterator, vertex_type()> path_vertex;
karma::rule<OutputIterator, int()> path_vertex_command;
PathType const& path_type_;
};
template <typename OutputIterator>
struct svg_path_attributes_grammar : karma::grammar<OutputIterator, mapnik::svg::path_output_attributes()>

View file

@ -62,7 +62,7 @@ class path_iterator
public:
typedef Value value_type;
typedef Container container_type;
typedef typename Container::value_type value_component_type;
//typedef typename Container::value_type value_component_type;
/*!
* @brief Constructor that initializes the reference to the current element to null.
@ -119,8 +119,8 @@ private:
void increment()
{
// variables used to extract vertex components.
geometry_type::value_type x;
geometry_type::value_type y;
geometry_type::coord_type x;
geometry_type::coord_type y;
// extract next vertex components.
unsigned cmd = path_.vertex(&x, &y);
@ -173,8 +173,8 @@ private:
* The Value type is a boost::tuple that holds 5 elements, the command and the x and y coordinate.
* Each coordinate is stored twice to match the needs of the grammar.
*/
typedef path_iterator<boost::tuple<unsigned, geometry_type::value_type, geometry_type::value_type>,
coord_transform<CoordTransform, geometry_type> > path_iterator_type;
//typedef path_iterator<boost::tuple<unsigned, geometry_type::coord_type, geometry_type::value_type>,
// coord_transform<CoordTransform, geometry_type> > path_iterator_type;
}}

View file

@ -42,54 +42,60 @@ class MAPNIK_DECL svg_renderer : public feature_style_processor<svg_renderer<Out
private boost::noncopyable
{
public:
typedef svg_renderer<OutputIterator> processor_impl_type;
svg_renderer(Map const& m, OutputIterator& output_iterator, unsigned offset_x=0, unsigned offset_y=0);
~svg_renderer();
void start_map_processing(Map const& map);
void end_map_processing(Map const& map);
void start_layer_processing(layer const& lay);
void start_layer_processing(layer const& lay, box2d<double> const& query_extent);
void end_layer_processing(layer const& lay);
void start_style_processing(feature_type_style const& st) {}
void end_style_processing(feature_type_style const& st) {}
/*!
* @brief Overloads that process each kind of symbolizer individually.
*/
void process(point_symbolizer const& sym,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans);
void process(line_symbolizer const& sym,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans);
void process(line_pattern_symbolizer const& sym,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans);
void process(polygon_symbolizer const& sym,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans);
void process(polygon_pattern_symbolizer const& sym,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans);
void process(raster_symbolizer const& sym,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans);
void process(shield_symbolizer const& sym,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans);
void process(text_symbolizer const& sym,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans);
void process(building_symbolizer const& sym,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans);
void process(markers_symbolizer const& sym,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans);
void process(debug_symbolizer const& sym,
mapnik::feature_impl & feature,
proj_transform const& prj_trans) {}
/*!
* @brief Overload that process the whole set of symbolizers of a rule.
* @return true, meaning that this renderer can process multiple symbolizers.
*/
bool process(rule::symbolizers const& syms,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans);
void painted(bool painted)
@ -114,6 +120,7 @@ private:
CoordTransform t_;
svg::svg_generator<OutputIterator> generator_;
svg::path_output_attributes path_attributes_;
box2d<double> query_extent_;
bool painted_;
/*!
@ -125,7 +132,7 @@ private:
struct symbol_dispatch : public boost::static_visitor<>
{
symbol_dispatch(svg_renderer<OutputIterator>& processor,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans)
: processor_(processor),
feature_(feature),
@ -138,7 +145,7 @@ private:
}
svg_renderer<OutputIterator>& processor_;
Feature const& feature_;
mapnik::feature_impl & feature_;
proj_transform const& prj_trans_;
};
};

View file

@ -25,7 +25,8 @@
// mapnik
#include <mapnik/global.hpp>
#include <mapnik/geometry.hpp>
#include <mapnik/geometry.hpp> // for container stuff
#include <mapnik/ctrans.hpp> // for container stuff
#include <mapnik/util/path_iterator.hpp>
#include <mapnik/util/container_adapter.hpp>
@ -38,35 +39,84 @@
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/spirit/home/phoenix/statement/if.hpp>
#include <boost/fusion/include/boost_tuple.hpp>
#include <boost/type_traits/remove_pointer.hpp>
//#define BOOST_SPIRIT_USE_PHOENIX_V3 1
/*!
* adapted to conform to the concepts
* required by Karma to be recognized as a container of
* attributes for output generation.
*/
namespace boost { namespace spirit { namespace traits {
// TODO - this needs to be made generic to any path type
typedef mapnik::coord_transform<mapnik::CoordTransform, mapnik::geometry_type> path_type;
template <>
struct is_container<path_type const> : mpl::true_ {} ;
template <>
struct container_iterator<path_type const>
{
typedef mapnik::util::path_iterator<path_type> type;
};
template <>
struct begin_container<path_type const>
{
static mapnik::util::path_iterator<path_type>
call (path_type const& g)
{
return mapnik::util::path_iterator<path_type>(g);
}
};
template <>
struct end_container<path_type const>
{
static mapnik::util::path_iterator<path_type>
call (path_type const& g)
{
return mapnik::util::path_iterator<path_type>();
}
};
}}}
namespace mapnik { namespace util {
namespace karma = boost::spirit::karma;
namespace phoenix = boost::phoenix;
namespace svg_detail {
template <typename Geometry>
struct get_type
{
template <typename T>
struct result { typedef int type; };
int operator() (geometry_type const& geom) const
int operator() (Geometry const& geom) const
{
return (int)geom.type();
return static_cast<int>(geom.type());
}
};
template <typename T>
struct get_first
{
template <typename T>
struct result { typedef geometry_type::value_type const type; };
typedef T geometry_type;
geometry_type::value_type const operator() (geometry_type const& geom) const
template <typename U>
struct result { typedef typename geometry_type::value_type const type; };
typename geometry_type::value_type const operator() (geometry_type const& geom) const
{
geometry_type::value_type coord;
boost::get<0>(coord) = geom.vertex(0,&boost::get<1>(coord),&boost::get<2>(coord));
typename geometry_type::value_type coord;
geom.rewind(0);
boost::get<0>(coord) = geom.vertex(&boost::get<1>(coord),&boost::get<2>(coord));
return coord;
}
};
@ -80,11 +130,14 @@ namespace mapnik { namespace util {
};
}
template <typename OutputIterator>
template <typename OutputIterator, typename Geometry>
struct svg_generator :
karma::grammar<OutputIterator, geometry_type const& ()>
karma::grammar<OutputIterator, Geometry const& ()>
{
typedef Geometry geometry_type;
typedef typename boost::remove_pointer<typename geometry_type::value_type>::type coord_type;
svg_generator()
: svg_generator::base_type(svg)
{
@ -102,22 +155,22 @@ namespace mapnik { namespace util {
;
svg_point = &uint_
<< lit("cx=\"") << coord_type
<< lit("\" cy=\"") << coord_type
<< lit("cx=\"") << coordinate
<< lit("\" cy=\"") << coordinate
<< lit('\"')
;
linestring = &uint_(mapnik::LineString)[_1 = _type(_val)]
<< svg_path
<< svg_path << lit('\"')
;
polygon = &uint_(mapnik::Polygon)[_1 = _type(_val)]
<< svg_path
<< svg_path << lit('\"')
;
svg_path %= ((&uint_(mapnik::SEG_MOVETO) << lit('M')
svg_path %= ((&uint_(mapnik::SEG_MOVETO) << lit("d=\"") << lit('M')
| &uint_(mapnik::SEG_LINETO) [_a +=1] << karma::string [if_(_a == 1) [_1 = "L" ] ])
<< lit(' ') << coord_type << lit(' ') << coord_type) % lit(' ')
<< lit(' ') << coordinate << lit(' ') << coordinate) % lit(' ')
;
@ -129,14 +182,14 @@ namespace mapnik { namespace util {
karma::rule<OutputIterator, geometry_type const& ()> linestring;
karma::rule<OutputIterator, geometry_type const& ()> polygon;
karma::rule<OutputIterator, geometry_type::value_type ()> svg_point;
karma::rule<OutputIterator, coord_type ()> svg_point;
karma::rule<OutputIterator, karma::locals<unsigned>, geometry_type const& ()> svg_path;
// phoenix functions
phoenix::function<svg_detail::get_type > _type;
phoenix::function<svg_detail::get_first> _first;
phoenix::function<svg_detail::get_type<geometry_type> > _type;
phoenix::function<svg_detail::get_first<geometry_type> > _first;
//
karma::real_generator<double, svg_detail::coordinate_policy<double> > coord_type;
karma::real_generator<double, svg_detail::coordinate_policy<double> > coordinate;
};

View file

@ -39,7 +39,7 @@ bool to_svg(std::string & svg, mapnik::geometry_type const& geom)
{
typedef std::back_insert_iterator<std::string> sink_type;
sink_type sink(svg);
svg_generator<sink_type> generator;
svg_generator<sink_type, mapnik::geometry_type> generator;
bool result = karma::generate(sink, generator, geom);
return result;
}

View file

@ -365,6 +365,16 @@ struct vertex_converter : private boost::noncopyable
disp_.vec_[index]=1;
}
template <typename Conv>
void unset()
{
typedef typename boost::mpl::find<conv_types,Conv>::type iter;
typedef typename boost::mpl::end<conv_types>::type end;
std::size_t index = boost::mpl::distance<iter,end>::value - 1;
if (index < disp_.vec_.size())
disp_.vec_[index]=0;
}
detail::dispatcher<args_type,conv_types> disp_;
};

View file

@ -23,7 +23,6 @@
#include "ogr_datasource.hpp"
#include "ogr_featureset.hpp"
#include "ogr_index_featureset.hpp"
#include "ogr_feature_ptr.hpp"
#include <gdal_version.h>
@ -394,10 +393,10 @@ boost::optional<mapnik::datasource::geometry_t> ogr_datasource::get_geometry_typ
// only new either reset of setNext
//layer->ResetReading();
layer->SetNextByIndex(0);
ogr_feature_ptr feat(layer->GetNextFeature());
if ((*feat) != NULL)
OGRFeature *poFeature;
while ((poFeature = layer->GetNextFeature()) != NULL)
{
OGRGeometry* geom = (*feat)->GetGeometryRef();
OGRGeometry* geom = poFeature->GetGeometryRef();
if (geom && ! geom->IsEmpty())
{
switch (wkbFlatten(geom->getGeometryType()))
@ -422,6 +421,8 @@ boost::optional<mapnik::datasource::geometry_t> ogr_datasource::get_geometry_typ
break;
}
}
OGRFeature::DestroyFeature( poFeature );
break;
}
}
break;

View file

@ -1,54 +0,0 @@
/*****************************************************************************
*
* 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
*
*****************************************************************************/
#ifndef OGR_FEATURE_PTR_HPP
#define OGR_FEATURE_PTR_HPP
// ogr
#include <ogrsf_frmts.h>
class ogr_feature_ptr
{
public:
ogr_feature_ptr(OGRFeature* const feat)
: feat_(feat)
{
}
~ogr_feature_ptr()
{
if (feat_ != NULL)
{
OGRFeature::DestroyFeature(feat_);
}
}
OGRFeature* operator*()
{
return feat_;
}
private:
OGRFeature* feat_;
};
#endif // OGR_FEATURE_PTR_HPP

View file

@ -35,7 +35,6 @@
// ogr
#include "ogr_featureset.hpp"
#include "ogr_converter.hpp"
#include "ogr_feature_ptr.hpp"
using mapnik::query;
using mapnik::box2d;
@ -84,23 +83,24 @@ ogr_featureset::~ogr_featureset()
feature_ptr ogr_featureset::next()
{
ogr_feature_ptr feat (layer_.GetNextFeature());
while ((*feat) != NULL)
OGRFeature *poFeature;
while ((poFeature = layer_.GetNextFeature()) != NULL)
{
// ogr feature ids start at 0, so add one to stay
// consistent with other mapnik datasources that start at 1
const int feature_id = ((*feat)->GetFID() + 1);
const int feature_id = (poFeature->GetFID() + 1);
feature_ptr feature(feature_factory::create(ctx_,feature_id));
OGRGeometry* geom = (*feat)->GetGeometryRef();
OGRGeometry* geom = poFeature->GetGeometryRef();
if (geom && ! geom->IsEmpty())
{
ogr_converter::convert_geometry(geom, feature);
}
else
{
MAPNIK_LOG_DEBUG(ogr) << "ogr_featureset: Feature with null geometry=" << (*feat)->GetFID();
MAPNIK_LOG_DEBUG(ogr) << "ogr_featureset: Feature with null geometry="
<< poFeature->GetFID();
OGRFeature::DestroyFeature( poFeature );
continue;
}
@ -117,20 +117,20 @@ feature_ptr ogr_featureset::next()
{
case OFTInteger:
{
feature->put( fld_name, (*feat)->GetFieldAsInteger(i));
feature->put( fld_name, poFeature->GetFieldAsInteger(i));
break;
}
case OFTReal:
{
feature->put( fld_name, (*feat)->GetFieldAsDouble(i));
feature->put( fld_name, poFeature->GetFieldAsDouble(i));
break;
}
case OFTString:
case OFTWideString: // deprecated !
{
UnicodeString ustr = tr_->transcode((*feat)->GetFieldAsString(i));
UnicodeString ustr = tr_->transcode(poFeature->GetFieldAsString(i));
feature->put( fld_name, ustr);
break;
}
@ -166,6 +166,7 @@ feature_ptr ogr_featureset::next()
}
}
}
OGRFeature::DestroyFeature( poFeature );
return feature;
}

View file

@ -40,7 +40,6 @@
#include "ogr_index_featureset.hpp"
#include "ogr_converter.hpp"
#include "ogr_index.hpp"
#include "ogr_feature_ptr.hpp"
using mapnik::query;
using mapnik::box2d;
@ -92,24 +91,27 @@ feature_ptr ogr_index_featureset<filterT>::next()
int pos = *itr_++;
layer_.SetNextByIndex (pos);
ogr_feature_ptr feat (layer_.GetNextFeature());
if ((*feat) == NULL)
OGRFeature *poFeature = layer_.GetNextFeature();
if (poFeature == NULL)
{
continue;
return feature_ptr();
}
// ogr feature ids start at 0, so add one to stay
// consistent with other mapnik datasources that start at 1
int feature_id = ((*feat)->GetFID() + 1);
int feature_id = (poFeature->GetFID() + 1);
feature_ptr feature(feature_factory::create(ctx_,feature_id));
OGRGeometry* geom=(*feat)->GetGeometryRef();
OGRGeometry* geom=poFeature->GetGeometryRef();
if (geom && !geom->IsEmpty())
{
ogr_converter::convert_geometry (geom, feature);
}
else
{
MAPNIK_LOG_DEBUG(ogr) << "ogr_index_featureset: Feature with null geometry=" << (*feat)->GetFID();
MAPNIK_LOG_DEBUG(ogr) << "ogr_index_featureset: Feature with null geometry="
<< poFeature->GetFID();
OGRFeature::DestroyFeature( poFeature );
continue;
}
@ -124,20 +126,20 @@ feature_ptr ogr_index_featureset<filterT>::next()
{
case OFTInteger:
{
feature->put(fld_name,(*feat)->GetFieldAsInteger (i));
feature->put(fld_name,poFeature->GetFieldAsInteger (i));
break;
}
case OFTReal:
{
feature->put(fld_name,(*feat)->GetFieldAsDouble (i));
feature->put(fld_name,poFeature->GetFieldAsDouble (i));
break;
}
case OFTString:
case OFTWideString: // deprecated !
{
UnicodeString ustr = tr_->transcode((*feat)->GetFieldAsString (i));
UnicodeString ustr = tr_->transcode(poFeature->GetFieldAsString (i));
feature->put(fld_name,ustr);
break;
}
@ -167,6 +169,7 @@ feature_ptr ogr_index_featureset<filterT>::next()
}
}
}
OGRFeature::DestroyFeature( poFeature );
return feature;
}

View file

@ -254,7 +254,7 @@ bool osm_way::is_polygon()
for (unsigned int count = 0; count < ptypes.ptypes.size(); ++count)
{
if (keyvals.find(ptypes.ptypes[count].first) != keyvals.end() &&
keyvals[ptypes.ptypes[count].first] == ptypes.ptypes[count].second)
(ptypes.ptypes[count].second.empty() || keyvals[ptypes.ptypes[count].first] == ptypes.ptypes[count].second))
{
return true;
}

View file

@ -49,13 +49,17 @@ public:
polygon_types()
{
ptypes.push_back(std::pair<std::string, std::string>("water", ""));
ptypes.push_back(std::pair<std::string, std::string>("aeroway", ""));
ptypes.push_back(std::pair<std::string, std::string>("building", ""));
ptypes.push_back(std::pair<std::string, std::string>("natural", "wood"));
ptypes.push_back(std::pair<std::string, std::string>("natural", "water"));
ptypes.push_back(std::pair<std::string, std::string>("natural", "heath"));
ptypes.push_back(std::pair<std::string, std::string>("natural", "marsh"));
ptypes.push_back(std::pair<std::string, std::string>("military", "danger_area"));
ptypes.push_back(std::pair<std::string, std::string>("landuse","forest"));
ptypes.push_back(std::pair<std::string, std::string>("landuse","industrial"));
ptypes.push_back(std::pair<std::string, std::string>("landuse", "forest"));
ptypes.push_back(std::pair<std::string, std::string>("landuse", "industrial"));
ptypes.push_back(std::pair<std::string, std::string>("leisure", "park"));
}
};

View file

@ -45,7 +45,6 @@ osm_featureset<filterT>::osm_featureset(const filterT& filter,
: filter_(filter),
query_ext_(),
tr_(new transcoder(encoding)),
feature_id_(1),
dataset_ (dataset),
attribute_names_ (attribute_names),
ctx_(boost::make_shared<mapnik::context_type>())
@ -62,8 +61,7 @@ feature_ptr osm_featureset<filterT>::next()
if (!cur_item) return feature_ptr();
if (dataset_->current_item_is_node())
{
feature = feature_factory::create(ctx_, feature_id_);
++feature_id_;
feature = feature_factory::create(ctx_, cur_item->id);
double lat = static_cast<osm_node*>(cur_item)->lat;
double lon = static_cast<osm_node*>(cur_item)->lon;
geometry_type* point = new geometry_type(mapnik::Point);
@ -83,8 +81,7 @@ feature_ptr osm_featureset<filterT>::next()
}
if (!cur_item) return feature_ptr();
feature = feature_factory::create(ctx_, feature_id_);
++feature_id_;
feature = feature_factory::create(ctx_, cur_item->id);
geometry_type* geom;
if (static_cast<osm_way*>(cur_item)->is_polygon())
{

View file

@ -61,7 +61,6 @@ private:
std::vector<int> attr_ids_;
mutable box2d<double> feature_ext_;
mutable int total_geom_size;
mutable int feature_id_;
osm_dataset *dataset_;
std::set<std::string> attribute_names_;
mapnik::context_ptr ctx_;

View file

@ -66,16 +66,8 @@ void osmparser::startElement(xmlTextReaderPtr reader, const xmlChar *name)
assert(xid);
way->id = atol((char*)xid);
cur_item = way;
// Prevent ways with no name being assigned a name of "0"
// Prevent ways with no name being assigned a name of "true"
cur_item->keyvals["name"] = "";
// HACK: allows comparison with "" in the XML file. Otherwise it
// doesn't work. Only do for the most crucial tags for Freemap's
// purposes. TODO investigate why this is
cur_item->keyvals["width"] = "";
cur_item->keyvals["horse"] = "";
cur_item->keyvals["foot"] = "";
cur_item->keyvals["bicycle"] = "";
xmlFree(xid);
}
else if (xmlStrEqual(name,BAD_CAST "nd"))

View file

@ -44,34 +44,24 @@ extern "C" {
class Connection
{
public:
Connection(std::string const& connection_str)
Connection(std::string const& connection_str,boost::optional<std::string> const& password)
: cursorId(0),
closed_(false)
{
conn_ = PQconnectdb(connection_str.c_str());
std::string connect_with_pass = connection_str;
if (password && !password->empty())
{
connect_with_pass += " password=" + *password;
}
conn_ = PQconnectdb(connect_with_pass.c_str());
if (PQstatus(conn_) != CONNECTION_OK)
{
std::ostringstream s;
s << "Postgis Plugin: ";
if (conn_ )
{
std::string msg = PQerrorMessage(conn_);
if (! msg.empty())
{
s << msg.substr(0, msg.size() - 1);
}
else
{
s << "unable to connect to postgres server";
}
}
else
{
s << "unable to connect to postgres server";
}
s << "\n" << connection_str;
throw mapnik::datasource_exception(s.str());
std::string err_msg = "Postgis Plugin: ";
err_msg += status();
err_msg += "\nConnection string: '";
err_msg += connection_str;
err_msg += "'\n";
throw mapnik::datasource_exception(err_msg);
}
}
@ -117,34 +107,35 @@ public:
if (! result || (PQresultStatus(result) != PGRES_TUPLES_OK))
{
std::ostringstream s;
s << "Postgis Plugin: PSQL error";
if (conn_)
{
std::string msg = PQerrorMessage(conn_);
if (! msg.empty())
{
s << ":\n" << msg.substr(0, msg.size() - 1);
}
s << "\nFull sql was: '" << sql << "'\n";
}
else
{
s << "unable to connect to database";
}
std::string err_msg = status();
err_msg += "\nFull sql was: '";
err_msg += sql;
err_msg += "'\n";
if (result)
{
PQclear(result);
}
throw mapnik::datasource_exception(s.str());
throw mapnik::datasource_exception(err_msg);
}
return boost::make_shared<ResultSet>(result);
}
std::string status() const
{
std::string status;
if (conn_)
{
status = PQerrorMessage(conn_);
}
else
{
status = "Uninitialized connection";
}
return status;
}
std::string client_encoding() const
{
return PQparameterStatus(conn_, "client_encoding");

View file

@ -33,10 +33,6 @@
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/optional.hpp>
#ifdef MAPNIK_THREADSAFE
#include <boost/thread/mutex.hpp>
//using boost::mutex;
#endif
// stl
#include <string>
@ -66,7 +62,7 @@ public:
T* operator()() const
{
return new T(connection_string());
return new T(connection_string_safe(),pass_);
}
inline std::string id() const
@ -75,14 +71,20 @@ public:
}
inline std::string connection_string() const
{
std::string connect_str = connection_string_safe();
if (pass_ && !pass_->empty()) connect_str += " password=" + *pass_;
return connect_str;
}
inline std::string connection_string_safe() const
{
std::string connect_str;
if (host_ && (*host_).size()) connect_str += "host=" + *host_;
if (port_ && (*port_).size()) connect_str += " port=" + *port_;
if (dbname_ && (*dbname_).size()) connect_str += " dbname=" + *dbname_;
if (user_ && (*user_).size()) connect_str += " user=" + *user_;
if (pass_ && (*pass_).size()) connect_str += " password=" + *pass_;
if (connect_timeout_ && (*connect_timeout_).size())
if (host_ && !host_->empty()) connect_str += "host=" + *host_;
if (port_ && !port_->empty()) connect_str += " port=" + *port_;
if (dbname_ && !dbname_->empty()) connect_str += " dbname=" + *dbname_;
if (user_ && !user_->empty()) connect_str += " user=" + *user_;
if (connect_timeout_ && !connect_timeout_->empty())
connect_str +=" connect_timeout=" + *connect_timeout_;
return connect_str;
}
@ -109,24 +111,25 @@ public:
bool registerPool(const ConnectionCreator<Connection>& creator,unsigned initialSize,unsigned maxSize)
{
#ifdef MAPNIK_THREADSAFE
//mutex::scoped_lock lock(mutex_);
#endif
if (pools_.find(creator.id())==pools_.end())
{
return pools_.insert(std::make_pair(creator.id(),
boost::make_shared<PoolType>(creator,initialSize,maxSize))).second;
}
ContType::const_iterator itr = pools_.find(creator.id());
if (itr != pools_.end())
{
itr->second->set_initial_size(initialSize);
itr->second->set_max_size(maxSize);
}
else
{
return pools_.insert(
std::make_pair(creator.id(),
boost::make_shared<PoolType>(creator,initialSize,maxSize))).second;
}
return false;
}
boost::shared_ptr<PoolType> getPool(std::string const& key)
{
#ifdef MAPNIK_THREADSAFE
//mutex::scoped_lock lock(mutex_);
#endif
ContType::const_iterator itr=pools_.find(key);
if (itr!=pools_.end())
{
@ -136,19 +139,6 @@ public:
return emptyPool;
}
HolderType get(std::string const& key)
{
#ifdef MAPNIK_THREADSAFE
//mutex::scoped_lock lock(mutex_);
#endif
ContType::const_iterator itr=pools_.find(key);
if (itr!=pools_.end())
{
boost::shared_ptr<PoolType> pool=itr->second;
return pool->borrowObject();
}
return HolderType();
}
ConnectionManager() {}
private:
ConnectionManager(const ConnectionManager&);

View file

@ -68,22 +68,22 @@ postgis_datasource::postgis_datasource(parameters const& params, bool bind)
srid_(*params_.get<int>("srid", 0)),
extent_initialized_(false),
simplify_geometries_(false),
desc_(*params_.get<std::string>("type"), "utf-8"),
creator_(params.get<std::string>("host"),
params.get<std::string>("port"),
params.get<std::string>("dbname"),
params.get<std::string>("user"),
params.get<std::string>("password"),
params.get<std::string>("connect_timeout", "4")),
bbox_token_("!bbox!"),
scale_denom_token_("!scale_denominator!"),
pixel_width_token_("!pixel_width!"),
pixel_height_token_("!pixel_height!"),
persist_connection_(*params_.get<mapnik::boolean>("persist_connection", true)),
extent_from_subquery_(*params_.get<mapnik::boolean>("extent_from_subquery", false)),
// params below are for testing purposes only (will likely be removed at any time)
intersect_min_scale_(*params_.get<int>("intersect_min_scale", 0)),
intersect_max_scale_(*params_.get<int>("intersect_max_scale", 0))
desc_(*params_.get<std::string>("type"), "utf-8"),
creator_(params.get<std::string>("host"),
params.get<std::string>("port"),
params.get<std::string>("dbname"),
params.get<std::string>("user"),
params.get<std::string>("password"),
params.get<std::string>("connect_timeout", "4")),
bbox_token_("!bbox!"),
scale_denom_token_("!scale_denominator!"),
pixel_width_token_("!pixel_width!"),
pixel_height_token_("!pixel_height!"),
persist_connection_(*params_.get<mapnik::boolean>("persist_connection", true)),
extent_from_subquery_(*params_.get<mapnik::boolean>("extent_from_subquery", false)),
// params below are for testing purposes only (will likely be removed at any time)
intersect_min_scale_(*params_.get<int>("intersect_min_scale", 0)),
intersect_max_scale_(*params_.get<int>("intersect_max_scale", 0))
{
if (table_.empty())
{
@ -128,7 +128,7 @@ void postgis_datasource::bind() const
if (conn && conn->isOK())
{
PoolGuard<shared_ptr<Connection>,
shared_ptr< Pool<Connection,ConnectionCreator> > > guard(conn, pool);
shared_ptr< Pool<Connection,ConnectionCreator> > > guard(conn, pool);
desc_.set_encoding(conn->client_encoding());
@ -160,46 +160,49 @@ void postgis_datasource::bind() const
#ifdef MAPNIK_STATS
mapnik::progress_timer __stats2__(std::clog, "postgis_datasource::bind(get_srid_and_geometry_column)");
#endif
std::ostringstream s;
s << "SELECT f_geometry_column, srid FROM "
<< GEOMETRY_COLUMNS <<" WHERE f_table_name='"
<< mapnik::sql_utils::unquote_double(geometry_table_)
<< "'";
if (! schema_.empty())
try
{
s << " AND f_table_schema='"
<< mapnik::sql_utils::unquote_double(schema_)
s << "SELECT f_geometry_column, srid FROM "
<< GEOMETRY_COLUMNS <<" WHERE f_table_name='"
<< mapnik::sql_utils::unquote_double(geometry_table_)
<< "'";
}
if (! geometry_field_.empty())
{
s << " AND f_geometry_column='"
<< mapnik::sql_utils::unquote_double(geometry_field_)
<< "'";
}
shared_ptr<ResultSet> rs = conn->executeQuery(s.str());
if (rs->next())
{
geometryColumn_ = rs->getValue("f_geometry_column");
if (srid_ == 0)
if (! schema_.empty())
{
const char* srid_c = rs->getValue("srid");
if (srid_c != NULL)
s << " AND f_table_schema='"
<< mapnik::sql_utils::unquote_double(schema_)
<< "'";
}
if (! geometry_field_.empty())
{
s << " AND f_geometry_column='"
<< mapnik::sql_utils::unquote_double(geometry_field_)
<< "'";
}
shared_ptr<ResultSet> rs = conn->executeQuery(s.str());
if (rs->next())
{
geometryColumn_ = rs->getValue("f_geometry_column");
if (srid_ == 0)
{
int result = 0;
if (mapnik::util::string2int(srid_c, result))
const char* srid_c = rs->getValue("srid");
if (srid_c != NULL)
{
srid_ = result;
int result = 0;
if (mapnik::util::string2int(srid_c, result))
{
srid_ = result;
}
}
}
}
rs->close();
}
catch (mapnik::datasource_exception const& ex) {
// let this pass on query error and use the fallback below
MAPNIK_LOG_WARN(postgis) << "postgis_datasource: metadata query failed: " << ex.what();
}
rs->close();
// If we still do not know the srid then we can try to fetch
// it from the 'table_' parameter, which should work even if it is
@ -386,6 +389,7 @@ void postgis_datasource::bind() const
case 701: // float8
case 1700: // numeric
desc_.add_descriptor(attribute_descriptor(fld_name, mapnik::Double));
break;
case 1042: // bpchar
case 1043: // varchar
case 25: // text
@ -649,14 +653,14 @@ featureset_ptr postgis_datasource::features(const query& q) const
s << "SELECT ST_AsBinary(";
if (simplify_geometries_) {
s << "ST_Simplify(";
s << "ST_Simplify(";
}
s << "\"" << geometryColumn_ << "\"";
if (simplify_geometries_) {
const double tolerance = std::min(px_gw, px_gh) / 2.0;
s << ", " << tolerance << ")";
const double tolerance = std::min(px_gw, px_gh) / 2.0;
s << ", " << tolerance << ")";
}
s << ") AS geom";
@ -703,7 +707,16 @@ featureset_ptr postgis_datasource::features(const query& q) const
}
else
{
throw mapnik::datasource_exception("Postgis Plugin: bad connection");
std::string err_msg = "Postgis Plugin:";
if (conn)
{
err_msg += conn->status();
}
else
{
err_msg += " Null connection";
}
throw mapnik::datasource_exception(err_msg);
}
}
@ -919,50 +932,53 @@ boost::optional<mapnik::datasource::geometry_t> postgis_datasource::get_geometry
std::ostringstream s;
std::string g_type;
s << "SELECT lower(type) as type FROM "
<< GEOMETRY_COLUMNS <<" WHERE f_table_name='"
<< mapnik::sql_utils::unquote_double(geometry_table_)
<< "'";
if (! schema_.empty())
try
{
s << " AND f_table_schema='"
<< mapnik::sql_utils::unquote_double(schema_)
s << "SELECT lower(type) as type FROM "
<< GEOMETRY_COLUMNS <<" WHERE f_table_name='"
<< mapnik::sql_utils::unquote_double(geometry_table_)
<< "'";
if (! schema_.empty())
{
s << " AND f_table_schema='"
<< mapnik::sql_utils::unquote_double(schema_)
<< "'";
}
if (! geometry_field_.empty())
{
s << " AND f_geometry_column='"
<< mapnik::sql_utils::unquote_double(geometry_field_)
<< "'";
}
shared_ptr<ResultSet> rs = conn->executeQuery(s.str());
if (rs->next())
{
g_type = rs->getValue("type");
if (boost::algorithm::contains(g_type, "line"))
{
result.reset(mapnik::datasource::LineString);
return result;
}
else if (boost::algorithm::contains(g_type, "point"))
{
result.reset(mapnik::datasource::Point);
return result;
}
else if (boost::algorithm::contains(g_type, "polygon"))
{
result.reset(mapnik::datasource::Polygon);
return result;
}
else // geometry
{
result.reset(mapnik::datasource::Collection);
return result;
}
}
}
if (! geometry_field_.empty())
{
s << " AND f_geometry_column='"
<< mapnik::sql_utils::unquote_double(geometry_field_)
<< "'";
}
shared_ptr<ResultSet> rs = conn->executeQuery(s.str());
if (rs->next())
{
g_type = rs->getValue("type");
if (boost::algorithm::contains(g_type, "line"))
{
result.reset(mapnik::datasource::LineString);
return result;
}
else if (boost::algorithm::contains(g_type, "point"))
{
result.reset(mapnik::datasource::Point);
return result;
}
else if (boost::algorithm::contains(g_type, "polygon"))
{
result.reset(mapnik::datasource::Polygon);
return result;
}
else // geometry
{
result.reset(mapnik::datasource::Collection);
return result;
}
catch (mapnik::datasource_exception const& ex) {
// let this pass on query error and use the fallback below
MAPNIK_LOG_WARN(postgis) << "postgis_datasource: metadata query failed: " << ex.what();
}
// fallback to querying first several features

View file

@ -14,7 +14,8 @@ plugin_env = plugin_base.Clone()
plugin_sources = Split(
"""
%(PLUGIN_NAME)s_datasource.cpp
%(PLUGIN_NAME)s_featureset.cpp
%(PLUGIN_NAME)s_featureset.cpp
%(PLUGIN_NAME)s_utils.cpp
""" % locals()
)

View file

@ -69,38 +69,34 @@ void python_datasource::bind() const
// if no factory callable is defined, bind is a nop
if (factory_.empty()) return;
// split factory at ':' to parse out module and callable
std::vector<std::string> factory_split;
split(factory_split, factory_, is_any_of(":"));
if ((factory_split.size() < 1) || (factory_split.size() > 2))
{
// FIMXE: is this appropriate error reporting?
std::cerr << "python: factory string must be of the form '[module:]callable' when parsing \""
<< factory_ << '"' << std::endl;
return;
}
// extract the module and the callable
str module_name("__main__"), callable_name;
if (factory_split.size() == 1)
{
callable_name = str(factory_split[0]);
}
else
{
module_name = str(factory_split[0]);
callable_name = str(factory_split[1]);
}
try
{
// split factory at ':' to parse out module and callable
std::vector<std::string> factory_split;
split(factory_split, factory_, is_any_of(":"));
if ((factory_split.size() < 1) || (factory_split.size() > 2))
{
throw mapnik::datasource_exception(
std::string("python: factory string must be of the form '[module:]callable' when parsing \"")
+ factory_ + '"');
}
// extract the module and the callable
str module_name("__main__"), callable_name;
if (factory_split.size() == 1)
{
callable_name = str(factory_split[0]);
}
else
{
module_name = str(factory_split[0]);
callable_name = str(factory_split[1]);
}
ensure_gil lock;
// import the main module from Python (in case we're embedding the
// interpreter directly) and also import the callable.
object main_module = import("__main__");
object callable_module = import(module_name);
object callable = callable_module.attr(callable_name);
// prepare the arguments
dict kwargs;
typedef std::map<std::string, std::string>::value_type kv_type;
@ -112,6 +108,10 @@ void python_datasource::bind() const
// get our wrapped data source
datasource_ = callable(*boost::python::make_tuple(), **kwargs);
}
catch ( error_already_set )
{
throw mapnik::datasource_exception(extractException());
}
is_bound_ = true;
}
@ -124,11 +124,18 @@ mapnik::datasource::datasource_t python_datasource::type() const
if (!is_bound_) bind();
ensure_gil lock;
try
{
ensure_gil lock;
object data_type = datasource_.attr("data_type");
long data_type_integer = extract<long>(data_type);
return mapnik::datasource::datasource_t(data_type_integer);
}
catch ( error_already_set )
{
throw mapnik::datasource_exception(extractException());
}
object data_type = datasource_.attr("data_type");
long data_type_integer = extract<long>(data_type);
return mapnik::datasource::datasource_t(data_type_integer);
}
mapnik::box2d<double> python_datasource::envelope() const
@ -137,8 +144,15 @@ mapnik::box2d<double> python_datasource::envelope() const
if (!is_bound_) bind();
ensure_gil lock;
return extract<mapnik::box2d<double> >(datasource_.attr("envelope"));
try
{
ensure_gil lock;
return extract<mapnik::box2d<double> >(datasource_.attr("envelope"));
}
catch ( error_already_set )
{
throw mapnik::datasource_exception(extractException());
}
}
boost::optional<mapnik::datasource::geometry_t> python_datasource::get_geometry_type() const
@ -149,20 +163,27 @@ boost::optional<mapnik::datasource::geometry_t> python_datasource::get_geometry_
if (!is_bound_) bind();
ensure_gil lock;
// if the datasource object has no geometry_type attribute, return a 'none' value
if (!PyObject_HasAttrString(datasource_.ptr(), "geometry_type"))
return return_type();
object py_geometry_type = datasource_.attr("geometry_type");
// if the attribute value is 'None', return a 'none' value
if (py_geometry_type.ptr() == object().ptr())
return return_type();
long geom_type_integer = extract<long>(py_geometry_type);
return mapnik::datasource::geometry_t(geom_type_integer);
try
{
ensure_gil lock;
// if the datasource object has no geometry_type attribute, return a 'none' value
if (!PyObject_HasAttrString(datasource_.ptr(), "geometry_type"))
{
return return_type();
}
object py_geometry_type = datasource_.attr("geometry_type");
// if the attribute value is 'None', return a 'none' value
if (py_geometry_type.ptr() == object().ptr())
{
return return_type();
}
long geom_type_integer = extract<long>(py_geometry_type);
return mapnik::datasource::geometry_t(geom_type_integer);
}
catch ( error_already_set )
{
throw mapnik::datasource_exception(extractException());
}
}
mapnik::featureset_ptr python_datasource::features(mapnik::query const& q) const
@ -171,22 +192,27 @@ mapnik::featureset_ptr python_datasource::features(mapnik::query const& q) const
if (!is_bound_) bind();
// if the query box intersects our world extent then query for features
if (envelope().intersects(q.get_bbox()))
try
{
ensure_gil lock;
object features(datasource_.attr("features")(q));
// if 'None' was returned, return an empty feature set
if(features.ptr() == object().ptr())
return mapnik::featureset_ptr();
return boost::make_shared<python_featureset>(features);
// if the query box intersects our world extent then query for features
if (envelope().intersects(q.get_bbox()))
{
ensure_gil lock;
object features(datasource_.attr("features")(q));
// if 'None' was returned, return an empty feature set
if(features.ptr() == object().ptr())
{
return mapnik::featureset_ptr();
}
return boost::make_shared<python_featureset>(features);
}
// otherwise return an empty featureset pointer
return mapnik::featureset_ptr();
}
catch ( error_already_set )
{
throw mapnik::datasource_exception(extractException());
}
// otherwise return an empty featureset pointer
return mapnik::featureset_ptr();
}
mapnik::featureset_ptr python_datasource::features_at_point(mapnik::coord2d const& pt, double tol) const
@ -195,14 +221,21 @@ mapnik::featureset_ptr python_datasource::features_at_point(mapnik::coord2d cons
if (!is_bound_) bind();
ensure_gil lock;
try
{
ensure_gil lock;
object features(datasource_.attr("features_at_point")(pt));
// if we returned none, return an empty set
if(features.ptr() == object().ptr())
{
return mapnik::featureset_ptr();
}
// otherwise, return a feature set which can iterate over the iterator
return boost::make_shared<python_featureset>(features);
}
catch ( error_already_set )
{
throw mapnik::datasource_exception(extractException());
}
object features(datasource_.attr("features_at_point")(pt));
// if we returned none, return an empty set
if(features.ptr() == object().ptr())
return mapnik::featureset_ptr();
// otherwise, return a feature set which can iterate over the iterator
return boost::make_shared<python_featureset>(features);
}

View file

@ -0,0 +1,23 @@
#include "python_utils.hpp"
std::string extractException()
{
using namespace boost::python;
PyObject *exc,*val,*tb;
PyErr_Fetch(&exc,&val,&tb);
PyErr_NormalizeException(&exc,&val,&tb);
handle<> hexc(exc),hval(allow_null(val)),htb(allow_null(tb));
if(!hval)
{
return extract<std::string>(str(hexc));
}
else
{
object traceback(import("traceback"));
object format_exception(traceback.attr("format_exception"));
object formatted_list(format_exception(hexc,hval,htb));
object formatted(str("").join(formatted_list));
return extract<std::string>(formatted);
}
}

View file

@ -13,4 +13,6 @@ class ensure_gil
PyGILState_STATE gil_state_;
};
std::string extractException();
#endif // PYTHON_UTILS_HPP

View file

@ -57,7 +57,7 @@ shape_featureset<filterT>::shape_featureset(filterT const& filter,
template <typename filterT>
feature_ptr shape_featureset<filterT>::next()
{
if (row_limit_ && count_ > row_limit_)
if (row_limit_ && count_ >= row_limit_)
{
return feature_ptr();
}

View file

@ -75,7 +75,7 @@ shape_index_featureset<filterT>::shape_index_featureset(filterT const& filter,
template <typename filterT>
feature_ptr shape_index_featureset<filterT>::next()
{
if (row_limit_ && count_ > row_limit_)
if (row_limit_ && count_ >= row_limit_)
{
return feature_ptr();
}

View file

@ -26,6 +26,7 @@
#include <mapnik/agg_rasterizer.hpp>
#include <mapnik/debug.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/geom_util.hpp>
#include <mapnik/expression_evaluator.hpp>
#include <mapnik/vertex_converters.hpp>
@ -136,10 +137,7 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
}
converter.template set<transform_tag>(); //always transform
if (sym.smooth() > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
BOOST_FOREACH(geometry_type & geom, feature.paths())
{
converter.apply(geom);
}
apply_markers_multi(feature, converter, sym);
}
else
{
@ -172,10 +170,7 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
}
converter.template set<transform_tag>(); //always transform
if (sym.smooth() > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
BOOST_FOREACH(geometry_type & geom, feature.paths())
{
converter.apply(geom);
}
apply_markers_multi(feature, converter, sym);
}
}
else // raster markers
@ -207,11 +202,7 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
}
converter.template set<transform_tag>(); //always transform
if (sym.smooth() > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
BOOST_FOREACH(geometry_type & geom, feature.paths())
{
converter.apply(geom);
}
apply_markers_multi(feature, converter, sym);
}
}
}

View file

@ -82,7 +82,10 @@ void agg_renderer<T>::process(raster_symbolizer const& sym,
}
if (premultiply_source)
{
agg::rendering_buffer buffer(source->data_.getBytes(),source->data_.width(),source->data_.height(),source->data_.width() * 4);
agg::rendering_buffer buffer(source->data_.getBytes(),
source->data_.width(),
source->data_.height(),
source->data_.width() * 4);
agg::pixfmt_rgba32 pixf(buffer);
pixf.premultiply();
}
@ -100,7 +103,10 @@ void agg_renderer<T>::process(raster_symbolizer const& sym,
{
if (scaling_method == SCALING_BILINEAR8)
{
scale_image_bilinear8<image_data_32>(target.data_,source->data_, 0.0, 0.0);
scale_image_bilinear8<image_data_32>(target.data_,
source->data_,
0.0,
0.0);
}
else
{

View file

@ -100,6 +100,7 @@ else: # unix, non-macos
source = Split(
"""
miniz_png.cpp
color.cpp
css_color_grammar.cpp
conversions.cpp
@ -292,26 +293,26 @@ source += Split(
""")
# https://github.com/mapnik/mapnik/issues/1438
#if env['SVG_RENDERER']: # svg backend
# source += Split(
# """
# svg/output/svg_renderer.cpp
# svg/output/svg_generator.cpp
# svg/output/svg_output_attributes.cpp
# svg/output/process_symbolizers.cpp
# svg/output/process_building_symbolizer.cpp
# svg/output/process_line_pattern_symbolizer.cpp
# svg/output/process_line_symbolizer.cpp
# svg/output/process_markers_symbolizer.cpp
# svg/output/process_point_symbolizer.cpp
# svg/output/process_polygon_pattern_symbolizer.cpp
# svg/output/process_polygon_symbolizer.cpp
# svg/output/process_raster_symbolizer.cpp
# svg/output/process_shield_symbolizer.cpp
# svg/output/process_text_symbolizer.cpp
# """)
# lib_env.Append(CXXFLAGS = '-DSVG_RENDERER')
# libmapnik_cxxflags.append('-DSVG_RENDERER')
if env['SVG_RENDERER']: # svg backend
source += Split(
"""
svg/output/svg_renderer.cpp
svg/output/svg_generator.cpp
svg/output/svg_output_attributes.cpp
svg/output/process_symbolizers.cpp
svg/output/process_building_symbolizer.cpp
svg/output/process_line_pattern_symbolizer.cpp
svg/output/process_line_symbolizer.cpp
svg/output/process_markers_symbolizer.cpp
svg/output/process_point_symbolizer.cpp
svg/output/process_polygon_pattern_symbolizer.cpp
svg/output/process_polygon_symbolizer.cpp
svg/output/process_raster_symbolizer.cpp
svg/output/process_shield_symbolizer.cpp
svg/output/process_text_symbolizer.cpp
""")
lib_env.Append(CXXFLAGS = '-DSVG_RENDERER')
libmapnik_cxxflags.append('-DSVG_RENDERER')
if env['XMLPARSER'] == 'libxml2' and env['HAS_LIBXML2']:
source += Split(

View file

@ -1750,10 +1750,7 @@ void cairo_renderer_base::process(markers_symbolizer const& sym,
}
converter.set<transform_tag>(); //always transform
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
BOOST_FOREACH(geometry_type & geom, feature.paths())
{
converter.apply(geom);
}
apply_markers_multi(feature, converter, sym);
}
else
{
@ -1778,10 +1775,7 @@ void cairo_renderer_base::process(markers_symbolizer const& sym,
}
converter.set<transform_tag>(); //always transform
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
BOOST_FOREACH(geometry_type & geom, feature.paths())
{
converter.apply(geom);
}
apply_markers_multi(feature, converter, sym);
}
}
else // raster markers
@ -1811,10 +1805,7 @@ void cairo_renderer_base::process(markers_symbolizer const& sym,
}
converter.set<transform_tag>(); //always transform
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
BOOST_FOREACH(geometry_type & geom, feature.paths())
{
converter.apply(geom);
}
apply_markers_multi(feature, converter, sym);
}
}
}

View file

@ -36,6 +36,7 @@
// stl
#include <algorithm>
#include <iostream>
#include <sstream>
#include <stdexcept>
namespace mapnik {
@ -73,8 +74,17 @@ datasource_ptr datasource_cache::create(const parameters& params, bool bind)
std::map<std::string,boost::shared_ptr<PluginInfo> >::iterator itr=plugins_.find(*type);
if ( itr == plugins_.end() )
{
throw config_error(std::string("Could not create datasource. No plugin ") +
"found for type '" + * type + "' (searched in: " + plugin_directories() + ")");
std::ostringstream s;
s << "Could not create datasource for type: '" << *type << "'";
if (plugin_directories_.empty())
{
s << " (no datasource plugin directories have been successfully registered)";
}
else
{
s << " (searched for datasource plugins in '" << plugin_directories() << "')";
}
throw config_error(s.str());
}
if ( ! itr->second->handle())

View file

@ -112,7 +112,7 @@ struct expression_string : boost::static_visitor<void>
#else
str_ += x.pattern.str();
str_ +="','";
str_ += x.pattern.str();
str_ += x.format;
#endif
str_ +="')";
}

View file

@ -65,6 +65,18 @@ hit_grid<T>::hit_grid(hit_grid<T> const& rhs)
data_.set(base_mask);
}
template <typename T>
void hit_grid<T>::clear()
{
painted_ = false;
f_keys_.clear();
features_.clear();
names_.clear();
f_keys_[base_mask] = "";
data_.set(base_mask);
ctx_ = boost::make_shared<mapnik::context_type>();
}
template <typename T>
void hit_grid<T>::add_feature(mapnik::feature_impl & feature)
{

View file

@ -163,10 +163,7 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
}
converter.template set<transform_tag>(); //always transform
if (sym.smooth() > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
BOOST_FOREACH(geometry_type & geom, feature.paths())
{
converter.apply(geom);
}
apply_markers_multi(feature, converter, sym);
}
else
{
@ -208,10 +205,7 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
}
converter.template set<transform_tag>(); //always transform
if (sym.smooth() > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
BOOST_FOREACH(geometry_type & geom, feature.paths())
{
converter.apply(geom);
}
apply_markers_multi(feature, converter, sym);
}
}
else // raster markers
@ -256,10 +250,7 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
}
converter.template set<transform_tag>(); //always transform
if (sym.smooth() > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
BOOST_FOREACH(geometry_type & geom, feature.paths())
{
converter.apply(geom);
}
apply_markers_multi(feature, converter, sym);
}
}
}

View file

@ -29,6 +29,7 @@ extern "C"
#include <mapnik/image_util.hpp>
#include <mapnik/png_io.hpp>
#include <mapnik/tiff_io.hpp>
#include <mapnik/image_data.hpp>
#include <mapnik/graphics.hpp>
#include <mapnik/memory.hpp>
#include <mapnik/image_view.hpp>
@ -111,7 +112,8 @@ void handle_png_options(std::string const& type,
int * strategy,
int * trans_mode,
double * gamma,
bool * use_octree)
bool * use_octree,
bool * use_miniz)
{
if (type == "png" || type == "png24" || type == "png32")
{
@ -138,19 +140,20 @@ void handle_png_options(std::string const& type,
{
*use_octree = true;
}
else if (t == "e=miniz")
{
*use_miniz = true;
}
else if (boost::algorithm::starts_with(t, "c="))
{
if (*colors < 0)
throw ImageWriterException("invalid color parameter: unavailable for true color images");
if (!mapnik::util::string2int(t.substr(2),*colors) || *colors < 0 || *colors > 256)
if (!mapnik::util::string2int(t.substr(2),*colors) || *colors < 1 || *colors > 256)
throw ImageWriterException("invalid color parameter: " + t.substr(2));
}
else if (boost::algorithm::starts_with(t, "t="))
{
if (*colors < 0)
throw ImageWriterException("invalid trans_mode parameter: unavailable for true color images");
if (!mapnik::util::string2int(t.substr(2),*trans_mode) || *trans_mode < 0 || *trans_mode > 2)
throw ImageWriterException("invalid trans_mode parameter: " + t.substr(2));
}
@ -173,9 +176,9 @@ void handle_png_options(std::string const& type,
*/
if (!mapnik::util::string2int(t.substr(2),*compression)
|| *compression < Z_DEFAULT_COMPRESSION
|| *compression > Z_BEST_COMPRESSION)
|| *compression > 10) // use 10 here rather than Z_BEST_COMPRESSION (9) to allow for MZ_UBER_COMPRESSION
{
throw ImageWriterException("invalid compression parameter: " + t.substr(2) + " (only -1 through 9 are valid)");
throw ImageWriterException("invalid compression parameter: " + t.substr(2) + " (only -1 through 10 are valid)");
}
}
else if (boost::algorithm::starts_with(t, "s="))
@ -197,12 +200,20 @@ void handle_png_options(std::string const& type,
{
*strategy = Z_RLE;
}
else if (s == "fixed")
{
*strategy = Z_FIXED;
}
else
{
throw ImageWriterException("invalid compression strategy parameter: " + s);
}
}
}
if ((*use_miniz == false) && *compression > Z_BEST_COMPRESSION)
{
throw ImageWriterException("invalid compression value: (only -1 through 9 are valid)");
}
}
}
@ -224,6 +235,7 @@ void save_to_stream(T const& image,
int trans_mode = -1;
double gamma = -1;
bool use_octree = true;
bool use_miniz = false;
handle_png_options(t,
&colors,
@ -231,16 +243,25 @@ void save_to_stream(T const& image,
&strategy,
&trans_mode,
&gamma,
&use_octree);
&use_octree,
&use_miniz);
if (palette.valid())
save_as_png8_pal(stream, image, palette, compression, strategy);
{
save_as_png8_pal(stream, image, palette, compression, strategy, use_miniz);
}
else if (colors < 0)
save_as_png(stream, image, compression, strategy);
{
save_as_png(stream, image, compression, strategy, trans_mode, use_miniz);
}
else if (use_octree)
save_as_png8_oct(stream, image, colors, compression, strategy);
{
save_as_png8_oct(stream, image, colors, compression, strategy, trans_mode, use_miniz);
}
else
save_as_png8_hex(stream, image, colors, compression, strategy, trans_mode, gamma);
{
save_as_png8_hex(stream, image, colors, compression, strategy, trans_mode, gamma, use_miniz);
}
}
else if (boost::algorithm::starts_with(t, "tif"))
{
@ -270,11 +291,12 @@ void save_to_stream(T const& image,
if (t == "png" || boost::algorithm::starts_with(t, "png"))
{
int colors = 256;
int compression = Z_DEFAULT_COMPRESSION;
int compression = Z_DEFAULT_COMPRESSION; // usually mapped to z=6 in zlib
int strategy = Z_DEFAULT_STRATEGY;
int trans_mode = -1;
double gamma = -1;
bool use_octree = true;
bool use_miniz = false;
handle_png_options(t,
&colors,
@ -282,14 +304,21 @@ void save_to_stream(T const& image,
&strategy,
&trans_mode,
&gamma,
&use_octree);
&use_octree,
&use_miniz);
if (colors < 0)
save_as_png(stream, image, compression, strategy);
{
save_as_png(stream, image, compression, strategy, trans_mode, use_miniz);
}
else if (use_octree)
save_as_png8_oct(stream, image, colors, compression, strategy);
{
save_as_png8_oct(stream, image, colors, compression, strategy, trans_mode, use_miniz);
}
else
save_as_png8_hex(stream, image, colors, compression, strategy, trans_mode, gamma);
{
save_as_png8_hex(stream, image, colors, compression, strategy, trans_mode, gamma, use_miniz);
}
}
else if (boost::algorithm::starts_with(t, "tif"))
{

View file

@ -1050,6 +1050,10 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& sym)
marker_placement_e placement = sym.get_attr<marker_placement_e>("placement",symbol.get_marker_placement());
symbol.set_marker_placement(placement);
marker_multi_policy_e mpolicy = sym.get_attr<marker_multi_policy_e>("multi-policy",symbol.get_marker_multi_policy());
symbol.set_marker_multi_policy(mpolicy);
parse_symbolizer_base(symbol, sym);
rule.append(symbol);
}
@ -1664,7 +1668,7 @@ void map_parser::ensure_exists(std::string const& file_path)
{
if (!boost::filesystem::exists(file_path))
{
throw mapnik::config_error("point-file could not be found: '" + file_path + "'");
throw mapnik::config_error("file could not be found: '" + file_path + "'");
}
}
}

View file

@ -238,7 +238,9 @@ unsigned Map::height() const
void Map::set_width(unsigned width)
{
if (width >= MIN_MAPSIZE && width <= MAX_MAPSIZE)
if (width != width_ &&
width >= MIN_MAPSIZE &&
width <= MAX_MAPSIZE)
{
width_=width;
fixAspectRatio();
@ -247,7 +249,9 @@ void Map::set_width(unsigned width)
void Map::set_height(unsigned height)
{
if (height >= MIN_MAPSIZE && height <= MAX_MAPSIZE)
if (height != height_ &&
height >= MIN_MAPSIZE &&
height <= MAX_MAPSIZE)
{
height_=height;
fixAspectRatio();
@ -256,8 +260,12 @@ void Map::set_height(unsigned height)
void Map::resize(unsigned width,unsigned height)
{
if (width >= MIN_MAPSIZE && width <= MAX_MAPSIZE &&
height >= MIN_MAPSIZE && height <= MAX_MAPSIZE)
if (width != width_ &&
height != height_ &&
width >= MIN_MAPSIZE &&
width <= MAX_MAPSIZE &&
height >= MIN_MAPSIZE &&
height <= MAX_MAPSIZE)
{
width_=width;
height_=height;
@ -346,8 +354,10 @@ void Map::zoom_all()
{
try
{
if (!layers_.size() > 0)
if (layers_.empty())
{
return;
}
projection proj0(srs_);
box2d<double> ext;
bool success = false;
@ -575,7 +585,7 @@ featureset_ptr Map::query_point(unsigned index, double x, double y) const
{
std::ostringstream s;
s << "Invalid layer index passed to query_point: '" << index << "'";
if (layers_.size() > 0) s << " for map with " << layers_.size() << " layers(s)";
if (!layers_.empty()) s << " for map with " << layers_.size() << " layers(s)";
else s << " (map has no layers)";
throw std::out_of_range(s.str());
}

View file

@ -37,6 +37,15 @@ static const char * marker_placement_strings[] = {
IMPLEMENT_ENUM( marker_placement_e, marker_placement_strings )
static const char * marker_multi_policy_strings[] = {
"each",
"whole",
"largest",
""
};
IMPLEMENT_ENUM( marker_multi_policy_e, marker_multi_policy_strings )
markers_symbolizer::markers_symbolizer()
: symbolizer_with_image(parse_path("shape://ellipse")),
symbolizer_base(),
@ -46,7 +55,10 @@ markers_symbolizer::markers_symbolizer()
allow_overlap_(false),
spacing_(100.0),
max_error_(0.2),
marker_p_(MARKER_POINT_PLACEMENT) { }
marker_p_(MARKER_POINT_PLACEMENT),
// TODO: consider defaulting to MARKER_WHOLE_MULTI,
// for backward compatibility with 2.0.0
marker_mp_(MARKER_EACH_MULTI) { }
markers_symbolizer::markers_symbolizer(path_expression_ptr const& filename)
: symbolizer_with_image(filename),
@ -57,7 +69,10 @@ markers_symbolizer::markers_symbolizer(path_expression_ptr const& filename)
allow_overlap_(false),
spacing_(100.0),
max_error_(0.2),
marker_p_(MARKER_POINT_PLACEMENT) { }
marker_p_(MARKER_POINT_PLACEMENT),
// TODO: consider defaulting to MARKER_WHOLE_MULTI,
// for backward compatibility with 2.0.0
marker_mp_(MARKER_EACH_MULTI) { }
markers_symbolizer::markers_symbolizer(markers_symbolizer const& rhs)
: symbolizer_with_image(rhs),
@ -71,7 +86,8 @@ markers_symbolizer::markers_symbolizer(markers_symbolizer const& rhs)
fill_(rhs.fill_),
fill_opacity_(rhs.fill_opacity_),
stroke_(rhs.stroke_),
marker_p_(rhs.marker_p_) {}
marker_p_(rhs.marker_p_),
marker_mp_(rhs.marker_mp_) {}
void markers_symbolizer::set_ignore_placement(bool ignore_placement)
{
@ -173,4 +189,14 @@ marker_placement_e markers_symbolizer::get_marker_placement() const
return marker_p_;
}
void markers_symbolizer::set_marker_multi_policy(marker_multi_policy_e marker_mp)
{
marker_mp_ = marker_mp;
}
marker_multi_policy_e markers_symbolizer::get_marker_multi_policy() const
{
return marker_mp_;
}
}

View file

@ -62,9 +62,10 @@ struct accumulate_extent
bool first_;
};
memory_datasource::memory_datasource()
memory_datasource::memory_datasource(datasource::datasource_t type)
: datasource(parameters()),
desc_("in-memory datasource","utf-8") {}
desc_("in-memory datasource","utf-8"),
type_(type) {}
memory_datasource::~memory_datasource() {}
@ -77,7 +78,7 @@ void memory_datasource::push(feature_ptr feature)
datasource::datasource_t memory_datasource::type() const
{
return datasource::Vector;
return type_;
}
featureset_ptr memory_datasource::features(const query& q) const

4834
src/miniz.c Normal file

File diff suppressed because it is too large Load diff

365
src/miniz_png.cpp Normal file
View file

@ -0,0 +1,365 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2012 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
*
*****************************************************************************/
// mapnik
#include <mapnik/palette.hpp>
#include <mapnik/miniz_png.hpp>
#include <mapnik/image_data.hpp>
#include <mapnik/image_view.hpp>
// miniz
#define MINIZ_NO_ARCHIVE_APIS
#define MINIZ_NO_STDIO
#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES
#include "miniz.c"
// zlib
#include <zlib.h>
// stl
#include <vector>
#include <iostream>
#include <stdexcept>
namespace mapnik { namespace MiniZ {
PNGWriter::PNGWriter(int level, int strategy)
{
buffer = NULL;
compressor = NULL;
if (level == -1)
{
level = MZ_DEFAULT_LEVEL; // 6
}
else if (level < 0 || level > 10)
{
throw std::runtime_error("compression level must be between 0 and 10");
}
mz_uint flags = s_tdefl_num_probes[level] | (level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0 | TDEFL_WRITE_ZLIB_HEADER;
if (strategy == Z_FILTERED) flags |= TDEFL_FILTER_MATCHES;
else if (strategy == Z_HUFFMAN_ONLY) flags &= ~TDEFL_MAX_PROBES_MASK;
else if (strategy == Z_RLE) flags |= TDEFL_RLE_MATCHES;
else if (strategy == Z_FIXED) flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS;
buffer = (tdefl_output_buffer *)MZ_MALLOC(sizeof(tdefl_output_buffer));
if (buffer == NULL)
{
throw std::bad_alloc();
}
buffer->m_pBuf = NULL;
buffer->m_capacity = 8192;
buffer->m_expandable = MZ_TRUE;
buffer->m_pBuf = (mz_uint8 *)MZ_MALLOC(buffer->m_capacity);
if (buffer->m_pBuf == NULL)
{
throw std::bad_alloc();
}
compressor = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor));
if (compressor == NULL)
{
throw std::bad_alloc();
}
// Reset output buffer.
buffer->m_size = 0;
tdefl_status tdstatus = tdefl_init(compressor, tdefl_output_buffer_putter, buffer, flags);
if (tdstatus != TDEFL_STATUS_OKAY)
{
throw std::runtime_error("tdefl_init failed");
}
// Write preamble.
mz_bool status = tdefl_output_buffer_putter(preamble, 8, buffer);
if (status != MZ_TRUE)
{
throw std::bad_alloc();
}
}
PNGWriter::~PNGWriter()
{
if (compressor)
{
MZ_FREE(compressor);
}
if (buffer)
{
if (buffer->m_pBuf)
{
MZ_FREE(buffer->m_pBuf);
}
MZ_FREE(buffer);
}
}
inline void PNGWriter::writeUInt32BE(mz_uint8 *target, mz_uint32 value)
{
target[0] = (value >> 24) & 0xFF;
target[1] = (value >> 16) & 0xFF;
target[2] = (value >> 8) & 0xFF;
target[3] = value & 0xFF;
}
size_t PNGWriter::startChunk(const mz_uint8 header[], size_t length)
{
size_t start = buffer->m_size;
mz_bool status = tdefl_output_buffer_putter(header, length, buffer);
if (status != MZ_TRUE)
{
throw std::bad_alloc();
}
return start;
}
void PNGWriter::finishChunk(size_t start)
{
// Write chunk length at the beginning of the chunk.
size_t payloadLength = buffer->m_size - start - 4 - 4;
writeUInt32BE(buffer->m_pBuf + start, payloadLength);
// Write CRC32 checksum. Don't include the 4-byte length, but /do/ include
// the 4-byte chunk name.
mz_uint32 crc = mz_crc32(MZ_CRC32_INIT, buffer->m_pBuf + start + 4, payloadLength + 4);
mz_uint8 checksum[] = { crc >> 24, crc >> 16, crc >> 8, crc };
mz_bool status = tdefl_output_buffer_putter(checksum, 4, buffer);
if (status != MZ_TRUE)
{
throw std::bad_alloc();
}
}
void PNGWriter::writeIHDR(mz_uint32 width, mz_uint32 height, mz_uint8 pixel_depth)
{
// Write IHDR chunk.
size_t IHDR = startChunk(IHDR_tpl, 21);
writeUInt32BE(buffer->m_pBuf + IHDR + 8, width);
writeUInt32BE(buffer->m_pBuf + IHDR + 12, height);
if (pixel_depth == 32)
{
// Alpha full color image.
buffer->m_pBuf[IHDR + 16] = 8; // bit depth
buffer->m_pBuf[IHDR + 17] = 6; // color type (6 == true color with alpha)
}
else if (pixel_depth == 24)
{
// Full color image.
buffer->m_pBuf[IHDR + 16] = 8; // bit depth
buffer->m_pBuf[IHDR + 17] = 2; // color type (2 == true color without alpha)
}
else
{
// Paletted image.
buffer->m_pBuf[IHDR + 16] = pixel_depth; // bit depth
buffer->m_pBuf[IHDR + 17] = 3; // color type (3 == indexed color)
}
buffer->m_pBuf[IHDR + 18] = 0; // compression method
buffer->m_pBuf[IHDR + 19] = 0; // filter method
buffer->m_pBuf[IHDR + 20] = 0; // interlace method
finishChunk(IHDR);
}
void PNGWriter::writePLTE(std::vector<rgb> const& palette)
{
// Write PLTE chunk.
size_t PLTE = startChunk(PLTE_tpl, 8);
const mz_uint8 *colors = reinterpret_cast<const mz_uint8 *>(&palette[0]);
mz_bool status = tdefl_output_buffer_putter(colors, palette.size() * 3, buffer);
if (status != MZ_TRUE)
{
throw std::bad_alloc();
}
finishChunk(PLTE);
}
void PNGWriter::writetRNS(std::vector<unsigned> const& alpha)
{
if (alpha.size() == 0)
{
return;
}
std::vector<unsigned char> transparency(alpha.size());
unsigned char transparencySize = 0; // Stores position of biggest to nonopaque value.
for(unsigned i = 0; i < alpha.size(); i++)
{
transparency[i] = alpha[i];
if (alpha[i] < 255)
{
transparencySize = i + 1;
}
}
if (transparencySize > 0)
{
// Write tRNS chunk.
size_t tRNS = startChunk(tRNS_tpl, 8);
mz_bool status = tdefl_output_buffer_putter(&transparency[0], transparencySize, buffer);
if (status != MZ_TRUE)
{
throw std::bad_alloc();
}
finishChunk(tRNS);
}
}
template<typename T>
void PNGWriter::writeIDAT(T const& image)
{
// Write IDAT chunk.
size_t IDAT = startChunk(IDAT_tpl, 8);
mz_uint8 filter_type = 0;
tdefl_status status;
int bytes_per_pixel = sizeof(typename T::pixel_type);
int stride = image.width() * bytes_per_pixel;
for (unsigned int y = 0; y < image.height(); y++)
{
// Write filter_type
status = tdefl_compress_buffer(compressor, &filter_type, 1, TDEFL_NO_FLUSH);
if (status != TDEFL_STATUS_OKAY)
{
throw std::runtime_error("failed to compress image");
}
// Write scanline
status = tdefl_compress_buffer(compressor, (mz_uint8 *)image.getRow(y), stride, TDEFL_NO_FLUSH);
if (status != TDEFL_STATUS_OKAY)
{
throw std::runtime_error("failed to compress image");
}
}
status = tdefl_compress_buffer(compressor, NULL, 0, TDEFL_FINISH);
if (status != TDEFL_STATUS_DONE)
{
throw std::runtime_error("failed to compress image");
}
finishChunk(IDAT);
}
template<typename T>
void PNGWriter::writeIDATStripAlpha(T const& image) {
// Write IDAT chunk.
size_t IDAT = startChunk(IDAT_tpl, 8);
mz_uint8 filter_type = 0;
tdefl_status status;
size_t stride = image.width() * 3;
size_t i, j;
mz_uint8 *scanline = (mz_uint8 *)MZ_MALLOC(stride);
for (unsigned int y = 0; y < image.height(); y++) {
// Write filter_type
status = tdefl_compress_buffer(compressor, &filter_type, 1, TDEFL_NO_FLUSH);
if (status != TDEFL_STATUS_OKAY)
{
MZ_FREE(scanline);
throw std::runtime_error("failed to compress image");
}
// Strip alpha bytes from scanline
mz_uint8 *row = (mz_uint8 *)image.getRow(y);
for (i = 0, j = 0; j < stride; i += 4, j += 3) {
scanline[j] = row[i];
scanline[j+1] = row[i+1];
scanline[j+2] = row[i+2];
}
// Write scanline
status = tdefl_compress_buffer(compressor, scanline, stride, TDEFL_NO_FLUSH);
if (status != TDEFL_STATUS_OKAY) {
MZ_FREE(scanline);
throw std::runtime_error("failed to compress image");
}
}
MZ_FREE(scanline);
status = tdefl_compress_buffer(compressor, NULL, 0, TDEFL_FINISH);
if (status != TDEFL_STATUS_DONE) throw std::runtime_error("failed to compress image");
finishChunk(IDAT);
}
void PNGWriter::writeIEND()
{
// Write IEND chunk.
size_t IEND = startChunk(IEND_tpl, 8);
finishChunk(IEND);
}
void PNGWriter::toStream(std::ostream& stream)
{
stream.write((char *)buffer->m_pBuf, buffer->m_size);
}
const mz_uint8 PNGWriter::preamble[] = {
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a
};
const mz_uint8 PNGWriter::IHDR_tpl[] = {
0x00, 0x00, 0x00, 0x0D, // chunk length
'I', 'H', 'D', 'R', // "IHDR"
0x00, 0x00, 0x00, 0x00, // image width (4 bytes)
0x00, 0x00, 0x00, 0x00, // image height (4 bytes)
0x00, // bit depth (1 byte)
0x00, // color type (1 byte)
0x00, // compression method (1 byte), has to be 0
0x00, // filter method (1 byte)
0x00 // interlace method (1 byte)
};
const mz_uint8 PNGWriter::PLTE_tpl[] = {
0x00, 0x00, 0x00, 0x00, // chunk length
'P', 'L', 'T', 'E' // "IDAT"
};
const mz_uint8 PNGWriter::tRNS_tpl[] = {
0x00, 0x00, 0x00, 0x00, // chunk length
't', 'R', 'N', 'S' // "IDAT"
};
const mz_uint8 PNGWriter::IDAT_tpl[] = {
0x00, 0x00, 0x00, 0x00, // chunk length
'I', 'D', 'A', 'T' // "IDAT"
};
const mz_uint8 PNGWriter::IEND_tpl[] = {
0x00, 0x00, 0x00, 0x00, // chunk length
'I', 'E', 'N', 'D' // "IEND"
};
template void PNGWriter::writeIDAT<image_data_8>(image_data_8 const& image);
template void PNGWriter::writeIDAT<image_view<image_data_8> >(image_view<image_data_8> const& image);
template void PNGWriter::writeIDAT<image_data_32>(image_data_32 const& image);
template void PNGWriter::writeIDAT<image_view<image_data_32> >(image_view<image_data_32> const& image);
template void PNGWriter::writeIDATStripAlpha<image_data_32>(image_data_32 const& image);
template void PNGWriter::writeIDATStripAlpha<image_view<image_data_32> >(image_view<image_data_32> const& image);
}}

View file

@ -75,9 +75,9 @@ bool rgba_palette::valid() const
}
// return color index in returned earlier palette
unsigned rgba_palette::quantize(rgba const& c) const
unsigned char rgba_palette::quantize(rgba const& c) const
{
unsigned index = 0;
unsigned char index = 0;
if (colors_ == 1) return index;
rgba_hash_table::iterator it = color_hashmap_.find(c);

View file

@ -98,6 +98,10 @@ public:
{
set_attr( sym_node, "rasterizer", sym.get_rasterizer() );
}
if ( sym.get_offset() != dfl.get_offset() || explicit_defaults_ )
{
set_attr( sym_node, "offset", sym.get_offset() );
}
serialize_symbolizer_base(sym_node, sym);
}
@ -319,6 +323,10 @@ public:
{
set_attr( sym_node, "placement", sym.get_marker_placement() );
}
if ( sym.get_marker_multi_policy() != dfl.get_marker_multi_policy() || explicit_defaults_ )
{
set_attr( sym_node, "multi-policy", sym.get_marker_multi_policy() );
}
if (sym.get_image_transform())
{
std::string tr_str = sym.get_image_transform_string();

View file

@ -27,13 +27,13 @@ namespace mapnik
{
template <typename T>
void svg_renderer<T>::process(building_symbolizer const& sym,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans)
{
// nothing yet.
}
template void svg_renderer<std::ostream_iterator<char> >::process(building_symbolizer const& sym,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans);
}

View file

@ -27,13 +27,13 @@ namespace mapnik
{
template <typename T>
void svg_renderer<T>::process(line_pattern_symbolizer const& sym,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans)
{
// nothing yet.
}
template void svg_renderer<std::ostream_iterator<char> >::process(line_pattern_symbolizer const& sym,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans);
}

View file

@ -30,7 +30,7 @@ namespace mapnik
*/
template <typename T>
void svg_renderer<T>::process(line_symbolizer const& sym,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans)
{
path_attributes_.set_stroke_color(sym.get_stroke().get_color());
@ -43,6 +43,6 @@ void svg_renderer<T>::process(line_symbolizer const& sym,
}
template void svg_renderer<std::ostream_iterator<char> >::process(line_symbolizer const& sym,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans);
}

View file

@ -27,13 +27,13 @@ namespace mapnik
{
template <typename T>
void svg_renderer<T>::process(markers_symbolizer const& sym,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans)
{
// nothing yet.
}
template void svg_renderer<std::ostream_iterator<char> >::process(markers_symbolizer const& sym,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans);
}

View file

@ -27,13 +27,13 @@ namespace mapnik
{
template <typename T>
void svg_renderer<T>::process(point_symbolizer const& sym,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans)
{
// nothing yet.
}
template void svg_renderer<std::ostream_iterator<char> >::process(point_symbolizer const& sym,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans);
}

View file

@ -27,13 +27,13 @@ namespace mapnik
{
template <typename T>
void svg_renderer<T>::process(polygon_pattern_symbolizer const& sym,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans)
{
// nothing yet.
}
template void svg_renderer<std::ostream_iterator<char> >::process(polygon_pattern_symbolizer const& sym,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans);
}

View file

@ -30,7 +30,7 @@ namespace mapnik
*/
template <typename T>
void svg_renderer<T>::process(polygon_symbolizer const& sym,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans)
{
path_attributes_.set_fill_color(sym.get_fill());
@ -38,6 +38,6 @@ void svg_renderer<T>::process(polygon_symbolizer const& sym,
}
template void svg_renderer<std::ostream_iterator<char> >::process(polygon_symbolizer const& sym,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans);
}

View file

@ -27,13 +27,13 @@ namespace mapnik
{
template <typename T>
void svg_renderer<T>::process(raster_symbolizer const& sym,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans)
{
// nothing yet.
}
template void svg_renderer<std::ostream_iterator<char> >::process(raster_symbolizer const& sym,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans);
}

View file

@ -27,13 +27,13 @@ namespace mapnik
{
template <typename T>
void svg_renderer<T>::process(shield_symbolizer const& sym,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans)
{
// nothing yet.
}
template void svg_renderer<std::ostream_iterator<char> >::process(shield_symbolizer const& sym,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans);
}

View file

@ -27,11 +27,10 @@ namespace mapnik {
template <typename OutputIterator>
bool svg_renderer<OutputIterator>::process(rule::symbolizers const& syms,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans)
{
// svg renderer supports processing of multiple symbolizers.
typedef coord_transform<CoordTransform, geometry_type> path_type;
// process each symbolizer to collect its (path) information.
@ -45,8 +44,8 @@ bool svg_renderer<OutputIterator>::process(rule::symbolizers const& syms,
// generate path output for each geometry of the current feature.
for(unsigned i=0; i<feature.num_geometries(); ++i)
{
geometry_type const& geom = feature.get_geometry(i);
if(geom.size() > 1)
geometry_type & geom = feature.get_geometry(i);
if(geom.size() > 0)
{
path_type path(t_, geom, prj_trans);
generator_.generate_path(path, path_attributes_);
@ -61,7 +60,7 @@ bool svg_renderer<OutputIterator>::process(rule::symbolizers const& syms,
};
template bool svg_renderer<std::ostream_iterator<char> >::process(rule::symbolizers const& syms,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans);
}

View file

@ -27,13 +27,13 @@ namespace mapnik
{
template <typename T>
void svg_renderer<T>::process(text_symbolizer const& sym,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans)
{
// nothing yet.
}
template void svg_renderer<std::ostream_iterator<char> >::process(text_symbolizer const& sym,
Feature const& feature,
mapnik::feature_impl & feature,
proj_transform const& prj_trans);
}

View file

@ -65,17 +65,5 @@ namespace mapnik { namespace svg {
karma::generate(output_iterator_, lit("<rect ") << attributes_grammar << lit("/>\n"), rect_attributes);
}
template <typename OutputIterator>
void svg_generator<OutputIterator>::generate_path(path_type const& path, path_output_attributes const& path_attributes)
{
path_data_grammar data_grammar(path);
path_attributes_grammar attributes_grammar;
path_dash_array_grammar dash_array_grammar;
karma::generate(output_iterator_, lit("<path ") << data_grammar, path);
karma::generate(output_iterator_, lit(" ") << dash_array_grammar, path_attributes.stroke_dasharray());
karma::generate(output_iterator_, lit(" ") << attributes_grammar << lit("/>\n"), path_attributes);
}
template class svg_generator<std::ostream_iterator<char> >;
}}

View file

@ -22,7 +22,7 @@
*****************************************************************************/
// mapnik
#include <mapnik/svg/svg_output_attributes.hpp>
#include <mapnik/svg/output/svg_output_attributes.hpp>
namespace mapnik { namespace svg {

View file

@ -76,7 +76,7 @@ void svg_renderer<T>::end_map_processing(Map const& map)
}
template <typename T>
void svg_renderer<T>::start_layer_processing(layer const& lay)
void svg_renderer<T>::start_layer_processing(layer const& lay, box2d<double> const& query_extent)
{
MAPNIK_LOG_DEBUG(svg_renderer) << "svg_renderer: Start layer processing=" << lay.name();
}

View file

@ -90,9 +90,13 @@ transform_type const& symbolizer_base::get_transform() const
std::string symbolizer_base::get_transform_string() const
{
if (affine_transform_)
{
return transform_processor_type::to_string(*affine_transform_);
}
else
{
return std::string();
}
}
void symbolizer_base::set_clip(bool clip)
@ -190,9 +194,13 @@ transform_type const& symbolizer_with_image::get_image_transform() const
std::string symbolizer_with_image::get_image_transform_string() const
{
if (image_transform_)
{
return transform_processor_type::to_string(*image_transform_);
}
else
{
return std::string();
}
}
} // end of namespace mapnik

View file

@ -472,6 +472,7 @@ compile_get_attr(std::string);
compile_get_attr(filter_mode_e);
compile_get_attr(point_placement_e);
compile_get_attr(marker_placement_e);
compile_get_attr(marker_multi_policy_e);
compile_get_attr(pattern_alignment_e);
compile_get_attr(line_rasterizer_e);
compile_get_attr(colorizer_mode);

View file

@ -31,6 +31,9 @@ int main( int, char*[] )
BOOST_TEST( x == 25 );
BOOST_TEST( y == 25 );
// TODO - centroid and interior should be equal but they appear not to be (check largest)
// MULTIPOLYGON(((-52 40,-60 32,-68 40,-60 48,-52 40)),((-60 50,-80 30,-100 49.9999999999999,-80.0000000000001 70,-60 50)),((-52 60,-60 52,-68 60,-60 68,-52 60)))
if (!::boost::detail::test_errors()) {
std::clog << "C++ label algorithms: \x1b[1;32m✓ \x1b[0m\n";
#if BOOST_VERSION >= 104600

View file

@ -21,7 +21,7 @@
#include <fstream>
#include <iterator>
namespace filesystem = boost::filesystem;
namespace fs = boost::filesystem;
/*
* This test case tests the generation of an SVG document
@ -57,10 +57,10 @@ BOOST_AUTO_TEST_CASE(file_output_test_case)
output_stream.close();
filesystem::path output_filename_path =
filesystem::system_complete(filesystem::path(".")) / filesystem::path(output_filename);
fs::path output_filename_path =
fs::system_complete(fs::path(".")) / fs::path(output_filename);
BOOST_CHECK_MESSAGE(filesystem::exists(output_filename_path), "File '"+output_filename_path.string()+"' was created.");
BOOST_CHECK_MESSAGE(fs::exists(output_filename_path), "File '"+output_filename_path.string()+"' was created.");
}
else
{

View file

@ -21,7 +21,7 @@
#include <fstream>
#include <iterator>
namespace filesystem = boost::filesystem;
namespace fs = boost::filesystem;
using namespace mapnik;
void prepare_map(Map& m)
@ -205,10 +205,10 @@ void render_to_file(Map const& m, const std::string output_filename)
output_stream.close();
filesystem::path output_filename_path =
filesystem::system_complete(filesystem::path(".")) / filesystem::path(output_filename);
fs::path output_filename_path =
fs::system_complete(fs::path(".")) / fs::path(output_filename);
BOOST_CHECK_MESSAGE(filesystem::exists(output_filename_path),
BOOST_CHECK_MESSAGE(fs::exists(output_filename_path),
"File '"+output_filename_path.string()+"' was created.");
}
else

View file

@ -13,7 +13,7 @@
<Layer name="lay" srs="+proj=longlat +ellps=airy +datum=OSGB36 +no_defs">
<StyleName>test</StyleName>
<Datasource base="shp">
<Datasource>
<Parameter name="type">shape</Parameter>
<Parameter name="file">../../data/shp/poly.shp</Parameter>
</Datasource>

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

View file

@ -0,0 +1,12 @@
{ "type": "FeatureCollection",
"features": [
{ "type": "Feature",
"geometry": {"type": "Point"},
"properties": {"feat_id": 0}
},
{ "type": "Feature",
"geometry": {"type": "Point", "coordinates":[0,0]},
"properties": {"feat_id": 1}
}
]
}

View file

@ -0,0 +1,63 @@
import sys
import os, mapnik
from timeit import Timer, time
from nose.tools import *
from utilities import execution_path
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_clearing_image_data():
im = mapnik.Image(256,256)
# make sure it equals itself
bytes = im.tostring()
eq_(im.tostring(),bytes)
# set background, then clear
im.background = mapnik.Color('green')
eq_(im.tostring()!=bytes,True)
# clear image, should now equal original
im.clear()
eq_(im.tostring(),bytes)
def make_map():
ds = mapnik.MemoryDatasource()
context = mapnik.Context()
context.push('Name')
pixel_key = 1
f = mapnik.Feature(context,pixel_key)
f['Name'] = str(pixel_key)
f.add_geometries_from_wkt('POLYGON ((0 0, 0 256, 256 256, 256 0, 0 0))')
ds.add_feature(f)
s = mapnik.Style()
r = mapnik.Rule()
symb = mapnik.PolygonSymbolizer()
r.symbols.append(symb)
s.rules.append(r)
lyr = mapnik.Layer('Places')
lyr.datasource = ds
lyr.styles.append('places_labels')
width,height = 256,256
m = mapnik.Map(width,height)
m.append_style('places_labels',s)
m.layers.append(lyr)
m.zoom_all()
return m
def test_clearing_grid_data():
g = mapnik.Grid(256,256)
utf = g.encode()
# make sure it equals itself
eq_(g.encode(),utf)
m = make_map()
mapnik.render_layer(m,g,layer=0,fields=['__id__','Name'])
eq_(g.encode()!=utf,True)
# clear grid, should now match original
g.clear()
eq_(g.encode(),utf)
if __name__ == "__main__":
setup()
[eval(run)() for run in dir() if 'test_' in run]

View file

@ -149,47 +149,48 @@ def test_pre_multiply_status_of_map2():
mapnik.render(m,im)
eq_(validate_pixels_are_not_premultiplied(im),True)
def test_style_level_comp_op():
m = mapnik.Map(256, 256)
mapnik.load_map(m, '../data/good_maps/style_level_comp_op.xml')
m.zoom_all()
successes = []
fails = []
for name in mapnik.CompositeOp.names:
# find_style returns a copy of the style object
style_markers = m.find_style("markers")
style_markers.comp_op = getattr(mapnik.CompositeOp, name)
# replace the original style with the modified one
replace_style(m, "markers", style_markers)
im = mapnik.Image(m.width, m.height)
mapnik.render(m, im)
actual = '/tmp/mapnik-style-comp-op-' + name + '.png'
expected = 'images/style-comp-op/' + name + '.png'
im.save(actual)
if not os.path.exists(expected):
print 'generating expected test image: %s' % expected
im.save(expected)
expected_im = mapnik.Image.open(expected)
# compare them
if im.tostring() == expected_im.tostring():
successes.append(name)
else:
fails.append('failed comparing actual (%s) and expected(%s)' % (actual,'tests/python_tests/'+ expected))
fail_im = side_by_side_image(expected_im, im)
fail_im.save('/tmp/mapnik-style-comp-op-' + name + '.fail.png')
eq_(len(fails), 0, '\n'+'\n'.join(fails))
if 'shape' in mapnik.DatasourceCache.plugin_names():
def test_style_level_comp_op():
m = mapnik.Map(256, 256)
mapnik.load_map(m, '../data/good_maps/style_level_comp_op.xml')
m.zoom_all()
successes = []
fails = []
for name in mapnik.CompositeOp.names:
# find_style returns a copy of the style object
style_markers = m.find_style("markers")
style_markers.comp_op = getattr(mapnik.CompositeOp, name)
# replace the original style with the modified one
replace_style(m, "markers", style_markers)
im = mapnik.Image(m.width, m.height)
mapnik.render(m, im)
actual = '/tmp/mapnik-style-comp-op-' + name + '.png'
expected = 'images/style-comp-op/' + name + '.png'
im.save(actual)
if not os.path.exists(expected):
print 'generating expected test image: %s' % expected
im.save(expected)
expected_im = mapnik.Image.open(expected)
# compare them
if im.tostring() == expected_im.tostring():
successes.append(name)
else:
fails.append('failed comparing actual (%s) and expected(%s)' % (actual,'tests/python_tests/'+ expected))
fail_im = side_by_side_image(expected_im, im)
fail_im.save('/tmp/mapnik-style-comp-op-' + name + '.fail.png')
eq_(len(fails), 0, '\n'+'\n'.join(fails))
def test_style_level_opacity():
m = mapnik.Map(512,512)
mapnik.load_map(m,'../data/good_maps/style_level_opacity_and_blur.xml')
m.zoom_all()
im = mapnik.Image(512,512)
mapnik.render(m,im)
actual = '/tmp/mapnik-style-level-opacity.png'
expected = 'images/support/mapnik-style-level-opacity.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_style_level_opacity():
m = mapnik.Map(512,512)
mapnik.load_map(m,'../data/good_maps/style_level_opacity_and_blur.xml')
m.zoom_all()
im = mapnik.Image(512,512)
mapnik.render(m,im)
actual = '/tmp/mapnik-style-level-opacity.png'
expected = 'images/support/mapnik-style-level-opacity.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_rounding_and_color_expectations():
m = mapnik.Map(1,1)

View file

@ -157,12 +157,17 @@ def test_regex_replace():
expr = mapnik.Expression("[name].replace('(\B)|( )','$1 ')")
eq_(expr.evaluate(f),'t e s t')
def test_unicode_regex_replace_to_str():
expr = mapnik.Expression("[name].replace('(\B)|( )','$1 ')")
eq_(str(expr),"[name].replace('(\B)|( )','$1 ')")
def test_unicode_regex_replace():
context = mapnik.Context()
context.push('name')
f = mapnik.Feature(context,0)
f["name"] = 'Québec'
expr = mapnik.Expression("[name].replace('(\B)|( )','$1 ')")
# will fail if -DBOOST_REGEX_HAS_ICU is not defined
eq_(expr.evaluate(f), u'Q u é b e c')
def test_float_precision():

View file

@ -18,14 +18,23 @@ combinations = ['png',
'png8:m=h',
'png8:m=o:t=0',
'png8:m=o:t=1',
'png8:m=o:t=2',
'png8:m=h:t=0',
'png8:m=h:t=1',
'png8:m=h:t=2',
'png:z=1',
'png8:z=1',
'png8:z=1:m=o',
'png8:z=1:m=h',
'png8:z=1:c=50',
'png8:z=1:c=1',
'png8:z=1:c=24',
'png8:z=1:c=64',
'png8:z=1:c=128',
'png8:z=1:c=200',
'png8:z=1:c=255',
'png8:z=9:c=64',
'png8:z=9:c=128',
'png8:z=9:c=200',
'png8:z=1:c=50:m=h',
'png8:z=1:c=1:m=o',
'png8:z=1:c=1:m=o:s=filtered',
@ -36,10 +45,18 @@ combinations = ['png',
'png:m=h;g=1.0',
]
tiles = [
'blank',
'solid',
'many_colors',
'aerial_24'
]
iterations = 10
def do_encoding():
image = None
iterations = 10
results = {}
sortable = {}
@ -53,47 +70,55 @@ def do_encoding():
min_ = min(set)*1000
avg = (sum(set)/len(set))*1000
name = func.__name__ + ' ' + format
results[name] = [avg,min_,elapsed*1000,name]
sortable[name] = [avg]
results[name] = [min_,avg,elapsed*1000,name,len(func())]
sortable[name] = [min_]
def blank():
eval('image.tostring("%s")' % c)
blank_im = mapnik.Image(512,512)
if 'blank' in tiles:
def blank():
return eval('image.tostring("%s")' % c)
blank_im = mapnik.Image(512,512)
for c in combinations:
t = Timer(blank)
run(blank,blank_im,c,t)
for c in combinations:
t = Timer(blank)
run(blank,blank_im,c,t)
if 'solid' in tiles:
def solid():
return eval('image.tostring("%s")' % c)
solid_im = mapnik.Image(512,512)
solid_im.background = mapnik.Color("#f2efe9")
for c in combinations:
t = Timer(solid)
run(solid,solid_im,c,t)
def solid():
eval('image.tostring("%s")' % c)
solid_im = mapnik.Image(512,512)
solid_im.background = mapnik.Color("#f2efe9")
if 'many_colors' in tiles:
def many_colors():
return eval('image.tostring("%s")' % c)
# lots of colors: http://tile.osm.org/13/4194/2747.png
many_colors_im = mapnik.Image.open('../data/images/13_4194_2747.png')
for c in combinations:
t = Timer(many_colors)
run(many_colors,many_colors_im,c,t)
for c in combinations:
t = Timer(solid)
run(solid,solid_im,c,t)
def many_colors():
eval('image.tostring("%s")' % c)
# lots of colors: http://tile.osm.org/13/4194/2747.png
many_colors_im = mapnik.Image.open('../data/images/13_4194_2747.png')
for c in combinations:
t = Timer(many_colors)
run(many_colors,many_colors_im,c,t)
if 'aerial_24' in tiles:
def aerial_24():
return eval('image.tostring("%s")' % c)
aerial_24_im = mapnik.Image.open('../data/images/12_654_1580.png')
for c in combinations:
t = Timer(aerial_24)
run(aerial_24,aerial_24_im,c,t)
for key, value in sorted(sortable.iteritems(), key=lambda (k,v): (v,k)):
s = results[key]
avg = str(s[0])[:6]
min_ = str(s[1])[:6]
min_ = str(s[0])[:6]
avg = str(s[1])[:6]
elapsed = str(s[2])[:6]
percent_reduction = s[4]
name = s[3]
print 'avg: %sms | min: %sms | total: %sms <-- %s' % (min_,avg,elapsed,name)
size = s[4]
print 'min: %sms | avg: %sms | total: %sms | len: %s <-- %s' % (min_,avg,elapsed,size,name)
if __name__ == "__main__":
setup()
do_encoding()
for t in dir():
if 'test_' in t:
eval(t)()
[eval(run)() for run in dir() if 'test_' in run]

Some files were not shown because too many files have changed in this diff Show more