diff --git a/Makefile b/Makefile index 0213d0d36..d88e216bb 100755 --- a/Makefile +++ b/Makefile @@ -1,13 +1,13 @@ all: mapnik install: - python scons/scons.py install + @python scons/scons.py --config=cache --implicit-deps-unchanged --max-drift=1 install mapnik: - python scons/scons.py + @python scons/scons.py --config=cache --implicit-deps-unchanged --max-drift=1 clean: - python scons/scons.py -c + python scons/scons.py -c --config=cache --implicit-deps-unchanged --max-drift=1 reset: if test -e ".sconf_temp/"; then rm -r ".sconf_temp/"; fi @@ -15,7 +15,7 @@ reset: if test -e "config.cache"; then rm "config.cache"; fi uninstall: - python scons/scons.py uninstall + python scons/scons.py --config=cache --implicit-deps-unchanged --max-drift=1 uninstall test: @echo "*** Running visual tests..." diff --git a/SConstruct b/SConstruct index 6c45529d7..2b0f716e7 100644 --- a/SConstruct +++ b/SConstruct @@ -33,6 +33,8 @@ except: HAS_DISTUTILS = False +py3 = None + # local file to hold custom user configuration variables # Todo check timestamp, reload if changed? SCONS_LOCAL_CONFIG = 'config.py' @@ -85,7 +87,7 @@ pretty_dep_names = { # Core plugin build configuration # opts.AddVariables still hardcoded however... PLUGINS = { # plugins with external dependencies - # configured by calling project, henche 'path':None + # configured by calling project, hence 'path':None 'postgis': {'default':True,'path':None,'inc':'libpq-fe.h','lib':'pq','lang':'C'}, 'gdal': {'default':True,'path':None,'inc':'gdal_priv.h','lib':'gdal','lang':'C++'}, 'ogr': {'default':True,'path':None,'inc':'ogrsf_frmts.h','lib':'gdal','lang':'C++'}, @@ -109,6 +111,8 @@ PLUGINS = { # plugins with external dependencies #### SCons build options and initial setup #### env = Environment(ENV=os.environ) +env.Decider('MD5-timestamp') +env.SourceCode(".", None) def color_print(color,text,newline=True): # 1 - red @@ -235,8 +239,6 @@ def sort_paths(items,priority): if platform.dist()[0] in ('Ubuntu','debian'): LIBDIR_SCHEMA='lib' -elif platform.uname()[4] == 'x86_64' and platform.system() == 'Linux': - LIBDIR_SCHEMA='lib64' elif platform.uname()[4] == 'ppc64': LIBDIR_SCHEMA='lib64' else: @@ -302,7 +304,7 @@ opts.AddVariables( ('BOOST_TOOLKIT','Specify boost toolkit, e.g., gcc41.','',False), ('BOOST_ABI', 'Specify boost ABI, e.g., d.','',False), ('BOOST_VERSION','Specify boost version, e.g., 1_35.','',False), - ('BOOST_PYTHON_LIB','Specify library name to specific Boost Python lib (e.g. "boost_python-py26")',''), + ('BOOST_PYTHON_LIB','Specify library name to specific Boost Python lib (e.g. "boost_python-py26")','boost_python'), # Variables for required dependencies ('FREETYPE_CONFIG', 'The path to the freetype-config executable.', 'freetype-config'), @@ -932,6 +934,8 @@ if not preconfigured: color_print(1,"SCons CONFIG not found: '%s'" % conf) # Recreate the base environment using modified `opts` env = Environment(ENV=os.environ,options=opts) + env.Decider('MD5-timestamp') + env.SourceCode(".", None) env['USE_CONFIG'] = True else: color_print(4,'SCons USE_CONFIG specified as false, will not inherit variables python config file...') @@ -1146,6 +1150,7 @@ if not preconfigured: # if the user is not setting custom boost configuration # enforce boost version greater than or equal to BOOST_MIN_VERSION if not conf.CheckBoost(BOOST_MIN_VERSION): + color_print(4,'Found boost lib version... %s' % env.get('BOOST_LIB_VERSION_FROM_HEADER') ) color_print(1,'Boost version %s or greater is required' % BOOST_MIN_VERSION) if not env['BOOST_VERSION']: env['MISSING_DEPS'].append('boost version >=%s' % BOOST_MIN_VERSION) @@ -1326,12 +1331,74 @@ if not preconfigured: color_print(4,'Not building with cairo support, pass CAIRO=True to enable') if 'python' in env['BINDINGS']: - # checklibwithheader does not work for boost_python since we can't feed it - # multiple header files, so we fall back on a simple check for boost_python headers + if not os.access(env['PYTHON'], os.X_OK): + color_print(1,"Cannot run python interpreter at '%s', make sure that you have the permissions to execute it." % env['PYTHON']) + Exit(1) + + py3 = 'True' in os.popen('''%s -c "import sys as s;s.stdout.write(str(s.version_info[0] == 3))"''' % env['PYTHON']).read().strip() + + if py3: + sys_prefix = '''%s -c "import sys; print(sys.prefix)"''' % env['PYTHON'] + else: + sys_prefix = '''%s -c "import sys; print sys.prefix"''' % env['PYTHON'] + env['PYTHON_SYS_PREFIX'] = call(sys_prefix) + + if HAS_DISTUTILS: + if py3: + sys_version = '''%s -c "from distutils.sysconfig import get_python_version; print(get_python_version())"''' % env['PYTHON'] + else: + sys_version = '''%s -c "from distutils.sysconfig import get_python_version; print get_python_version()"''' % env['PYTHON'] + env['PYTHON_VERSION'] = call(sys_version) + + if py3: + py_includes = '''%s -c "from distutils.sysconfig import get_python_inc; print(get_python_inc())"''' % env['PYTHON'] + else: + py_includes = '''%s -c "from distutils.sysconfig import get_python_inc; print get_python_inc()"''' % env['PYTHON'] + env['PYTHON_INCLUDES'] = call(py_includes) + + # Note: we use the plat_specific argument here to make sure to respect the arch-specific site-packages location + if py3: + site_packages = '''%s -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(plat_specific=True))"''' % env['PYTHON'] + else: + site_packages = '''%s -c "from distutils.sysconfig import get_python_lib; print get_python_lib(plat_specific=True)"''' % env['PYTHON'] + env['PYTHON_SITE_PACKAGES'] = call(site_packages) + else: + env['PYTHON_SYS_PREFIX'] = os.popen('''%s -c "import sys; print sys.prefix"''' % env['PYTHON']).read().strip() + env['PYTHON_VERSION'] = os.popen('''%s -c "import sys; print sys.version"''' % env['PYTHON']).read()[0:3] + env['PYTHON_INCLUDES'] = env['PYTHON_SYS_PREFIX'] + '/include/python' + env['PYTHON_VERSION'] + env['PYTHON_SITE_PACKAGES'] = env['DESTDIR'] + os.path.sep + env['PYTHON_SYS_PREFIX'] + os.path.sep + env['LIBDIR_SCHEMA'] + '/python' + env['PYTHON_VERSION'] + '/site-packages/' + + # if user-requested custom prefix fall back to manual concatenation for building subdirectories + if env['PYTHON_PREFIX']: + py_relative_install = env['LIBDIR_SCHEMA'] + '/python' + env['PYTHON_VERSION'] + '/site-packages/' + env['PYTHON_INSTALL_LOCATION'] = env['DESTDIR'] + os.path.sep + env['PYTHON_PREFIX'] + os.path.sep + py_relative_install + else: + env['PYTHON_INSTALL_LOCATION'] = env['DESTDIR'] + os.path.sep + env['PYTHON_SITE_PACKAGES'] + + if py3: + is_64_bit = '''%s -c "import sys; print(sys.maxsize == 9223372036854775807)"''' % env['PYTHON'] + else: + is_64_bit = '''%s -c "import sys; print sys.maxint == 9223372036854775807"''' % env['PYTHON'] + + if is_64_bit: + env['PYTHON_IS_64BIT'] = True + else: + env['PYTHON_IS_64BIT'] = False + + if py3 and env['BOOST_PYTHON_LIB'] == 'boost_python': + env['BOOST_PYTHON_LIB'] = 'boost_python3%s' % env['BOOST_APPEND'] + elif env['BOOST_PYTHON_LIB'] == 'boost_python': + env['BOOST_PYTHON_LIB'] = 'boost_python%s' % env['BOOST_APPEND'] + if not conf.CheckHeader(header='boost/python/detail/config.hpp',language='C++'): color_print(1,'Could not find required header files for boost python') env['MISSING_DEPS'].append('boost python') + if not conf.CheckLibWithHeader(libs=[env['BOOST_PYTHON_LIB'],'python%s' % env['PYTHON_VERSION']], header='boost/python/detail/config.hpp', language='C++'): + color_print(1, 'Could not find library "%s" for boost python bindings' % env['BOOST_PYTHON_LIB']) + # failing on launchpad, so let's make it a warning for now + #env['MISSING_DEPS'].append('boost python') + if env['CAIRO']: if conf.CheckPKGConfig('0.15.0') and conf.CheckPKG('pycairo'): env['HAS_PYCAIRO'] = True @@ -1459,68 +1526,13 @@ if not preconfigured: if env['DEBUG']: env.Append(CXXFLAGS = gcc_cxx_flags + '-O0 -fno-inline %s' % debug_flags) else: - env.Append(CXXFLAGS = gcc_cxx_flags + '-O%s -finline-functions -Wno-inline -Wno-parentheses -Wno-char-subscripts %s' % (env['OPTIMIZATION'],ndebug_flags)) + env.Append(CXXFLAGS = gcc_cxx_flags + '-O%s -fno-strict-aliasing -finline-functions -Wno-inline -Wno-parentheses -Wno-char-subscripts %s' % (env['OPTIMIZATION'],ndebug_flags)) if env['DEBUG_UNDEFINED']: env.Append(CXXFLAGS = '-fcatch-undefined-behavior -ftrapv -fwrapv') if 'python' in env['BINDINGS']: - if not os.access(env['PYTHON'], os.X_OK): - color_print(1,"Cannot run python interpreter at '%s', make sure that you have the permissions to execute it." % env['PYTHON']) - Exit(1) - - py3 = 'True' in os.popen('''%s -c "import sys as s;s.stdout.write(str(s.version_info[0] == 3))"''' % env['PYTHON']).read().strip() - - if py3: - sys_prefix = '''%s -c "import sys; print(sys.prefix)"''' % env['PYTHON'] - else: - sys_prefix = '''%s -c "import sys; print sys.prefix"''' % env['PYTHON'] - env['PYTHON_SYS_PREFIX'] = call(sys_prefix) - - if HAS_DISTUTILS: - if py3: - sys_version = '''%s -c "from distutils.sysconfig import get_python_version; print(get_python_version())"''' % env['PYTHON'] - else: - sys_version = '''%s -c "from distutils.sysconfig import get_python_version; print get_python_version()"''' % env['PYTHON'] - env['PYTHON_VERSION'] = call(sys_version) - - if py3: - py_includes = '''%s -c "from distutils.sysconfig import get_python_inc; print(get_python_inc())"''' % env['PYTHON'] - else: - py_includes = '''%s -c "from distutils.sysconfig import get_python_inc; print get_python_inc()"''' % env['PYTHON'] - env['PYTHON_INCLUDES'] = call(py_includes) - - # Note: we use the plat_specific argument here to make sure to respect the arch-specific site-packages location - if py3: - site_packages = '''%s -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(plat_specific=True))"''' % env['PYTHON'] - else: - site_packages = '''%s -c "from distutils.sysconfig import get_python_lib; print get_python_lib(plat_specific=True)"''' % env['PYTHON'] - env['PYTHON_SITE_PACKAGES'] = call(site_packages) - else: - env['PYTHON_SYS_PREFIX'] = os.popen('''%s -c "import sys; print sys.prefix"''' % env['PYTHON']).read().strip() - env['PYTHON_VERSION'] = os.popen('''%s -c "import sys; print sys.version"''' % env['PYTHON']).read()[0:3] - env['PYTHON_INCLUDES'] = env['PYTHON_SYS_PREFIX'] + '/include/python' + env['PYTHON_VERSION'] - env['PYTHON_SITE_PACKAGES'] = env['DESTDIR'] + os.path.sep + env['PYTHON_SYS_PREFIX'] + os.path.sep + env['LIBDIR_SCHEMA'] + '/python' + env['PYTHON_VERSION'] + '/site-packages/' - - # if user-requested custom prefix fall back to manual concatenation for building subdirectories - if env['PYTHON_PREFIX']: - py_relative_install = env['LIBDIR_SCHEMA'] + '/python' + env['PYTHON_VERSION'] + '/site-packages/' - env['PYTHON_INSTALL_LOCATION'] = env['DESTDIR'] + os.path.sep + env['PYTHON_PREFIX'] + os.path.sep + py_relative_install - else: - env['PYTHON_INSTALL_LOCATION'] = env['DESTDIR'] + os.path.sep + env['PYTHON_SITE_PACKAGES'] - - if py3: - is_64_bit = '''%s -c "import sys; print(sys.maxsize == 9223372036854775807)"''' % env['PYTHON'] - else: - is_64_bit = '''%s -c "import sys; print sys.maxint == 9223372036854775807"''' % env['PYTHON'] - - if is_64_bit: - env['PYTHON_IS_64BIT'] = True - else: - env['PYTHON_IS_64BIT'] = False - majver, minver = env['PYTHON_VERSION'].split('.') - # we don't want the includes it in the main environment... # as they are later set in the python build.py # ugly hack needed until we have env specific conf @@ -1535,11 +1547,6 @@ if not preconfigured: color_print(1,"Python version 2.2 or greater required") Exit(1) - if env['BOOST_PYTHON_LIB']: - if not conf.CheckLibWithHeader(libs=[env['BOOST_PYTHON_LIB']], header='boost/python/detail/config.hpp', language='C++'): - color_print(1, 'Could not find library %s for boost python' % env['BOOST_PYTHON_LIB']) - Exit(1) - color_print(4,'Bindings Python version... %s' % env['PYTHON_VERSION']) color_print(4,'Python %s prefix... %s' % (env['PYTHON_VERSION'], env['PYTHON_SYS_PREFIX'])) color_print(4,'Python bindings will install in... %s' % os.path.normpath(env['PYTHON_INSTALL_LOCATION'])) @@ -1656,7 +1663,6 @@ if not HELP_REQUESTED: # But let's also cache implicit deps... EnsureSConsVersion(0,98) SetOption('implicit_cache', 1) - env.Decider('MD5-timestamp') SetOption('max_drift', 1) else: diff --git a/bindings/python/build.py b/bindings/python/build.py index cee697357..646b2eeaf 100644 --- a/bindings/python/build.py +++ b/bindings/python/build.py @@ -43,15 +43,7 @@ prefix = env['PREFIX'] target_path = os.path.normpath(env['PYTHON_INSTALL_LOCATION'] + os.path.sep + 'mapnik') target_path_deprecated = os.path.normpath(env['PYTHON_INSTALL_LOCATION'] + os.path.sep + 'mapnik2') -libraries = ['mapnik'] - -if env['BOOST_PYTHON_LIB']: - libraries.append(env['BOOST_PYTHON_LIB']) -else: - if is_py3(): - libraries.append('boost_python3%s' % env['BOOST_APPEND']) - else: - libraries.append('boost_python%s' % env['BOOST_APPEND']) +libraries = ['mapnik',env['BOOST_PYTHON_LIB']] # TODO - do solaris/fedora need direct linking too? if env['PLATFORM'] == 'Darwin': diff --git a/bindings/python/mapnik_geometry.cpp b/bindings/python/mapnik_geometry.cpp index bc261e153..5731f3098 100644 --- a/bindings/python/mapnik_geometry.cpp +++ b/bindings/python/mapnik_geometry.cpp @@ -60,9 +60,9 @@ void add_wkt_impl(path_type& p, std::string const& wkt) if (!result) throw std::runtime_error("Failed to parse WKT"); } -void add_wkb_impl(path_type& p, std::string const& wkb) +bool add_wkb_impl(path_type& p, std::string const& wkb) { - mapnik::geometry_utils::from_wkb(p, wkb.c_str(), wkb.size()); + return mapnik::geometry_utils::from_wkb(p, wkb.c_str(), wkb.size()); } boost::shared_ptr from_wkt_impl(std::string const& wkt) diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index 0de5e35d1..e9934252a 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -118,6 +118,18 @@ bool painted(mapnik::image_32 const& im) return im.painted(); } +unsigned get_pixel(mapnik::image_32 const& im, int x, int y) +{ + if (x < static_cast(im.width()) && y < static_cast(im.height())) + { + mapnik::image_data_32 const & data = im.data(); + return data(x,y); + } + PyErr_SetString(PyExc_IndexError, "invalid x,y for image dimensions"); + boost::python::throw_error_already_set(); + return 0; +} + void set_pixel(mapnik::image_32 & im, unsigned x, unsigned y, mapnik::color const& c) { im.setPixel(x, y, c.rgba()); @@ -216,6 +228,7 @@ void export_image() .def("premultiply",&image_32::premultiply) .def("demultiply",&image_32::demultiply) .def("set_pixel",&set_pixel) + .def("get_pixel",&get_pixel) //TODO(haoyu) The method name 'tostring' might be confusing since they actually return bytes in Python 3 .def("tostring",&tostring1) diff --git a/bindings/python/mapnik_markers_symbolizer.cpp b/bindings/python/mapnik_markers_symbolizer.cpp index b95fd47c6..698569378 100644 --- a/bindings/python/mapnik_markers_symbolizer.cpp +++ b/bindings/python/mapnik_markers_symbolizer.cpp @@ -97,7 +97,7 @@ void export_markers_symbolizer() ; class_("MarkersSymbolizer", - init<>("Default Markers Symbolizer - blue arrow")) + init<>("Default Markers Symbolizer - circle")) .def (init("")) //.def_pickle(markers_symbolizer_pickle_suite()) .add_property("filename", @@ -123,21 +123,21 @@ void export_markers_symbolizer() &mapnik::get_svg_transform, &mapnik::set_svg_transform) .add_property("width", - &markers_symbolizer::get_width, + make_function(&markers_symbolizer::get_width, + return_value_policy()), &markers_symbolizer::set_width, "Set/get the marker width") .add_property("height", - &markers_symbolizer::get_height, + make_function(&markers_symbolizer::get_height, + return_value_policy()), &markers_symbolizer::set_height, "Set/get the marker height") .add_property("fill", - make_function(&markers_symbolizer::get_fill, - return_value_policy()), + &markers_symbolizer::get_fill, &markers_symbolizer::set_fill, "Set/get the marker fill color") .add_property("stroke", - make_function(&markers_symbolizer::get_stroke, - return_value_policy()), + &markers_symbolizer::get_stroke, &markers_symbolizer::set_stroke, "Set/get the marker stroke (outline)") .add_property("placement", diff --git a/bindings/python/mapnik_python.cpp b/bindings/python/mapnik_python.cpp index 6020d3b16..5ec4b93ac 100644 --- a/bindings/python/mapnik_python.cpp +++ b/bindings/python/mapnik_python.cpp @@ -37,6 +37,7 @@ void export_palette(); void export_image(); void export_image_view(); void export_gamma_method(); +void export_scaling_method(); void export_grid(); void export_grid_view(); void export_map(); @@ -88,6 +89,15 @@ void export_logger(); #include "mapnik_value_converter.hpp" #include "mapnik_threads.hpp" #include "python_optional.hpp" +#include +#include + + +void clear_cache() +{ + mapnik::marker_cache::instance()->clear(); + mapnik::mapped_memory_cache::instance()->clear(); +} #if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO) #include @@ -150,12 +160,13 @@ void render_layer2(const mapnik::Map& map, void render3(const mapnik::Map& map, PycairoSurface* surface, + double scale_factor = 1.0, unsigned offset_x = 0, unsigned offset_y = 0) { python_unblock_auto_block b; Cairo::RefPtr s(new Cairo::Surface(surface->surface)); - mapnik::cairo_renderer ren(map,s,offset_x, offset_y); + mapnik::cairo_renderer ren(map,s,scale_factor,offset_x,offset_y); ren.apply(); } @@ -169,12 +180,13 @@ void render4(const mapnik::Map& map, PycairoSurface* surface) void render5(const mapnik::Map& map, PycairoContext* context, + double scale_factor = 1.0, unsigned offset_x = 0, unsigned offset_y = 0) { python_unblock_auto_block b; Cairo::RefPtr c(new Cairo::Context(context->ctx)); - mapnik::cairo_renderer ren(map,c,offset_x, offset_y); + mapnik::cairo_renderer ren(map,c,scale_factor,offset_x, offset_y); ren.apply(); } @@ -207,7 +219,7 @@ void render_to_file1(const mapnik::Map& map, if (format == "pdf" || format == "svg" || format =="ps" || format == "ARGB32" || format == "RGB24") { #if defined(HAVE_CAIRO) - mapnik::save_to_cairo_file(map,filename,format); + mapnik::save_to_cairo_file(map,filename,format,1.0); #else throw mapnik::ImageWriterException("Cairo backend not available, cannot write to format: " + format); #endif @@ -226,7 +238,7 @@ void render_to_file2(const mapnik::Map& map,const std::string& filename) if (format == "pdf" || format == "svg" || format =="ps") { #if defined(HAVE_CAIRO) - mapnik::save_to_cairo_file(map,filename,format); + mapnik::save_to_cairo_file(map,filename,format,1.0); #else throw mapnik::ImageWriterException("Cairo backend not available, cannot write to format: " + format); #endif @@ -248,7 +260,7 @@ void render_to_file3(const mapnik::Map& map, if (format == "pdf" || format == "svg" || format =="ps" || format == "ARGB32" || format == "RGB24") { #if defined(HAVE_CAIRO) - mapnik::save_to_cairo_file(map,filename,format); + mapnik::save_to_cairo_file(map,filename,format,scale_factor); #else throw mapnik::ImageWriterException("Cairo backend not available, cannot write to format: " + format); #endif @@ -360,6 +372,7 @@ BOOST_PYTHON_MODULE(_mapnik) export_image(); export_image_view(); export_gamma_method(); + export_scaling_method(); export_grid(); export_grid_view(); export_expression(); @@ -389,6 +402,15 @@ BOOST_PYTHON_MODULE(_mapnik) export_label_collision_detector(); export_logger(); + def("clear_cache", &clear_cache, + "\n" + "Clear all global caches of markers and mapped memory regions.\n" + "\n" + "Usage:\n" + ">>> from mapnik import clear_cache\n" + ">>> clear_cache()\n" + ); + def("render_grid",&render_grid, ( arg("map"), arg("layer"), diff --git a/bindings/python/mapnik_query.cpp b/bindings/python/mapnik_query.cpp index f2b5c368f..cd49ef967 100644 --- a/bindings/python/mapnik_query.cpp +++ b/bindings/python/mapnik_query.cpp @@ -30,6 +30,8 @@ using mapnik::query; using mapnik::box2d; +namespace python = boost::python; + struct query_pickle_suite : boost::python::pickle_suite { static boost::python::tuple @@ -39,10 +41,26 @@ struct query_pickle_suite : boost::python::pickle_suite } }; +struct resolution_to_tuple +{ + static PyObject* convert(query::resolution_type const& x) + { + python::object tuple(python::make_tuple(x.get<0>(), x.get<1>())); + return python::incref(tuple.ptr()); + } + + static PyTypeObject const* get_pytype() + { + return &PyTuple_Type; + } +}; + void export_query() { using namespace boost::python; + to_python_converter (); + class_("Query", "a spatial query data object", init,query::resolution_type const&,double>() ) .def(init >()) diff --git a/bindings/python/mapnik_raster_symbolizer.cpp b/bindings/python/mapnik_raster_symbolizer.cpp index dacaea5de..3830dd9f1 100644 --- a/bindings/python/mapnik_raster_symbolizer.cpp +++ b/bindings/python/mapnik_raster_symbolizer.cpp @@ -25,6 +25,7 @@ // mapnik #include +#include using mapnik::raster_symbolizer; @@ -39,13 +40,13 @@ struct raster_symbolizer_pickle_suite : boost::python::pickle_suite */ static boost::python::tuple - getstate(const raster_symbolizer& r) + getstate(raster_symbolizer const& r) { - return boost::python::make_tuple(r.get_mode(),r.get_scaling(),r.get_opacity(),r.get_filter_factor(),r.get_mesh_size()); + return boost::python::make_tuple(r.get_mode(),r.get_scaling_method(),r.get_opacity(),r.get_filter_factor(),r.get_mesh_size()); } static void - setstate (raster_symbolizer& r, boost::python::tuple state) + setstate (raster_symbolizer & r, boost::python::tuple state) { using namespace boost::python; if (len(state) != 5) @@ -58,7 +59,7 @@ struct raster_symbolizer_pickle_suite : boost::python::pickle_suite } r.set_mode(extract(state[0])); - r.set_scaling(extract(state[1])); + r.set_scaling_method(extract(state[1])); r.set_opacity(extract(state[2])); r.set_filter_factor(extract(state[3])); r.set_mesh_size(extract(state[4])); @@ -91,17 +92,15 @@ void export_raster_symbolizer() ) .add_property("scaling", - make_function(&raster_symbolizer::get_scaling,return_value_policy()), - &raster_symbolizer::set_scaling, + &raster_symbolizer::get_scaling_method, + &raster_symbolizer::set_scaling_method, "Get/Set scaling algorithm.\n" - "Possible values are:\n" - "fast, bilinear, and bilinear8\n" "\n" "Usage:\n" "\n" ">>> from mapnik import RasterSymbolizer\n" ">>> r = RasterSymbolizer()\n" - ">>> r.scaling = 'bilinear8'\n" + ">>> r.scaling = 'mapnik.scaling_method.GAUSSIAN'\n" ) .add_property("opacity", diff --git a/bindings/python/mapnik_scaling_method.cpp b/bindings/python/mapnik_scaling_method.cpp new file mode 100644 index 000000000..a5ac926c6 --- /dev/null +++ b/bindings/python/mapnik_scaling_method.cpp @@ -0,0 +1,53 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 Artem Pavlenko, Jean-Francois Doyon + * + * 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 + * + *****************************************************************************/ +//$Id$ + + +#include +#include +#include "mapnik_enumeration.hpp" + +void export_scaling_method() +{ + using namespace boost::python; + + enum_("scaling_method") + .value("NEAR", mapnik::SCALING_NEAR) + .value("BILINEAR", mapnik::SCALING_BILINEAR) + .value("BICUBIC", mapnik::SCALING_BICUBIC) + .value("SPLINE16", mapnik::SCALING_SPLINE16) + .value("SPLINE36", mapnik::SCALING_SPLINE36) + .value("HANNING", mapnik::SCALING_HANNING) + .value("HAMMING", mapnik::SCALING_HAMMING) + .value("HERMITE", mapnik::SCALING_HERMITE) + .value("KAISER", mapnik::SCALING_KAISER) + .value("QUADRIC", mapnik::SCALING_QUADRIC) + .value("CATROM", mapnik::SCALING_CATROM) + .value("GAUSSIAN", mapnik::SCALING_GAUSSIAN) + .value("BESSEL", mapnik::SCALING_BESSEL) + .value("MITCHELL", mapnik::SCALING_MITCHELL) + .value("SINC", mapnik::SCALING_SINC) + .value("LANCZOS", mapnik::SCALING_LANCZOS) + .value("BLACKMAN", mapnik::SCALING_BLACKMAN) + .value("BILINEAR8", mapnik::SCALING_BILINEAR8) + ; +} diff --git a/bindings/python/python_grid_utils.cpp b/bindings/python/python_grid_utils.cpp new file mode 100644 index 000000000..87379c9fd --- /dev/null +++ b/bindings/python/python_grid_utils.cpp @@ -0,0 +1,505 @@ +/***************************************************************************** + * + * 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 + * + *****************************************************************************/ + +// boost +#include +#include +#include + +// mapnik +#include +#include +#include +#include +#include +#include +#include +#include +#include "mapnik_value_converter.hpp" +#include "python_grid_utils.hpp" + +namespace mapnik { + + +template +void grid2utf(T const& grid_type, + boost::python::list& l, + std::vector& key_order) +{ + typedef std::map< typename T::lookup_type, typename T::value_type> keys_type; + typedef typename keys_type::const_iterator keys_iterator; + + typename T::data_type const& data = grid_type.data(); + typename T::feature_key_type const& feature_keys = grid_type.get_feature_keys(); + typename T::feature_key_type::const_iterator feature_pos; + + keys_type keys; + // start counting at utf8 codepoint 32, aka space character + boost::uint16_t codepoint = 32; + + unsigned array_size = data.width(); + for (unsigned y = 0; y < data.height(); ++y) + { + boost::uint16_t idx = 0; + boost::scoped_array line(new Py_UNICODE[array_size]); + typename T::value_type const* row = data.getRow(y); + for (unsigned x = 0; x < data.width(); ++x) + { + typename T::value_type feature_id = row[x]; + feature_pos = feature_keys.find(feature_id); + if (feature_pos != feature_keys.end()) + { + mapnik::grid::lookup_type val = feature_pos->second; + keys_iterator key_pos = keys.find(val); + if (key_pos == keys.end()) + { + // Create a new entry for this key. Skip the codepoints that + // can't be encoded directly in JSON. + if (codepoint == 34) ++codepoint; // Skip " + else if (codepoint == 92) ++codepoint; // Skip backslash + if (feature_id == mapnik::grid::base_mask) + { + keys[""] = codepoint; + key_order.push_back(""); + } + else + { + keys[val] = codepoint; + key_order.push_back(val); + } + line[idx++] = static_cast(codepoint); + ++codepoint; + } + else + { + line[idx++] = static_cast(key_pos->second); + } + } + // else, shouldn't get here... + } + l.append(boost::python::object( + boost::python::handle<>( + PyUnicode_FromUnicode(line.get(), array_size)))); + } +} + + +template +void grid2utf(T const& grid_type, + boost::python::list& l, + std::vector& key_order, + unsigned int resolution) +{ + typedef std::map< typename T::lookup_type, typename T::value_type> keys_type; + typedef typename keys_type::const_iterator keys_iterator; + + typename T::feature_key_type const& feature_keys = grid_type.get_feature_keys(); + typename T::feature_key_type::const_iterator feature_pos; + + keys_type keys; + // start counting at utf8 codepoint 32, aka space character + boost::uint16_t codepoint = 32; + + // TODO - use double? + unsigned array_size = static_cast(grid_type.width()/resolution); + for (unsigned y = 0; y < grid_type.height(); y=y+resolution) + { + boost::uint16_t idx = 0; + boost::scoped_array line(new Py_UNICODE[array_size]); + mapnik::grid::value_type const* row = grid_type.getRow(y); + for (unsigned x = 0; x < grid_type.width(); x=x+resolution) + { + typename T::value_type feature_id = row[x]; + feature_pos = feature_keys.find(feature_id); + if (feature_pos != feature_keys.end()) + { + mapnik::grid::lookup_type val = feature_pos->second; + keys_iterator key_pos = keys.find(val); + if (key_pos == keys.end()) + { + // Create a new entry for this key. Skip the codepoints that + // can't be encoded directly in JSON. + if (codepoint == 34) ++codepoint; // Skip " + else if (codepoint == 92) ++codepoint; // Skip backslash + if (feature_id == mapnik::grid::base_mask) + { + keys[""] = codepoint; + key_order.push_back(""); + } + else + { + keys[val] = codepoint; + key_order.push_back(val); + } + line[idx++] = static_cast(codepoint); + ++codepoint; + } + else + { + line[idx++] = static_cast(key_pos->second); + } + } + // else, shouldn't get here... + } + l.append(boost::python::object( + boost::python::handle<>( + PyUnicode_FromUnicode(line.get(), array_size)))); + } +} + + +template +void grid2utf2(T const& grid_type, + boost::python::list& l, + std::vector& key_order, + unsigned int resolution) +{ + typedef std::map< typename T::lookup_type, typename T::value_type> keys_type; + typedef typename keys_type::const_iterator keys_iterator; + + typename T::data_type const& data = grid_type.data(); + typename T::feature_key_type const& feature_keys = grid_type.get_feature_keys(); + typename T::feature_key_type::const_iterator feature_pos; + + keys_type keys; + // start counting at utf8 codepoint 32, aka space character + uint16_t codepoint = 32; + + mapnik::grid::data_type target(data.width()/resolution,data.height()/resolution); + mapnik::scale_grid(target,grid_type.data(),0.0,0.0); + + unsigned array_size = target.width(); + for (unsigned y = 0; y < target.height(); ++y) + { + uint16_t idx = 0; + boost::scoped_array line(new Py_UNICODE[array_size]); + mapnik::grid::value_type * row = target.getRow(y); + unsigned x; + for (x = 0; x < target.width(); ++x) + { + feature_pos = feature_keys.find(row[x]); + if (feature_pos != feature_keys.end()) + { + mapnik::grid::lookup_type val = feature_pos->second; + keys_iterator key_pos = keys.find(val); + if (key_pos == keys.end()) + { + // Create a new entry for this key. Skip the codepoints that + // can't be encoded directly in JSON. + if (codepoint == 34) ++codepoint; // Skip " + else if (codepoint == 92) ++codepoint; // Skip backslash + keys[val] = codepoint; + key_order.push_back(val); + line[idx++] = static_cast(codepoint); + ++codepoint; + } + else + { + line[idx++] = static_cast(key_pos->second); + } + } + // else, shouldn't get here... + } + l.append(boost::python::object( + boost::python::handle<>( + PyUnicode_FromUnicode(line.get(), array_size)))); + } +} + + +template +void write_features(T const& grid_type, + boost::python::dict& feature_data, + std::vector const& key_order) +{ + std::string const& key = grid_type.get_key(); + std::set const& attributes = grid_type.property_names(); + typename T::feature_type const& g_features = grid_type.get_grid_features(); + typename T::feature_type::const_iterator feat_itr = g_features.begin(); + typename T::feature_type::const_iterator feat_end = g_features.end(); + bool include_key = (attributes.find(key) != attributes.end()); + for (; feat_itr != feat_end; ++feat_itr) + { + mapnik::feature_ptr feature = feat_itr->second; + boost::optional join_value; + if (key == grid_type.key_name()) + { + join_value = feat_itr->first; + } + else if (feature->has_key(key)) + { + join_value = feature->get(key).to_string(); + } + + if (join_value) + { + // only serialize features visible in the grid + if(std::find(key_order.begin(), key_order.end(), *join_value) != key_order.end()) { + boost::python::dict feat; + bool found = false; + if (key == grid_type.key_name()) + { + // drop key unless requested + if (include_key) { + found = true; + //TODO - add __id__ as data key? + //feat[key] = *join_value; + } + } + + feature_kv_iterator itr = feature->begin(); + feature_kv_iterator end = feature->end(); + for ( ;itr!=end; ++itr) + { + std::string const& key_name = boost::get<0>(*itr); + if (key_name == key) { + // drop key unless requested + if (include_key) { + found = true; + feat[key_name] = boost::get<1>(*itr); + } + } + else if ( (attributes.find(key_name) != attributes.end()) ) + { + found = true; + feat[key_name] = boost::get<1>(*itr); + } + } + + if (found) + { + feature_data[feat_itr->first] = feat; + } + } + } + else + { + MAPNIK_LOG_DEBUG(bindings) << "write_features: Should not get here: key " << key << " not found in grid feature properties"; + } + } +} + +template +void grid_encode_utf(T const& grid_type, + boost::python::dict & json, + bool add_features, + unsigned int resolution) +{ + // convert buffer to utf and gather key order + boost::python::list l; + std::vector key_order; + + if (resolution != 1) { + // resample on the fly - faster, less accurate + mapnik::grid2utf(grid_type,l,key_order,resolution); + + // resample first - slower, more accurate + //mapnik::grid2utf2(grid_type,l,key_order,resolution); + } + else + { + mapnik::grid2utf(grid_type,l,key_order); + } + + // convert key order to proper python list + boost::python::list keys_a; + BOOST_FOREACH ( typename T::lookup_type const& key_id, key_order ) + { + keys_a.append(key_id); + } + + // gather feature data + boost::python::dict feature_data; + if (add_features) { + mapnik::write_features(grid_type,feature_data,key_order); + } + + json["grid"] = l; + json["keys"] = keys_a; + json["data"] = feature_data; + +} + +template +boost::python::dict grid_encode( T const& grid, std::string format, bool add_features, unsigned int resolution) +{ + if (format == "utf") { + boost::python::dict json; + grid_encode_utf(grid,json,add_features,resolution); + return json; + } + else + { + std::stringstream s; + s << "'utf' is currently the only supported encoding format."; + throw mapnik::value_error(s.str()); + } +} + +template boost::python::dict grid_encode( mapnik::grid const& grid, std::string format, bool add_features, unsigned int resolution); +template boost::python::dict grid_encode( mapnik::grid_view const& grid, std::string format, bool add_features, unsigned int resolution); + +/* new approach: key comes from grid object + * grid size should be same as the map + * encoding, resizing handled as method on grid object + * whether features are dumped is determined by argument not 'fields' + */ +void render_layer_for_grid(const mapnik::Map& map, + mapnik::grid& grid, + unsigned layer_idx, // TODO - layer by name or index + boost::python::list const& fields) +{ + std::vector const& layers = map.layers(); + std::size_t layer_num = layers.size(); + if (layer_idx >= layer_num) { + std::ostringstream s; + s << "Zero-based layer index '" << layer_idx << "' not valid, only '" + << layer_num << "' layers are in map\n"; + throw std::runtime_error(s.str()); + } + + // convert python list to std::vector + boost::python::ssize_t num_fields = boost::python::len(fields); + for(boost::python::ssize_t i=0; i name(fields[i]); + if (name.check()) { + grid.add_property_name(name()); + } + else + { + std::stringstream s; + s << "list of field names must be strings"; + throw mapnik::value_error(s.str()); + } + } + + // copy property names + std::set attributes = grid.property_names(); + std::string const& key = grid.get_key(); + + // if key is special __id__ keyword + if (key == grid.key_name()) + { + // TODO - should feature.id() be a first class attribute? + + // if __id__ is requested to be dumped out + // remove it so that datasource queries will not break + if (attributes.find(key) != attributes.end()) + { + attributes.erase(key); + } + } + // if key is not the special __id__ keyword + else if (attributes.find(key) == attributes.end()) + { + // them make sure the datasource query includes this field + attributes.insert(key); + } + + mapnik::grid_renderer ren(map,grid,1.0,0,0); + mapnik::layer const& layer = layers[layer_idx]; + ren.apply(layer,attributes); +} + +/* old, original impl - to be removed after further testing + * grid object is created on the fly at potentially reduced size + */ +boost::python::dict render_grid(const mapnik::Map& map, + unsigned layer_idx, // layer + std::string const& key, // key_name + unsigned int step, // resolution + boost::python::list const& fields) +{ + + std::vector const& layers = map.layers(); + std::size_t layer_num = layers.size(); + if (layer_idx >= layer_num) { + std::ostringstream s; + s << "Zero-based layer index '" << layer_idx << "' not valid, only '" + << layer_num << "' layers are in map\n"; + throw std::runtime_error(s.str()); + } + + unsigned int grid_width = map.width()/step; + unsigned int grid_height = map.height()/step; + + // TODO - no need to pass step here + mapnik::grid grid(grid_width,grid_height,key,step); + + // convert python list to std::vector + boost::python::ssize_t num_fields = boost::python::len(fields); + for(boost::python::ssize_t i=0; i name(fields[i]); + if (name.check()) { + grid.add_property_name(name()); + } + else + { + std::stringstream s; + s << "list of field names must be strings"; + throw mapnik::value_error(s.str()); + } + } + + // copy property names + std::set attributes = grid.property_names(); + + // if key is special __id__ keyword + if (key == grid.key_name()) + { + // TODO - should feature.id() be a first class attribute? + + // if __id__ is requested to be dumped out + // remove it so that datasource queries will not break + if (attributes.find(key) != attributes.end()) + { + attributes.erase(key); + } + } + // if key is not the special __id__ keyword + else if (attributes.find(key) == attributes.end()) + { + // them make sure the datasource query includes this field + attributes.insert(key); + } + + try + { + mapnik::grid_renderer ren(map,grid,1.0,0,0); + mapnik::layer const& layer = layers[layer_idx]; + ren.apply(layer,attributes); + } + catch (...) + { + throw; + } + + bool add_features = false; + if (num_fields > 0) + add_features = true; + // build dictionary and return to python + boost::python::dict json; + grid_encode_utf(grid,json,add_features,1); + return json; +} + +} diff --git a/bindings/python/python_grid_utils.hpp b/bindings/python/python_grid_utils.hpp index 62d83a9c0..30ed4ff43 100644 --- a/bindings/python/python_grid_utils.hpp +++ b/bindings/python/python_grid_utils.hpp @@ -24,475 +24,66 @@ // boost #include -#include -#include // mapnik -#include -#include +#include #include -#include -#include -#include -#include -#include -#include "mapnik_value_converter.hpp" - namespace mapnik { template -static void grid2utf(T const& grid_type, +void grid2utf(T const& grid_type, boost::python::list& l, - std::vector& key_order) -{ - typename T::data_type const& data = grid_type.data(); - typename T::feature_key_type const& feature_keys = grid_type.get_feature_keys(); - typename T::key_type keys; - typename T::key_type::const_iterator key_pos; - typename T::feature_key_type::const_iterator feature_pos; - // start counting at utf8 codepoint 32, aka space character - boost::uint16_t codepoint = 32; - - unsigned array_size = data.width(); - for (unsigned y = 0; y < data.height(); ++y) - { - boost::uint16_t idx = 0; - boost::scoped_array line(new Py_UNICODE[array_size]); - typename T::value_type const* row = data.getRow(y); - for (unsigned x = 0; x < data.width(); ++x) - { - typename T::value_type feature_id = row[x]; - feature_pos = feature_keys.find(feature_id); - if (feature_pos != feature_keys.end()) - { - mapnik::grid::lookup_type val = feature_pos->second; - key_pos = keys.find(val); - if (key_pos == keys.end()) - { - // Create a new entry for this key. Skip the codepoints that - // can't be encoded directly in JSON. - if (codepoint == 34) ++codepoint; // Skip " - else if (codepoint == 92) ++codepoint; // Skip backslash - if (feature_id == mapnik::grid::base_mask) - { - keys[""] = codepoint; - key_order.push_back(""); - } - else - { - keys[val] = codepoint; - key_order.push_back(val); - } - line[idx++] = static_cast(codepoint); - ++codepoint; - } - else - { - line[idx++] = static_cast(key_pos->second); - } - } - // else, shouldn't get here... - } - l.append(boost::python::object( - boost::python::handle<>( - PyUnicode_FromUnicode(line.get(), array_size)))); - } -} + std::vector& key_order); template -static void grid2utf(T const& grid_type, +void grid2utf(T const& grid_type, boost::python::list& l, std::vector& key_order, - unsigned int resolution) -{ - //typename T::data_type const& data = grid_type.data(); - typename T::feature_key_type const& feature_keys = grid_type.get_feature_keys(); - typename T::key_type keys; - typename T::key_type::const_iterator key_pos; - typename T::feature_key_type::const_iterator feature_pos; - // start counting at utf8 codepoint 32, aka space character - boost::uint16_t codepoint = 32; - - // TODO - use double? - unsigned array_size = static_cast(grid_type.width()/resolution); - for (unsigned y = 0; y < grid_type.height(); y=y+resolution) - { - boost::uint16_t idx = 0; - boost::scoped_array line(new Py_UNICODE[array_size]); - mapnik::grid::value_type const* row = grid_type.getRow(y); - for (unsigned x = 0; x < grid_type.width(); x=x+resolution) - { - typename T::value_type feature_id = row[x]; - feature_pos = feature_keys.find(feature_id); - if (feature_pos != feature_keys.end()) - { - mapnik::grid::lookup_type val = feature_pos->second; - key_pos = keys.find(val); - if (key_pos == keys.end()) - { - // Create a new entry for this key. Skip the codepoints that - // can't be encoded directly in JSON. - if (codepoint == 34) ++codepoint; // Skip " - else if (codepoint == 92) ++codepoint; // Skip backslash - if (feature_id == mapnik::grid::base_mask) - { - keys[""] = codepoint; - key_order.push_back(""); - } - else - { - keys[val] = codepoint; - key_order.push_back(val); - } - line[idx++] = static_cast(codepoint); - ++codepoint; - } - else - { - line[idx++] = static_cast(key_pos->second); - } - } - // else, shouldn't get here... - } - l.append(boost::python::object( - boost::python::handle<>( - PyUnicode_FromUnicode(line.get(), array_size)))); - } -} + unsigned int resolution); template -static void grid2utf2(T const& grid_type, +void grid2utf2(T const& grid_type, boost::python::list& l, std::vector& key_order, - unsigned int resolution) -{ - typename T::data_type const& data = grid_type.data(); - typename T::feature_key_type const& feature_keys = grid_type.get_feature_keys(); - typename T::key_type keys; - typename T::key_type::const_iterator key_pos; - typename T::feature_key_type::const_iterator feature_pos; - // start counting at utf8 codepoint 32, aka space character - uint16_t codepoint = 32; - - mapnik::grid::data_type target(data.width()/resolution,data.height()/resolution); - mapnik::scale_grid(target,grid_type.data(),0.0,0.0); - - unsigned array_size = target.width(); - for (unsigned y = 0; y < target.height(); ++y) - { - uint16_t idx = 0; - boost::scoped_array line(new Py_UNICODE[array_size]); - mapnik::grid::value_type * row = target.getRow(y); - unsigned x; - for (x = 0; x < target.width(); ++x) - { - feature_pos = feature_keys.find(row[x]); - if (feature_pos != feature_keys.end()) - { - mapnik::grid::lookup_type val = feature_pos->second; - key_pos = keys.find(val); - if (key_pos == keys.end()) - { - // Create a new entry for this key. Skip the codepoints that - // can't be encoded directly in JSON. - if (codepoint == 34) ++codepoint; // Skip " - else if (codepoint == 92) ++codepoint; // Skip backslash - keys[val] = codepoint; - key_order.push_back(val); - line[idx++] = static_cast(codepoint); - ++codepoint; - } - else - { - line[idx++] = static_cast(key_pos->second); - } - } - // else, shouldn't get here... - } - l.append(boost::python::object( - boost::python::handle<>( - PyUnicode_FromUnicode(line.get(), array_size)))); - } -} + unsigned int resolution); template -static void write_features(T const& grid_type, +void write_features(T const& grid_type, boost::python::dict& feature_data, - std::vector const& key_order) -{ - std::string const& key = grid_type.get_key(); - std::set const& attributes = grid_type.property_names(); - typename T::feature_type const& g_features = grid_type.get_grid_features(); - typename T::feature_type::const_iterator feat_itr = g_features.begin(); - typename T::feature_type::const_iterator feat_end = g_features.end(); - bool include_key = (attributes.find(key) != attributes.end()); - for (; feat_itr != feat_end; ++feat_itr) - { - mapnik::feature_ptr feature = feat_itr->second; - boost::optional join_value; - if (key == grid_type.key_name()) - { - join_value = feat_itr->first; - } - else if (feature->has_key(key)) - { - join_value = feature->get(key).to_string(); - } - - if (join_value) - { - // only serialize features visible in the grid - if(std::find(key_order.begin(), key_order.end(), *join_value) != key_order.end()) { - boost::python::dict feat; - bool found = false; - if (key == grid_type.key_name()) - { - // drop key unless requested - if (include_key) { - found = true; - //TODO - add __id__ as data key? - //feat[key] = *join_value; - } - } - - feature_kv_iterator itr = feature->begin(); - feature_kv_iterator end = feature->end(); - for ( ;itr!=end; ++itr) - { - std::string const& key_name = boost::get<0>(*itr); - if (key_name == key) { - // drop key unless requested - if (include_key) { - found = true; - feat[key_name] = boost::get<1>(*itr); - } - } - else if ( (attributes.find(key_name) != attributes.end()) ) - { - found = true; - feat[key_name] = boost::get<1>(*itr); - } - } - - if (found) - { - feature_data[feat_itr->first] = feat; - } - } - } - else - { - MAPNIK_LOG_DEBUG(bindings) << "write_features: Should not get here: key " << key << " not found in grid feature properties"; - } - } -} + std::vector const& key_order); template -static void grid_encode_utf(T const& grid_type, +void grid_encode_utf(T const& grid_type, boost::python::dict & json, bool add_features, - unsigned int resolution) -{ - // convert buffer to utf and gather key order - boost::python::list l; - std::vector key_order; - - if (resolution != 1) { - // resample on the fly - faster, less accurate - mapnik::grid2utf(grid_type,l,key_order,resolution); - - // resample first - slower, more accurate - //mapnik::grid2utf2(grid_type,l,key_order,resolution); - } - else - { - mapnik::grid2utf(grid_type,l,key_order); - } - - // convert key order to proper python list - boost::python::list keys_a; - BOOST_FOREACH ( typename T::lookup_type const& key_id, key_order ) - { - keys_a.append(key_id); - } - - // gather feature data - boost::python::dict feature_data; - if (add_features) { - mapnik::write_features(grid_type,feature_data,key_order); - } - - json["grid"] = l; - json["keys"] = keys_a; - json["data"] = feature_data; - -} + unsigned int resolution); template -static boost::python::dict grid_encode( T const& grid, std::string format, bool add_features, unsigned int resolution) -{ - if (format == "utf") { - boost::python::dict json; - grid_encode_utf(grid,json,add_features,resolution); - return json; - } - else - { - std::stringstream s; - s << "'utf' is currently the only supported encoding format."; - throw mapnik::value_error(s.str()); - } -} +boost::python::dict grid_encode( T const& grid, std::string format, bool add_features, unsigned int resolution); /* new approach: key comes from grid object * grid size should be same as the map * encoding, resizing handled as method on grid object * whether features are dumped is determined by argument not 'fields' */ -static void render_layer_for_grid(const mapnik::Map& map, +void render_layer_for_grid(const mapnik::Map& map, mapnik::grid& grid, unsigned layer_idx, // TODO - layer by name or index - boost::python::list const& fields) -{ - std::vector const& layers = map.layers(); - std::size_t layer_num = layers.size(); - if (layer_idx >= layer_num) { - std::ostringstream s; - s << "Zero-based layer index '" << layer_idx << "' not valid, only '" - << layer_num << "' layers are in map\n"; - throw std::runtime_error(s.str()); - } - - // convert python list to std::vector - boost::python::ssize_t num_fields = boost::python::len(fields); - for(boost::python::ssize_t i=0; i name(fields[i]); - if (name.check()) { - grid.add_property_name(name()); - } - else - { - std::stringstream s; - s << "list of field names must be strings"; - throw mapnik::value_error(s.str()); - } - } - - // copy property names - std::set attributes = grid.property_names(); - std::string const& key = grid.get_key(); - - // if key is special __id__ keyword - if (key == grid.key_name()) - { - // TODO - should feature.id() be a first class attribute? - - // if __id__ is requested to be dumped out - // remove it so that datasource queries will not break - if (attributes.find(key) != attributes.end()) - { - attributes.erase(key); - } - } - // if key is not the special __id__ keyword - else if (attributes.find(key) == attributes.end()) - { - // them make sure the datasource query includes this field - attributes.insert(key); - } - - mapnik::grid_renderer ren(map,grid,1.0,0,0); - mapnik::layer const& layer = layers[layer_idx]; - ren.apply(layer,attributes); -} + boost::python::list const& fields); /* old, original impl - to be removed after further testing * grid object is created on the fly at potentially reduced size */ -static boost::python::dict render_grid(const mapnik::Map& map, +boost::python::dict render_grid(const mapnik::Map& map, unsigned layer_idx, // layer std::string const& key, // key_name unsigned int step, // resolution - boost::python::list const& fields) -{ - - std::vector const& layers = map.layers(); - std::size_t layer_num = layers.size(); - if (layer_idx >= layer_num) { - std::ostringstream s; - s << "Zero-based layer index '" << layer_idx << "' not valid, only '" - << layer_num << "' layers are in map\n"; - throw std::runtime_error(s.str()); - } - - unsigned int grid_width = map.width()/step; - unsigned int grid_height = map.height()/step; - - // TODO - no need to pass step here - mapnik::grid grid(grid_width,grid_height,key,step); - - // convert python list to std::vector - boost::python::ssize_t num_fields = boost::python::len(fields); - for(boost::python::ssize_t i=0; i name(fields[i]); - if (name.check()) { - grid.add_property_name(name()); - } - else - { - std::stringstream s; - s << "list of field names must be strings"; - throw mapnik::value_error(s.str()); - } - } - - // copy property names - std::set attributes = grid.property_names(); - - // if key is special __id__ keyword - if (key == grid.key_name()) - { - // TODO - should feature.id() be a first class attribute? - - // if __id__ is requested to be dumped out - // remove it so that datasource queries will not break - if (attributes.find(key) != attributes.end()) - { - attributes.erase(key); - } - } - // if key is not the special __id__ keyword - else if (attributes.find(key) == attributes.end()) - { - // them make sure the datasource query includes this field - attributes.insert(key); - } - - try - { - mapnik::grid_renderer ren(map,grid,1.0,0,0); - mapnik::layer const& layer = layers[layer_idx]; - ren.apply(layer,attributes); - } - catch (...) - { - throw; - } - - bool add_features = false; - if (num_fields > 0) - add_features = true; - // build dictionary and return to python - boost::python::dict json; - grid_encode_utf(grid,json,add_features,1); - return json; -} - + boost::python::list const& fields); } #endif // MAPNIK_PYTHON_BINDING_GRID_UTILS_INCLUDED diff --git a/configure b/configure index ebe8aaf7b..99d1fc22a 100755 --- a/configure +++ b/configure @@ -1,3 +1,3 @@ #!/bin/sh -python scons/scons.py configure "$@" +python scons/scons.py --implicit-cache configure "$@" diff --git a/demo/viewer/mainwindow.cpp b/demo/viewer/mainwindow.cpp index 6ceaf0656..436a31ddc 100644 --- a/demo/viewer/mainwindow.cpp +++ b/demo/viewer/mainwindow.cpp @@ -32,6 +32,7 @@ #include #include #include +#include // mapnik @@ -97,12 +98,15 @@ MainWindow::MainWindow() //connect mapview to layerlist connect(mapWidget_, SIGNAL(mapViewChanged()),layerTab_, SLOT(update())); // slider - connect(slider_,SIGNAL(valueChanged(int)),mapWidget_,SLOT(zoomToLevel(int))); + connect(slider_,SIGNAL(valueChanged(int)),mapWidget_,SLOT(zoomToLevel(int))); // renderer selector - connect(renderer_selector_,SIGNAL(currentIndexChanged(QString const&)), + connect(renderer_selector_,SIGNAL(currentIndexChanged(QString const&)), mapWidget_, SLOT(updateRenderer(QString const&))); - - // + + // scale factor + connect(scale_factor_,SIGNAL(valueChanged(double)), + mapWidget_, SLOT(updateScaleFactor(double))); + // connect(layerTab_,SIGNAL(update_mapwidget()),mapWidget_,SLOT(updateMap())); connect(layerTab_,SIGNAL(layerSelected(int)), mapWidget_,SLOT(layerSelected(int))); @@ -373,16 +377,23 @@ void MainWindow::createToolBars() fileToolBar->addAction(infoAct); fileToolBar->addAction(reloadAct); fileToolBar->addAction(printAct); - + renderer_selector_ = new QComboBox(fileToolBar); renderer_selector_->setFocusPolicy(Qt::NoFocus); renderer_selector_->addItem("AGG"); #ifdef HAVE_CAIRO renderer_selector_->addItem("Cairo"); #endif - renderer_selector_->addItem("Grid"); + renderer_selector_->addItem("Grid"); fileToolBar->addWidget(renderer_selector_); + scale_factor_ = new QDoubleSpinBox(fileToolBar); + scale_factor_->setMinimum(0.1); + scale_factor_->setMaximum(5.0); + scale_factor_->setSingleStep(0.1); + scale_factor_->setValue(1.0); + + fileToolBar->addWidget(scale_factor_); slider_ = new QSlider(Qt::Horizontal,fileToolBar); slider_->setRange(1,18); slider_->setTickPosition(QSlider::TicksBelow); diff --git a/demo/viewer/mainwindow.hpp b/demo/viewer/mainwindow.hpp index e96fb78f2..25271693b 100644 --- a/demo/viewer/mainwindow.hpp +++ b/demo/viewer/mainwindow.hpp @@ -28,6 +28,7 @@ #include #include #include +#include #include "mapwidget.hpp" @@ -37,6 +38,7 @@ class LayerTab; class StyleTab; class QSlider; class QComboBox; +class QDoubleSpinBox; class MainWindow : public QMainWindow { @@ -108,6 +110,7 @@ private: QStatusBar *status; QSlider * slider_; QComboBox * renderer_selector_; + QDoubleSpinBox * scale_factor_; mapnik::box2d default_extent_; }; diff --git a/demo/viewer/mapwidget.cpp b/demo/viewer/mapwidget.cpp index 220eb5586..eb57adce9 100644 --- a/demo/viewer/mapwidget.cpp +++ b/demo/viewer/mapwidget.cpp @@ -184,29 +184,29 @@ void MapWidget::mousePressEvent(QMouseEvent* e) feature_ptr feat = fs->next(); if (feat) { - + feature_kv_iterator itr(*feat,true); feature_kv_iterator end(*feat); - + for ( ;itr!=end; ++itr) { info.push_back(QPair(QString(boost::get<0>(*itr).c_str()), boost::get<1>(*itr).to_string().c_str())); } - + typedef mapnik::coord_transform path_type; for (unsigned i=0; inum_geometries();++i) { mapnik::geometry_type & geom = feat->get_geometry(i); path_type path(t,geom,prj_trans); - if (geom.num_points() > 0) + if (geom.size() > 0) { QPainterPath qpath; double x,y; path.vertex(&x,&y); qpath.moveTo(x,y); - for (unsigned j = 1; j < geom.num_points(); ++j) + for (unsigned j = 1; j < geom.size(); ++j) { path.vertex(&x,&y); qpath.lineTo(x,y); @@ -498,12 +498,12 @@ void render_agg(mapnik::Map const& map, double scaling_factor, QPixmap & pix) { unsigned width=map.width(); unsigned height=map.height(); - + image_32 buf(width,height); mapnik::agg_renderer ren(map,buf,scaling_factor); - + try - { + { ren.apply(); QImage image((uchar*)buf.raw_data(),width,height,QImage::Format_ARGB32); pix = QPixmap::fromImage(image.rgbSwapped()); @@ -527,23 +527,23 @@ void render_grid(mapnik::Map const& map, double scaling_factor, QPixmap & pix) { unsigned width=map.width(); unsigned height=map.height(); - + mapnik::grid buf(width,height,"F_CODE", 1); mapnik::grid_renderer ren(map,buf,scaling_factor); - + try - { + { ren.apply(); int * imdata = static_cast(buf.raw_data()); - + QImage image(width,height,QImage::Format_RGB32); for (unsigned i = 0 ; i < height ; ++i) - { + { for (unsigned j = 0 ; j < width ; ++j) { image.setPixel(j,i,qRgb((uint8_t)(imdata[i*width+j]>>8), (uint8_t)(imdata[i*width+j+1]>>8), - (uint8_t)(imdata[i*width+j+2]>>8))); + (uint8_t)(imdata[i*width+j+2]>>8))); } } pix = QPixmap::fromImage(image); @@ -567,12 +567,12 @@ void render_cairo(mapnik::Map const& map, double scaling_factor, QPixmap & pix) { #ifdef HAVE_CAIRO - Cairo::RefPtr image_surface = + Cairo::RefPtr image_surface = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, map.width(),map.height()); - - mapnik::cairo_renderer png_render(map, image_surface); + + mapnik::cairo_renderer png_render(map, image_surface, scaling_factor); png_render.apply(); - + image_32 buf(image_surface); QImage image((uchar*)buf.raw_data(),buf.width(),buf.height(),QImage::Format_ARGB32); pix = QPixmap::fromImage(image.rgbSwapped()); @@ -588,6 +588,12 @@ void MapWidget::updateRenderer(QString const& txt) updateMap(); } +void MapWidget::updateScaleFactor(double scale_factor) +{ + set_scaling_factor(scale_factor); + updateMap(); +} + void MapWidget::updateMap() { if (map_) @@ -611,7 +617,7 @@ void MapWidget::updateMap() try { - projection prj(map_->srs()); // map projection + projection prj(map_->srs()); // map projection box2d ext = map_->get_current_extent(); double x0 = ext.minx(); double y0 = ext.miny(); @@ -623,7 +629,7 @@ void MapWidget::updateMap() update(); // emit signal to interested widgets emit mapViewChanged(); - } + } catch (...) { std::cerr << "Unknown exception caught!\n"; diff --git a/demo/viewer/mapwidget.hpp b/demo/viewer/mapwidget.hpp index 671cc5ab4..0aab462b8 100644 --- a/demo/viewer/mapwidget.hpp +++ b/demo/viewer/mapwidget.hpp @@ -53,8 +53,8 @@ public: AGG, Cairo, Grid - }; - + }; + private: boost::shared_ptr map_; int selected_; @@ -91,6 +91,7 @@ public slots: void updateMap(); void layerSelected(int); void updateRenderer(QString const& txt); + void updateScaleFactor(double scale_factor); signals: void mapViewChanged(); protected: diff --git a/demo/viewer/viewer.pro b/demo/viewer/viewer.pro index 538419e49..048cfad9c 100644 --- a/demo/viewer/viewer.pro +++ b/demo/viewer/viewer.pro @@ -1,18 +1,11 @@ ###################################################################### # Mapnik viewer - Copyright (C) 2007 Artem Pavlenko ###################################################################### -CC = g++ TEMPLATE = app - -INCLUDEPATH += /usr/local/include/ -INCLUDEPATH += /usr/boost/include/ -INCLUDEPATH += /usr/X11/include/ -INCLUDEPATH += /usr/X11/include/freetype2 -INCLUDEPATH += . - -QMAKE_CXXFLAGS +=' -DDARWIN -Wno-missing-field-initializers -ansi' -unix:LIBS = -L/usr/local/lib -L/usr/X11/lib -lmapnik -lfreetype -unix:LIBS += -lboost_system -licuuc -lboost_filesystem -lboost_regex +QMAKE_CXX = clang++ +QMAKE_CXXFLAGS += $$system(mapnik-config --cflags) +QMAKE_LFLAGS += $$system(mapnik-config --libs) +QMAKE_LFLAGS += $$system(mapnik-config --ldflags --dep-libs) # Input diff --git a/include/mapnik/attribute.hpp b/include/mapnik/attribute.hpp index b38292c48..a9ae97169 100644 --- a/include/mapnik/attribute.hpp +++ b/include/mapnik/attribute.hpp @@ -25,6 +25,9 @@ // mapnik #include +#include +// boost +#include // stl #include @@ -44,6 +47,24 @@ struct attribute std::string const& name() const { return name_;} }; + +struct geometry_type_attribute +{ + template + V value(F const& f) const + { + int result = 0; + + geometry_container::const_iterator itr = f.paths().begin(); + geometry_container::const_iterator end = f.paths().end(); + for ( ; itr != end; ++itr) + { + result = itr->type(); + } + return result; + } +}; + } #endif // MAPNIK_ATTRIBUTE_HPP diff --git a/include/mapnik/attribute_collector.hpp b/include/mapnik/attribute_collector.hpp index 4cba3a09b..f814d1ac5 100644 --- a/include/mapnik/attribute_collector.hpp +++ b/include/mapnik/attribute_collector.hpp @@ -47,6 +47,11 @@ struct expression_attributes : boost::static_visitor boost::ignore_unused_variable_warning(x); } + void operator() (geometry_type_attribute const& type) const + { + // do nothing + } + void operator() (attribute const& attr) const { names_.insert(attr.name()); diff --git a/include/mapnik/cairo_renderer.hpp b/include/mapnik/cairo_renderer.hpp index 3fe8f5344..73d5e4f47 100644 --- a/include/mapnik/cairo_renderer.hpp +++ b/include/mapnik/cairo_renderer.hpp @@ -72,7 +72,7 @@ private: class MAPNIK_DECL cairo_renderer_base : private boost::noncopyable { protected: - cairo_renderer_base(Map const& m, Cairo::RefPtr const& context, unsigned offset_x=0, unsigned offset_y=0); + cairo_renderer_base(Map const& m, Cairo::RefPtr const& context, double scale_factor=1.0, unsigned offset_x=0, unsigned offset_y=0); public: ~cairo_renderer_base(); void start_map_processing(Map const& map); @@ -127,6 +127,9 @@ protected: Map const& m_; Cairo::RefPtr context_; + unsigned width_; + unsigned height_; + double scale_factor_; CoordTransform t_; boost::shared_ptr font_engine_; face_manager font_manager_; @@ -141,7 +144,7 @@ class MAPNIK_DECL cairo_renderer : public feature_style_processor const& surface, unsigned offset_x=0, unsigned offset_y=0); + cairo_renderer(Map const& m, Cairo::RefPtr const& surface, double scale_factor=1.0, unsigned offset_x=0, unsigned offset_y=0); void end_map_processing(Map const& map); }; } diff --git a/include/mapnik/datasource.hpp b/include/mapnik/datasource.hpp index 6ae828a94..127265377 100644 --- a/include/mapnik/datasource.hpp +++ b/include/mapnik/datasource.hpp @@ -126,7 +126,7 @@ protected: mutable bool is_bound_; }; -typedef std::string datasource_name(); +typedef const char * datasource_name(); typedef datasource* create_ds(const parameters& params, bool bind); typedef void destroy_ds(datasource *ds); @@ -142,7 +142,7 @@ public: typedef boost::shared_ptr datasource_ptr; #define DATASOURCE_PLUGIN(classname) \ - extern "C" MAPNIK_EXP std::string datasource_name() \ + extern "C" MAPNIK_EXP const char * datasource_name() \ { \ return classname::name(); \ } \ diff --git a/include/mapnik/expression_evaluator.hpp b/include/mapnik/expression_evaluator.hpp index a4d199012..e23da962f 100644 --- a/include/mapnik/expression_evaluator.hpp +++ b/include/mapnik/expression_evaluator.hpp @@ -50,6 +50,10 @@ struct evaluate : boost::static_visitor return attr.value(feature_); } + value_type operator() (geometry_type_attribute const& attr) const + { + return attr.value(feature_); + } value_type operator() (binary_node const & x) const { diff --git a/include/mapnik/expression_grammar.hpp b/include/mapnik/expression_grammar.hpp index c74b70d47..0fe062923 100644 --- a/include/mapnik/expression_grammar.hpp +++ b/include/mapnik/expression_grammar.hpp @@ -29,7 +29,6 @@ // boost #include -#include #include #include @@ -87,14 +86,7 @@ struct regex_match_impl : tr_(tr) {} template - expr_node operator() (T0 & node, T1 const& pattern) const - { -#if defined(BOOST_REGEX_HAS_ICU) - return regex_match_node(node,tr_.transcode(pattern.c_str())); -#else - return regex_match_node(node,pattern); -#endif - } + expr_node operator() (T0 & node, T1 const& pattern) const; mapnik::transcoder const& tr_; }; @@ -111,149 +103,34 @@ struct regex_replace_impl : tr_(tr) {} template - expr_node operator() (T0 & node, T1 const& pattern, T2 const& format) const - { -#if defined(BOOST_REGEX_HAS_ICU) - return regex_replace_node(node,tr_.transcode(pattern.c_str()),tr_.transcode(format.c_str())); -#else - return regex_replace_node(node,pattern,format); -#endif - } + expr_node operator() (T0 & node, T1 const& pattern, T2 const& format) const; mapnik::transcoder const& tr_; }; +struct geometry_types : qi::symbols +{ + geometry_types() + { + add + ("point",1) + ("line", 2) + ("polygon",3) + ; + } +}; + template struct expression_grammar : qi::grammar { typedef qi::rule rule_type; - explicit expression_grammar(mapnik::transcoder const& tr) - : expression_grammar::base_type(expr), - unicode_(unicode_impl(tr)), - regex_match_(regex_match_impl(tr)), - regex_replace_(regex_replace_impl(tr)) - { - using boost::phoenix::construct; - using qi::_1; - using qi::_a; - using qi::_b; - using qi::_r1; -#if BOOST_VERSION > 104200 - using qi::no_skip; -#endif - using qi::lexeme; - using qi::_val; - using qi::lit; - using qi::int_; - using qi::double_; - using qi::hex; - using qi::omit; - using standard_wide::char_; - - expr = logical_expr.alias(); - - logical_expr = not_expr [_val = _1] - >> - *( ( ( lit("and") | lit("&&")) >> not_expr [_val && _1] ) - | (( lit("or") | lit("||")) >> not_expr [_val || _1]) - ) - ; - - not_expr = - cond_expr [_val = _1 ] - | ((lit("not") | lit('!')) >> cond_expr [ _val = !_1 ]) - ; - - cond_expr = equality_expr [_val = _1] | additive_expr [_val = _1] - ; - - equality_expr = - relational_expr [_val = _1] - >> *( ( (lit("=") | lit("eq") | lit("is")) >> relational_expr [_val == _1]) - | (( lit("!=") | lit("<>") | lit("neq") ) >> relational_expr [_val != _1]) - ) - ; - - regex_match_expr = lit(".match") - >> lit('(') - >> ustring [_val = _1] - >> lit(')') - ; - - regex_replace_expr = - lit(".replace") - >> lit('(') - >> ustring [_a = _1] - >> lit(',') - >> ustring [_b = _1] - >> lit(')') [_val = regex_replace_(_r1,_a,_b)] - ; - - relational_expr = additive_expr[_val = _1] - >> - *( ( (lit("<=") | lit("le") ) >> additive_expr [ _val <= _1 ]) - | ( (lit('<') | lit("lt") ) >> additive_expr [ _val < _1 ]) - | ( (lit(">=") | lit("ge") ) >> additive_expr [ _val >= _1 ]) - | ( (lit('>') | lit("gt") ) >> additive_expr [ _val > _1 ]) - ) - ; - - additive_expr = multiplicative_expr [_val = _1] - >> * ( '+' >> multiplicative_expr[_val += _1] - | '-' >> multiplicative_expr[_val -= _1] - ) - ; - - multiplicative_expr = unary_expr [_val = _1] - >> *( '*' >> unary_expr [_val *= _1] - | '/' >> unary_expr [_val /= _1] - | '%' >> unary_expr [_val %= _1] - | regex_match_expr[_val = regex_match_(_val, _1)] - | regex_replace_expr(_val) [_val = _1] - ) - ; - - unary_expr = primary_expr [_val = _1] - | '+' >> primary_expr [_val = _1] - | '-' >> primary_expr [_val = -_1] - ; - - primary_expr = strict_double [_val = _1] - | int_ [_val = _1] - | lit("true") [_val = true] - | lit("false") [_val = false] - | lit("null") [_val = value_null() ] - | ustring [_val = unicode_(_1) ] - | attr [_val = construct( _1 ) ] - | '(' >> expr [_val = _1 ] >> ')' - ; - - unesc_char.add("\\a", '\a')("\\b", '\b')("\\f", '\f')("\\n", '\n') - ("\\r", '\r')("\\t", '\t')("\\v", '\v')("\\\\", '\\') - ("\\\'", '\'')("\\\"", '\"') - ; - -#if BOOST_VERSION > 104500 - quote_char %= char_('\'') | char_('"'); - ustring %= omit[quote_char[_a = _1]] - >> *(unesc_char | "\\x" >> hex | (char_ - lit(_a))) - >> lit(_a); - attr %= '[' >> no_skip[+~char_(']')] >> ']'; -#else - ustring %= lit('\'') - >> *(unesc_char | "\\x" >> hex | (char_ - lit('\''))) - >> lit('\''); - attr %= '[' >> lexeme[+(char_ - ']')] >> ']'; -#endif - - } + explicit expression_grammar(mapnik::transcoder const& tr); qi::real_parser > strict_double; boost::phoenix::function unicode_; boost::phoenix::function regex_match_; boost::phoenix::function regex_replace_; - // rule_type expr; rule_type equality_expr; rule_type cond_expr; @@ -270,6 +147,7 @@ struct expression_grammar : qi::grammar qi::rule > ustring; qi::symbols unesc_char; qi::rule quote_char; + geometry_types geom_type; }; } // namespace diff --git a/include/mapnik/expression_node.hpp b/include/mapnik/expression_node.hpp index a123297c5..56b70a9ef 100644 --- a/include/mapnik/expression_node.hpp +++ b/include/mapnik/expression_node.hpp @@ -28,12 +28,12 @@ #include // boost -#include -#include #include #if defined(BOOST_REGEX_HAS_ICU) #include #endif +#include +#include #include namespace mapnik @@ -174,6 +174,7 @@ typedef mapnik::value value_type; typedef boost::variant < value_type, attribute, +geometry_type_attribute, boost::recursive_wrapper >, boost::recursive_wrapper >, boost::recursive_wrapper >, @@ -239,12 +240,10 @@ struct binary_node }; #if defined(BOOST_REGEX_HAS_ICU) + struct regex_match_node { - regex_match_node (expr_node const& a, UnicodeString const& ustr) - : expr(a), - pattern(boost::make_u32regex(ustr)) {} - + regex_match_node (expr_node const& a, UnicodeString const& ustr); expr_node expr; boost::u32regex pattern; }; @@ -252,22 +251,17 @@ struct regex_match_node struct regex_replace_node { - regex_replace_node (expr_node const& a, UnicodeString const& ustr, UnicodeString const& f) - : expr(a), - pattern(boost::make_u32regex(ustr)), - format(f) {} - + regex_replace_node (expr_node const& a, UnicodeString const& ustr, UnicodeString const& f); expr_node expr; boost::u32regex pattern; UnicodeString format; }; + #else + struct regex_match_node { - regex_match_node (expr_node const& a, std::string const& str) - : expr(a), - pattern(str) {} - + regex_match_node (expr_node const& a, std::string const& str); expr_node expr; boost::regex pattern; }; @@ -275,11 +269,7 @@ struct regex_match_node struct regex_replace_node { - regex_replace_node (expr_node const& a, std::string const& str, std::string const& f) - : expr(a), - pattern(str), - format(f) {} - + regex_replace_node (expr_node const& a, std::string const& str, std::string const& f); expr_node expr; boost::regex pattern; std::string format; diff --git a/include/mapnik/feature.hpp b/include/mapnik/feature.hpp index 7100f8e65..e4799a811 100644 --- a/include/mapnik/feature.hpp +++ b/include/mapnik/feature.hpp @@ -77,6 +77,11 @@ public: return index; } + void add(key_type const& name, size_type index) + { + mapping_.insert(std::make_pair(name, index)); + } + size_type size() const { return mapping_.size(); } const_iterator begin() const { return mapping_.begin();} const_iterator end() const { return mapping_.end();} diff --git a/include/mapnik/font_engine_freetype.hpp b/include/mapnik/font_engine_freetype.hpp index b7c716dd5..b1d7b340a 100644 --- a/include/mapnik/font_engine_freetype.hpp +++ b/include/mapnik/font_engine_freetype.hpp @@ -365,7 +365,7 @@ struct text_renderer : private boost::noncopyable stroker & s, composite_mode_e comp_op = src_over, double scale_factor=1.0); - box2d prepare_glyphs(text_path *path); + box2d prepare_glyphs(text_path const& path); void render(pixel_position pos); void render_id(int feature_id, pixel_position pos, double min_radius=1.0); diff --git a/include/mapnik/geom_util.hpp b/include/mapnik/geom_util.hpp index ce9440dcc..31432aa33 100644 --- a/include/mapnik/geom_util.hpp +++ b/include/mapnik/geom_util.hpp @@ -32,13 +32,14 @@ // stl #include +#include namespace mapnik { template bool clip_test(T p,T q,double& tmin,double& tmax) { - double r; + double r = 0; bool result=true; if (p<0.0) { @@ -95,7 +96,8 @@ inline bool point_inside_path(double x,double y,Iter start,Iter end) double x0=boost::get<0>(*start); double y0=boost::get<1>(*start); - double x1,y1; + double x1 = 0; + double y1 = 0; while (++start!=end) { if ( boost::get<2>(*start) == SEG_MOVETO) @@ -172,7 +174,8 @@ inline bool point_on_path(double x,double y,Iter start,Iter end, double tol) { double x0=boost::get<0>(*start); double y0=boost::get<1>(*start); - double x1,y1; + double x1 = 0; + double y1 = 0; while (++start != end) { if ( boost::get<2>(*start) == SEG_MOVETO) @@ -216,6 +219,226 @@ struct filter_at_point return extent.contains(pt_); } }; + +//////////////////////////////////////////////////////////////////////////// +template +double path_length(PathType & path) +{ + double x0 = 0; + double y0 = 0; + double x1 = 0; + double y1 = 0; + path.rewind(0); + unsigned command = path.vertex(&x0,&y0); + if (command == SEG_END) return 0; + double length = 0; + while (SEG_END != (command = path.vertex(&x1, &y1))) + { + length += distance(x0,y0,x1,y1); + x0 = x1; + y0 = y1; + } + return length; } +template +bool middle_point(PathType & path, double & x, double & y) +{ + double x0 = 0; + double y0 = 0; + double x1 = 0; + double y1 = 0; + double mid_length = 0.5 * path_length(path); + path.rewind(0); + unsigned command = path.vertex(&x0,&y0); + if (command == SEG_END) return false; + double dist = 0.0; + while (SEG_END != (command = path.vertex(&x1, &y1))) + { + double seg_length = distance(x0, y0, x1, y1); + + if ( dist + seg_length >= mid_length) + { + double r = (mid_length - dist)/seg_length; + x = x0 + (x1 - x0) * r; + y = y0 + (y1 - y0) * r; + break; + } + dist += seg_length; + x0 = x1; + y0 = y1; + } + return true; +} + +namespace label { + +template +bool centroid(PathType & path, double & x, double & y) +{ + double x0 = 0; + double y0 = 0; + double x1 = 0; + double y1 = 0; + double start_x; + double start_y; + + path.rewind(0); + unsigned command = path.vertex(&x0, &y0); + if (command == SEG_END) return false; + + start_x = x0; + start_y = y0; + + double atmp = 0; + double xtmp = 0; + double ytmp = 0; + unsigned count = 1; + 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 (count == 1) + { + x = start_x; + y = start_y; + 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 +bool hit_test(PathType & path, double x, double y, double tol) +{ + bool inside=false; + double x0 = 0; + double y0 = 0; + double x1 = 0; + double y1 = 0; + path.rewind(0); + unsigned command = path.vertex(&x0, &y0); + if (command == SEG_END) return false; + unsigned count = 0; + while (SEG_END != (command = path.vertex(&x1, &y1))) + { + ++count; + if (command == SEG_MOVETO) + { + x0 = x1; + y0 = y1; + continue; + } + if ((((y1 <= y) && (y < y0)) || + ((y0 <= y) && (y < y1))) && + (x < (x0 - x1) * (y - y1)/ (y0 - y1) + x1)) + inside=!inside; + + x0 = x1; + y0 = y1; + } + + if (count == 0) // one vertex + { + return distance(x, y, x0, y0) <= fabs(tol); + } + return inside; +} + +template +void interior_position(PathType & path, double & x, double & y) +{ + // start with the centroid + label::centroid(path, x,y); + + // if we are not a polygon, or the default is within the polygon we are done + if (hit_test(path,x,y,0.001)) + return; + + // otherwise we find a horizontal line across the polygon and then return the + // center of the widest intersection between the polygon and the line. + + std::vector intersections; // only need to store the X as we know the y + + double x0 = 0; + double y0 = 0; + path.rewind(0); + unsigned command = path.vertex(&x0, &y0); + double x1 = 0; + double y1 = 0; + while (SEG_END != (command = path.vertex(&x1, &y1))) + { + if (command != SEG_MOVETO) + { + // if the segments overlap + if (y0==y1) + { + if (y0==y) + { + double xi = (x0+x1)/2.0; + intersections.push_back(xi); + } + } + // if the path segment crosses the bisector + else if ((y0 <= y && y1 >= y) || + (y0 >= y && y1 <= y)) + { + // then calculate the intersection + double xi = x0; + if (x0 != x1) + { + double m = (y1-y0)/(x1-x0); + double c = y0 - m*x0; + xi = (y-c)/m; + } + + intersections.push_back(xi); + } + } + x0 = x1; + y0 = y1; + } + // no intersections we just return the default + if (intersections.empty()) + return; + x0=intersections[0]; + double max_width = 0; + for (unsigned ii = 1; ii < intersections.size(); ++ii) + { + double x1=intersections[ii]; + double xc=(x0+x1)/2.0; + double width = std::fabs(x1-x0); + if (width > max_width && hit_test(path,xc,y,0)) + { + x=xc; + max_width = width; + break; + } + } +} + +}} + #endif // MAPNIK_GEOM_UTIL_HPP diff --git a/include/mapnik/geometry.hpp b/include/mapnik/geometry.hpp index 691bf5404..31bfeb337 100644 --- a/include/mapnik/geometry.hpp +++ b/include/mapnik/geometry.hpp @@ -80,13 +80,18 @@ public: return cont_; } + size_type size() const + { + return cont_.size(); + } + box2d envelope() const { box2d result; - double x(0); - double y(0); + double x = 0; + double y = 0; rewind(0); - for (unsigned i=0;i intersections; // only need to store the X as we know the y - - double x0=0; - double y0=0; - rewind(0); - unsigned command = vertex(&x0, &y0); - double x1,y1; - while (SEG_END != (command=vertex(&x1, &y1))) - { - if (command != SEG_MOVETO) - { - // if the segments overlap - if (y0==y1) - { - if (y0==*y) - { - double xi = (x0+x1)/2.0; - intersections.push_back(xi); - } - } - // if the path segment crosses the bisector - else if ((y0 <= *y && y1 >= *y) || - (y0 >= *y && y1 <= *y)) - { - // then calculate the intersection - double xi = x0; - if (x0 != x1) - { - double m = (y1-y0)/(x1-x0); - double c = y0 - m*x0; - xi = (*y-c)/m; - } - - intersections.push_back(xi); - } - } - x0 = x1; - y0 = y1; - } - // no intersections we just return the default - if (intersections.empty()) - return; - x0=intersections[0]; - double max_width = 0; - for (unsigned ii = 1; ii < intersections.size(); ++ii) - { - double x1=intersections[ii]; - double xc=(x0+x1)/2.0; - double width = fabs(x1-x0); - if (width > max_width && hit_test(xc,*y,0)) - { - *x=xc; - max_width = width; - } - } - } - - /* center of gravity centroid - - best visually but does not work with multipolygons - */ - void label_position(double *x, double *y) const - { - if (type_ == LineString) - { - middle_point(x,y); - return; - } - - unsigned size = cont_.size(); - if (size < 3) - { - cont_.get_vertex(0,x,y); - return; - } - - double ai; - double atmp = 0; - double xtmp = 0; - double ytmp = 0; - double x0 =0; - double y0 =0; - double x1 =0; - double y1 =0; - double ox =0; - double oy =0; - - unsigned i; - - // Use first point as origin to improve numerical accuracy - cont_.get_vertex(0,&ox,&oy); - - for (i = 0; i < size-1; i++) - { - cont_.get_vertex(i,&x0,&y0); - cont_.get_vertex(i+1,&x1,&y1); - - x0 -= ox; y0 -= oy; - x1 -= ox; y1 -= oy; - - ai = x0 * y1 - x1 * y0; - atmp += ai; - xtmp += (x1 + x0) * ai; - ytmp += (y1 + y0) * ai; - } - if (atmp != 0) - { - *x = (xtmp/(3*atmp)) + ox; - *y = (ytmp/(3*atmp)) + oy; - return; - } - *x=x0; - *y=y0; - } - - /* center of bounding box centroid */ - void label_position2(double *x, double *y) const - { - - box2d box = envelope(); - *x = box.center().x; - *y = box.center().y; - } - - /* summarized distance centroid */ - void label_position3(double *x, double *y) const - { - if (type_ == LineString) - { - middle_point(x,y); - return; - } - - unsigned i = 0; - double l = 0.0; - double tl = 0.0; - double cx = 0.0; - double cy = 0.0; - double x0 = 0.0; - double y0 = 0.0; - double x1 = 0.0; - double y1 = 0.0; - unsigned size = cont_.size(); - for (i = 0; i < size-1; i++) - { - cont_.get_vertex(i,&x0,&y0); - cont_.get_vertex(i+1,&x1,&y1); - l = distance(x0,y0,x1,y1); - cx += l * (x1 + x0)/2; - cy += l * (y1 + y0)/2; - tl += l; - } - *x = cx / tl; - *y = cy / tl; - } - - void middle_point(double *x, double *y) const - { - // calculate mid point on path - double x0=0; - double y0=0; - double x1=0; - double y1=0; - - unsigned size = cont_.size(); - if (size == 1) - { - cont_.get_vertex(0,x,y); - } - else if (size == 2) - { - cont_.get_vertex(0,&x0,&y0); - cont_.get_vertex(1,&x1,&y1); - *x = 0.5 * (x1 + x0); - *y = 0.5 * (y1 + y0); - } - else - { - double len=0.0; - for (unsigned pos = 1; pos < size; ++pos) - { - cont_.get_vertex(pos-1,&x0,&y0); - cont_.get_vertex(pos,&x1,&y1); - double dx = x1 - x0; - double dy = y1 - y0; - len += std::sqrt(dx * dx + dy * dy); - } - double midlen = 0.5 * len; - double dist = 0.0; - for (unsigned pos = 1; pos < size;++pos) - { - cont_.get_vertex(pos-1,&x0,&y0); - cont_.get_vertex(pos,&x1,&y1); - double dx = x1 - x0; - double dy = y1 - y0; - double seg_len = std::sqrt(dx * dx + dy * dy); - if (( dist + seg_len) >= midlen) - { - double r = (midlen - dist)/seg_len; - *x = x0 + (x1 - x0) * r; - *y = y0 + (y1 - y0) * r; - break; - } - dist += seg_len; - } - } - } - void push_vertex(coord_type x, coord_type y, CommandType c) { cont_.push_back(x,y,c); @@ -335,62 +121,20 @@ public: push_vertex(x,y,SEG_MOVETO); } - unsigned num_points() const - { - return cont_.size(); - } - unsigned vertex(double* x, double* y) const { return cont_.get_vertex(itr_++,x,y); } - unsigned get_vertex(unsigned pos, double* x, double* y) const + unsigned vertex(std::size_t index, double* x, double* y) const { - return cont_.get_vertex(pos, x, y); + return cont_.get_vertex(index, x, y); } void rewind(unsigned ) const { itr_=0; } - - bool hit_test(coord_type x, coord_type y, double tol) const - { - if (cont_.size() == 1) { - // Handle points - double x0, y0; - cont_.get_vertex(0, &x0, &y0); - return distance(x, y, x0, y0) <= fabs(tol); - } else if (cont_.size() > 1) { - bool inside=false; - double x0=0; - double y0=0; - rewind(0); - vertex(&x0, &y0); - - unsigned command; - double x1,y1; - while (SEG_END != (command=vertex(&x1, &y1))) - { - if (command == SEG_MOVETO) - { - x0 = x1; - y0 = y1; - continue; - } - if ((((y1 <= y) && (y < y0)) || - ((y0 <= y) && (y < y1))) && - ( x < (x0 - x1) * (y - y1)/ (y0 - y1) + x1)) - inside=!inside; - x0=x1; - y0=y1; - } - return inside; - } - return false; - } - }; typedef geometry geometry_type; diff --git a/include/mapnik/grid/grid.hpp b/include/mapnik/grid/grid.hpp index 708f8bddc..0c89e8173 100644 --- a/include/mapnik/grid/grid.hpp +++ b/include/mapnik/grid/grid.hpp @@ -58,7 +58,6 @@ public: typedef std::string lookup_type; // mapping between pixel id and key typedef std::map feature_key_type; - typedef std::map key_type; typedef std::map feature_type; static const value_type base_mask; @@ -77,39 +76,9 @@ private: public: - hit_grid(int width, int height, std::string const& key, unsigned int resolution) - :width_(width), - height_(height), - key_(key), - data_(width,height), - resolution_(resolution), - id_name_("__id__"), - painted_(false), - names_(), - f_keys_(), - features_(), - ctx_(boost::make_shared()) - { - f_keys_[base_mask] = ""; - data_.set(base_mask); - } + hit_grid(int width, int height, std::string const& key, unsigned int resolution); - hit_grid(const hit_grid& rhs) - :width_(rhs.width_), - height_(rhs.height_), - key_(rhs.key_), - data_(rhs.data_), - resolution_(rhs.resolution_), - id_name_("__id__"), - painted_(rhs.painted_), - names_(rhs.names_), - f_keys_(rhs.f_keys_), - features_(rhs.features_), - ctx_(rhs.ctx_) - { - f_keys_[base_mask] = ""; - data_.set(base_mask); - } + hit_grid(hit_grid const& rhs); ~hit_grid() {} @@ -128,64 +97,7 @@ public: return id_name_; } - inline void add_feature(mapnik::feature_impl & feature) - { - int feature_id = feature.id(); - // avoid adding duplicate features (e.g. in the case of both a line symbolizer and a polygon symbolizer) - typename feature_key_type::const_iterator feature_pos = f_keys_.find(feature_id); - if (feature_pos != f_keys_.end()) - { - return; - } - - if (ctx_->size() == 0) { - mapnik::feature_impl::iterator itr = feature.begin(); - mapnik::feature_impl::iterator end = feature.end(); - for ( ;itr!=end; ++itr) - { - ctx_->push(boost::get<0>(*itr)); - } - } - // NOTE: currently lookup keys must be strings, - // but this should be revisited - lookup_type lookup_value; - if (key_ == id_name_) - { - mapnik::util::to_string(lookup_value,feature_id); - } - else - { - if (feature.has_key(key_)) - { - lookup_value = feature.get(key_).to_string(); - } - else - { - MAPNIK_LOG_DEBUG(grid) << "hit_grid: Should not get here: key '" << key_ << "' not found in feature properties"; - } - } - - if (!lookup_value.empty()) - { - // TODO - consider shortcutting f_keys if feature_id == lookup_value - // create a mapping between the pixel id and the feature key - f_keys_.insert(std::make_pair(feature_id,lookup_value)); - // if extra fields have been supplied, push them into grid memory - if (!names_.empty()) - { - // it is ~ 2x faster to copy feature attributes compared - // to building up a in-memory cache of feature_ptrs - // https://github.com/mapnik/mapnik/issues/1198 - mapnik::feature_ptr feature2(mapnik::feature_factory::create(ctx_,feature_id)); - feature2->set_data(feature.get_data()); - features_.insert(std::make_pair(lookup_value,feature2)); - } - } - else - { - MAPNIK_LOG_DEBUG(grid) << "hit_grid: Warning - key '" << key_ << "' was blank for " << feature; - } - } + inline void add_feature(mapnik::feature_impl & feature); inline void add_property_name(std::string const& name) { @@ -197,27 +109,17 @@ public: return names_; } - inline const feature_type& get_grid_features() const + inline feature_type const& get_grid_features() const { return features_; } - inline feature_type& get_grid_features() - { - return features_; - } - - inline const feature_key_type& get_feature_keys() const + inline feature_key_type const& get_feature_keys() const { return f_keys_; } - inline feature_key_type& get_feature_keys() - { - return f_keys_; - } - - inline const std::string& get_key() const + inline std::string const& get_key() const { return key_; } @@ -237,7 +139,7 @@ public: resolution_ = res; } - inline const data_type& data() const + inline data_type const& data() const { return data_; } @@ -247,7 +149,7 @@ public: return data_; } - inline const T* raw_data() const + inline T const * raw_data() const { return data_.getData(); } @@ -257,7 +159,7 @@ public: return data_.getData(); } - inline const value_type* getRow(unsigned row) const + inline value_type const * getRow(unsigned row) const { return data_.getRow(row); } diff --git a/include/mapnik/grid/grid_renderer.hpp b/include/mapnik/grid/grid_renderer.hpp index fe4c65a15..1fa66aedf 100644 --- a/include/mapnik/grid/grid_renderer.hpp +++ b/include/mapnik/grid/grid_renderer.hpp @@ -65,7 +65,7 @@ public: 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) {} - void render_marker(mapnik::feature_impl & feature, unsigned int step, pixel_position const& pos, marker const& marker, const agg::trans_affine & tr, double opacity); + void render_marker(mapnik::feature_impl & feature, unsigned int step, pixel_position const& pos, marker const& marker, const agg::trans_affine & tr, double opacity, composite_mode_e comp_op); void process(point_symbolizer const& sym, mapnik::feature_impl & feature, @@ -119,6 +119,7 @@ private: face_manager font_manager_; label_collision_detector4 detector_; boost::scoped_ptr ras_ptr; + box2d query_extent_; }; } diff --git a/include/mapnik/grid/grid_util.hpp b/include/mapnik/grid/grid_util.hpp index 517c4ccc1..b1b61c661 100644 --- a/include/mapnik/grid/grid_util.hpp +++ b/include/mapnik/grid/grid_util.hpp @@ -26,6 +26,9 @@ // mapnik #include +// boost +#include + namespace mapnik { /* @@ -45,15 +48,20 @@ static inline void scale_grid(mapnik::grid::data_type & target, if (source_width<1 || source_height<1 || target_width<1 || target_height<1) return; - int x=0,y=0,xs=0,ys=0; + int x = 0; + int y = 0; + int xs = 0; + int ys = 0; int tw2 = target_width/2; int th2 = target_height/2; int offs_x = rint((source_width-target_width-x_off_f*2*source_width)/2); int offs_y = rint((source_height-target_height-y_off_f*2*source_height)/2); - unsigned yprt(0); - unsigned yprt1(0); - unsigned xprt(0); - unsigned xprt1(0); + unsigned yprt = 0; + unsigned yprt1 = 0; + unsigned xprt = 0; + unsigned xprt1 = 0; + boost::ignore_unused_variable_warning(yprt1); + boost::ignore_unused_variable_warning(xprt1); //no scaling or subpixel offset if (target_height == source_height && target_width == source_width && offs_x == 0 && offs_y == 0){ diff --git a/include/mapnik/grid/grid_view.hpp b/include/mapnik/grid/grid_view.hpp index 7e18050db..a33e1656a 100644 --- a/include/mapnik/grid/grid_view.hpp +++ b/include/mapnik/grid/grid_view.hpp @@ -53,7 +53,6 @@ public: typedef typename T::pixel_type pixel_type; typedef std::string lookup_type; typedef std::map feature_key_type; - typedef std::map key_type; typedef std::map feature_type; hit_grid_view(unsigned x, unsigned y, @@ -115,6 +114,7 @@ public: names_ = rhs.names_; f_keys_ = rhs.f_keys_; features_ = rhs.features_; + return *this; } inline unsigned x() const @@ -142,7 +142,7 @@ public: return id_name_; } - inline const value_type* getRow(unsigned row) const + inline value_type const * getRow(unsigned row) const { return data_.getRow(row + y_) + x_; } @@ -162,22 +162,22 @@ public: return data_.getBytes(); } - std::set const& property_names() const + inline std::set const& property_names() const { return names_; } - inline const feature_type& get_grid_features() const + inline feature_type const& get_grid_features() const { return features_; } - inline const feature_key_type& get_feature_keys() const + inline feature_key_type const& get_feature_keys() const { return f_keys_; } - inline const lookup_type& get_key() const + inline lookup_type const& get_key() const { return key_; } @@ -206,4 +206,3 @@ typedef hit_grid_view > grid_view; } #endif // MAPNIK_GRID_VIEW_HPP - diff --git a/include/mapnik/hit_test_filter.hpp b/include/mapnik/hit_test_filter.hpp index 461c7daba..792c8c12e 100644 --- a/include/mapnik/hit_test_filter.hpp +++ b/include/mapnik/hit_test_filter.hpp @@ -25,6 +25,9 @@ // mapnik #include +#include +// boost +#include namespace mapnik { class hit_test_filter @@ -35,12 +38,11 @@ public: y_(y), tol_(tol) {} - bool pass(Feature const& feature) + bool pass(Feature & feature) { - for (unsigned i=0;i comp_op_from_string(std::string const& name); +MAPNIK_DECL boost::optional comp_op_to_string(composite_mode_e comp_op); template MAPNIK_DECL void composite(T1 & dst, T2 & src, diff --git a/include/mapnik/image_filter.hpp b/include/mapnik/image_filter.hpp index a92b91fc7..58fee0181 100644 --- a/include/mapnik/image_filter.hpp +++ b/include/mapnik/image_filter.hpp @@ -487,7 +487,7 @@ struct filter_visitor : boost::static_visitor : src_(src) {} template - void operator () (T filter_tag) + void operator () (T const& filter_tag) { apply_filter(src_,filter_tag); } @@ -495,7 +495,6 @@ struct filter_visitor : boost::static_visitor Src & src_; }; - }} #endif // MAPNIK_IMAGE_FILTER_HPP diff --git a/include/mapnik/image_filter_types.hpp b/include/mapnik/image_filter_types.hpp index f39d8a722..bb19f5392 100644 --- a/include/mapnik/image_filter_types.hpp +++ b/include/mapnik/image_filter_types.hpp @@ -23,7 +23,12 @@ #ifndef MAPNIK_IMAGE_FILTER_TYPES_HPP #define MAPNIK_IMAGE_FILTER_TYPES_HPP +// boost #include +#include +#include +// stl +#include namespace mapnik { namespace filter { @@ -37,18 +42,14 @@ struct x_gradient {}; struct y_gradient {}; struct invert {}; -struct agg_stack_blur +struct agg_stack_blur { agg_stack_blur(unsigned rx_, unsigned ry_) : rx(rx_),ry(ry_) {} - // an attempt to support older boost spirit (< 1.46) - agg_stack_blur() - : rx(1),ry(1) {} unsigned rx; unsigned ry; }; - typedef boost::variant filter_type; +inline std::ostream& operator<< (std::ostream& os, blur) +{ + os << "blur"; + return os; +} + +inline std::ostream& operator<< (std::ostream& os, gray) +{ + os << "gray"; + return os; +} + +inline std::ostream& operator<< (std::ostream& os, agg_stack_blur const& filter) +{ + os << "agg-stack-blur:" << filter.rx << ',' << filter.ry; + return os; +} + +inline std::ostream& operator<< (std::ostream& os, emboss) +{ + os << "emboss"; + return os; +} + +inline std::ostream& operator<< (std::ostream& os, sharpen) +{ + os << "sharpen"; + return os; +} + +inline std::ostream& operator<< (std::ostream& os, edge_detect) +{ + os << "edge-detect"; + return os; +} + +inline std::ostream& operator<< (std::ostream& os, sobel) +{ + os << "sobel"; + return os; +} + +inline std::ostream& operator<< (std::ostream& os, x_gradient) +{ + os << "x-gradient"; + return os; +} + +inline std::ostream& operator<< (std::ostream& os, y_gradient) +{ + os << "y-gradient"; + return os; +} + +inline std::ostream& operator<< (std::ostream& os, invert) +{ + os << "invert"; + return os; +} + +template +struct to_string_visitor : boost::static_visitor +{ + to_string_visitor(Out & out) + : out_(out) {} + + template + void operator () (T const& filter_tag) + { + out_ << filter_tag; + } + + Out & out_; +}; + +inline std::ostream& operator<< (std::ostream& os, filter_type const& filter) +{ + to_string_visitor visitor(os); + boost::apply_visitor(visitor, filter); + return os; +} + +template +bool generate_image_filters(OutputIterator& sink, Container const& v) +{ + using boost::spirit::karma::stream; + using boost::spirit::karma::generate; + bool r = generate(sink, stream % ' ', v); + return r; +} + }} #endif // MAPNIK_IMAGE_FILTER_TYPES_HPP diff --git a/include/mapnik/image_scaling.hpp b/include/mapnik/image_scaling.hpp new file mode 100644 index 000000000..89e5fcd69 --- /dev/null +++ b/include/mapnik/image_scaling.hpp @@ -0,0 +1,83 @@ +/***************************************************************************** + * + * 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 MAPNIK_IMAGE_SCALING_HPP +#define MAPNIK_IMAGE_SCALING_HPP + +// stl +#include + +#include +#include + +namespace mapnik +{ + +enum scaling_method_e +{ + SCALING_NEAR=0, + SCALING_BILINEAR, + SCALING_BICUBIC, + SCALING_SPLINE16, + SCALING_SPLINE36, + SCALING_HANNING, + SCALING_HAMMING, + SCALING_HERMITE, + SCALING_KAISER, + SCALING_QUADRIC, + SCALING_CATROM, + SCALING_GAUSSIAN, + SCALING_BESSEL, + SCALING_MITCHELL, + SCALING_SINC, + SCALING_LANCZOS, + SCALING_BLACKMAN, + SCALING_BILINEAR8 +}; + +boost::optional scaling_method_from_string(std::string const& name); +boost::optional scaling_method_to_string(scaling_method_e scaling_method); + +template +void scale_image_agg(Image & target, + Image const& source, + scaling_method_e scaling_method, + double scale_factor, + double x_off_f=0, + double y_off_f=0, + double filter_radius=2, + double ratio=1); + +template +void scale_image_bilinear_old(Image & target, + Image const& source, + double x_off_f=0, + double y_off_f=0); + +template +void scale_image_bilinear8(Image & target, + Image const& source, + double x_off_f=0, + double y_off_f=0); + +} +#endif // MAPNIK_IMAGE_SCALING_HPP diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index bb5a563f3..0f438eeb8 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -60,7 +60,8 @@ public: #if defined(HAVE_CAIRO) MAPNIK_DECL void save_to_cairo_file(mapnik::Map const& map, std::string const& filename, - std::string const& type); + std::string const& type, + double scale_factor=1.0); #endif template @@ -184,38 +185,7 @@ void add_border(T & image) } } -// IMAGE SCALING -enum scaling_method_e -{ - SCALING_NEAR=0, - SCALING_BILINEAR=1, - SCALING_BICUBIC=2, - SCALING_SPLINE16=3, - SCALING_SPLINE36=4, - SCALING_HANNING=5, - SCALING_HAMMING=6, - SCALING_HERMITE=7, - SCALING_KAISER=8, - SCALING_QUADRIC=9, - SCALING_CATROM=10, - SCALING_GAUSSIAN=11, - SCALING_BESSEL=12, - SCALING_MITCHELL=13, - SCALING_SINC=14, - SCALING_LANCZOS=15, - SCALING_BLACKMAN=16 -}; -scaling_method_e get_scaling_method_by_name (std::string name); - -template -void scale_image_agg (Image& target,const Image& source, scaling_method_e scaling_method, double scale_factor, double x_off_f=0, double y_off_f=0, double filter_radius=2, double ratio=1); - -template -void scale_image_bilinear_old (Image& target,const Image& source, double x_off_f=0, double y_off_f=0); - -template -void scale_image_bilinear8 (Image& target,const Image& source, double x_off_f=0, double y_off_f=0); /////////// save_to_file //////////////////////////////////////////////// class image_32; diff --git a/include/mapnik/image_view.hpp b/include/mapnik/image_view.hpp index 1008a6d2a..135125f79 100644 --- a/include/mapnik/image_view.hpp +++ b/include/mapnik/image_view.hpp @@ -61,6 +61,7 @@ public: width_ = rhs.width_; height_ = rhs.height_; data_ = rhs.data_; + return *this; } inline unsigned x() const @@ -77,6 +78,7 @@ public: { return width_; } + inline unsigned height() const { return height_; diff --git a/include/mapnik/json/feature_grammar.hpp b/include/mapnik/json/feature_grammar.hpp index b756daead..b56a991b7 100644 --- a/include/mapnik/json/feature_grammar.hpp +++ b/include/mapnik/json/feature_grammar.hpp @@ -25,6 +25,7 @@ // mapnik #include +#include // spirit::qi #include @@ -135,196 +136,7 @@ struct feature_grammar : qi::grammar { - feature_grammar(mapnik::transcoder const& tr) - : feature_grammar::base_type(feature,"feature"), - put_property_(put_property(tr)) - { - using qi::lit; - using qi::int_; - using qi::double_; -#if BOOST_VERSION > 104200 - using qi::no_skip; -#else - using qi::lexeme; -#endif - using standard_wide::char_; - using qi::_val; - using qi::_1; - using qi::_2; - using qi::_3; - using qi::_4; - using qi::_a; - using qi::_b; - using qi::_r1; - using qi::_r2; - using qi::fail; - using qi::on_error; - using qi::_pass; - using qi::eps; - using qi::raw; - - using phoenix::new_; - using phoenix::push_back; - using phoenix::construct; - - // generic json types - value = object | array | string_ - | number - ; - - pairs = key_value % lit(',') - ; - - key_value = (string_ >> lit(':') >> value) - ; - - object = lit('{') - >> *pairs - >> lit('}') - ; - array = lit('[') - >> value >> *(lit(',') >> value) - >> lit(']') - ; - - number %= strict_double - | int_ - | lit("true") [_val = true] - | lit ("false") [_val = false] - | lit("null")[_val = construct()] - ; - - unesc_char.add - ("\\\"", '\"') // quotation mark - ("\\\\", '\\') // reverse solidus - ("\\/", '/') // solidus - ("\\b", '\b') // backspace - ("\\f", '\f') // formfeed - ("\\n", '\n') // newline - ("\\r", '\r') // carrige return - ("\\t", '\t') // tab - ; - - string_ %= lit('"') >> *(unesc_char | "\\u" >> hex4 | (char_ - lit('"'))) >> lit('"') - ; - - // geojson types - - feature_type = lit("\"type\"") - >> lit(':') - >> lit("\"Feature\"") - ; - - feature = lit('{') - >> (feature_type | (lit("\"geometry\"") > lit(':') > geometry(_r1)) | properties(_r1) | key_value) % lit(',') - >> lit('}') - ; - - properties = lit("\"properties\"") - >> lit(':') >> (lit('{') >> attributes(_r1) >> lit('}')) | lit("null") - ; - - attributes = (string_ [_a = _1] >> lit(':') >> attribute_value [put_property_(_r1,_a,_1)]) % lit(',') - ; - - attribute_value %= number | string_ ; - - // Nabialek trick - FIXME: how to bind argument to dispatch rule? - // geometry = lit("\"geometry\"") - // >> lit(':') >> lit('{') - // >> lit("\"type\"") >> lit(':') >> geometry_dispatch[_a = _1] - // >> lit(',') >> lit("\"coordinates\"") >> lit(':') - // >> qi::lazy(*_a) - // >> lit('}') - // ; - // geometry_dispatch.add - // ("\"Point\"",&point_coordinates) - // ("\"LineString\"",&linestring_coordinates) - // ("\"Polygon\"",&polygon_coordinates) - // ; - ////////////////////////////////////////////////////////////////// - - geometry = (lit('{')[_a = 0 ] - >> lit("\"type\"") >> lit(':') >> geometry_dispatch[_a = _1] // <---- should be Nabialek trick! - >> lit(',') - >> (lit("\"coordinates\"") > lit(':') > coordinates(_r1,_a) - | - lit("\"geometries\"") > lit(':') - >> lit('[') >> geometry_collection(_r1) >> lit(']')) - >> lit('}')) - | lit("null") - ; - - geometry_dispatch.add - ("\"Point\"",1) - ("\"LineString\"",2) - ("\"Polygon\"",3) - ("\"MultiPoint\"",4) - ("\"MultiLineString\"",5) - ("\"MultiPolygon\"",6) - ("\"GeometryCollection\"",7) - // - ; - - coordinates = (eps(_r2 == 1) > point_coordinates(extract_geometry_(_r1))) - | (eps(_r2 == 2) > linestring_coordinates(extract_geometry_(_r1))) - | (eps(_r2 == 3) > polygon_coordinates(extract_geometry_(_r1))) - | (eps(_r2 == 4) > multipoint_coordinates(extract_geometry_(_r1))) - | (eps(_r2 == 5) > multilinestring_coordinates(extract_geometry_(_r1))) - | (eps(_r2 == 6) > multipolygon_coordinates(extract_geometry_(_r1))) - ; - - point_coordinates = eps[ _a = new_(Point) ] - > ( point(SEG_MOVETO,_a) [push_back(_r1,_a)] | eps[cleanup_(_a)][_pass = false] ) - ; - - linestring_coordinates = eps[ _a = new_(LineString)] - > -(points(_a) [push_back(_r1,_a)] - | eps[cleanup_(_a)][_pass = false]) - ; - - polygon_coordinates = eps[ _a = new_(Polygon) ] - > ((lit('[') - > -(points(_a) % lit(',')) - > lit(']')) [push_back(_r1,_a)] - | eps[cleanup_(_a)][_pass = false]) - ; - - multipoint_coordinates = lit('[') - > -(point_coordinates(_r1) % lit(',')) - > lit(']') - ; - - multilinestring_coordinates = lit('[') - > -(linestring_coordinates(_r1) % lit(',')) - > lit(']') - ; - - multipolygon_coordinates = lit('[') - > -(polygon_coordinates(_r1) % lit(',')) - > lit(']') - ; - - geometry_collection = *geometry(_r1) >> *(lit(',') >> geometry(_r1)) - ; - - // point - point = lit('[') > -((double_ > lit(',') > double_)[push_vertex_(_r1,_r2,_1,_2)]) > lit(']'); - // points - points = lit('[')[_a = SEG_MOVETO] > -(point (_a,_r1) % lit(',')[_a = SEG_LINETO]) > lit(']'); - on_error - ( - feature - , std::clog - << phoenix::val("Error! Expecting ") - << _4 // what failed? - << phoenix::val(" here: \"") - << construct(_3, _2) // iterators to error-pos, end - << phoenix::val("\"") - << std::endl - ); - - } + feature_grammar(mapnik::transcoder const& tr); // start // generic JSON diff --git a/include/mapnik/json/geometry_generator_grammar.hpp b/include/mapnik/json/geometry_generator_grammar.hpp index cbb09efef..a1915b062 100644 --- a/include/mapnik/json/geometry_generator_grammar.hpp +++ b/include/mapnik/json/geometry_generator_grammar.hpp @@ -78,7 +78,7 @@ struct get_first geometry_type::value_type const operator() (geometry_type const& geom) const { geometry_type::value_type coord; - boost::get<0>(coord) = geom.get_vertex(0,&boost::get<1>(coord),&boost::get<2>(coord)); + boost::get<0>(coord) = geom.vertex(0,&boost::get<1>(coord),&boost::get<2>(coord)); return coord; } }; diff --git a/include/mapnik/marker.hpp b/include/mapnik/marker.hpp index d8b181ad7..d26819892 100644 --- a/include/mapnik/marker.hpp +++ b/include/mapnik/marker.hpp @@ -65,19 +65,21 @@ public: (*bitmap_data_)->set(0xff000000); } - marker(const boost::optional &data) : bitmap_data_(data) + marker(const boost::optional &data) + : bitmap_data_(data) { } - marker(const boost::optional &data) : vector_data_(data) + marker(const boost::optional &data) + : vector_data_(data) { } - marker(const marker& rhs) : bitmap_data_(rhs.bitmap_data_), vector_data_(rhs.vector_data_) - { - } + marker(const marker& rhs) + : bitmap_data_(rhs.bitmap_data_), vector_data_(rhs.vector_data_) + {} box2d bounding_box() const { diff --git a/include/mapnik/marker_cache.hpp b/include/mapnik/marker_cache.hpp index 2e7f57699..b696a00b9 100644 --- a/include/mapnik/marker_cache.hpp +++ b/include/mapnik/marker_cache.hpp @@ -41,14 +41,21 @@ class marker; typedef boost::shared_ptr marker_ptr; -struct MAPNIK_DECL marker_cache : - public singleton , +class MAPNIK_DECL marker_cache : + public singleton , private boost::noncopyable { - - friend class CreateStatic; - static boost::unordered_map cache_; - static bool insert(std::string const& key, marker_ptr); + friend class CreateUsingNew; +private: + marker_cache(); + ~marker_cache(); + static bool insert_marker(std::string const& key, marker_ptr path); + static boost::unordered_map marker_cache_; + static bool insert_svg(std::string const& name, std::string const& svg_string); + static boost::unordered_map svg_cache_; +public: + static std::string known_svg_prefix_; + static bool is_uri(std::string const& path); static boost::optional find(std::string const& key, bool update_cache = false); static void clear(); }; diff --git a/include/mapnik/marker_helpers.hpp b/include/mapnik/marker_helpers.hpp new file mode 100644 index 000000000..fd26b8ca6 --- /dev/null +++ b/include/mapnik/marker_helpers.hpp @@ -0,0 +1,108 @@ +/***************************************************************************** + * + * 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_MARKER_HELPERS_HPP +#define MAPNIK_MARKER_HELPERS_HPP + +#include +#include +#include +#include + +// boost +#include + +namespace mapnik { + +template +bool push_explicit_style(Attr const& src, Attr & dst, markers_symbolizer const& sym) +{ + boost::optional const& strk = sym.get_stroke(); + boost::optional const& fill = sym.get_fill(); + if (strk || fill) + { + for(unsigned i = 0; i < src.size(); ++i) + { + mapnik::svg::path_attributes attr = src[i]; + + if (strk) + { + attr.stroke_flag = true; + attr.stroke_width = strk->get_width(); + color const& s_color = strk->get_color(); + attr.stroke_color = agg::rgba(s_color.red()/255.0,s_color.green()/255.0, + s_color.blue()/255.0,(s_color.alpha()*strk->get_opacity())/255.0); + } + if (fill) + { + + attr.fill_flag = true; + color const& f_color = *fill; + attr.fill_color = agg::rgba(f_color.red()/255.0,f_color.green()/255.0, + f_color.blue()/255.0,(f_color.alpha()*sym.get_opacity())/255.0); + } + dst.push_back(attr); + } + return true; + } + return false; +} + +template +void setup_label_transform(agg::trans_affine & tr, box2d const& bbox, mapnik::feature_impl const& feature, T const& sym) +{ + double width = 0; + double height = 0; + + expression_ptr const& width_expr = sym.get_width(); + if (width_expr) + width = boost::apply_visitor(evaluate(feature), *width_expr).to_double(); + + expression_ptr const& height_expr = sym.get_height(); + if (height_expr) + height = boost::apply_visitor(evaluate(feature), *height_expr).to_double(); + + if (width > 0 && height > 0) + { + double sx = width/bbox.width(); + double sy = height/bbox.height(); + tr *= agg::trans_affine_scaling(sx,sy); + } + else if (width > 0) + { + double sx = width/bbox.width(); + tr *= agg::trans_affine_scaling(sx); + } + else if (height > 0) + { + double sy = height/bbox.height(); + tr *= agg::trans_affine_scaling(sy); + } + else + { + evaluate_transform(tr, feature, sym.get_image_transform()); + } +} + +} + +#endif //MAPNIK_MARKER_HELPERS_HPP diff --git a/include/mapnik/markers_placement.hpp b/include/mapnik/markers_placement.hpp index 2524a36d9..a0828caba 100644 --- a/include/mapnik/markers_placement.hpp +++ b/include/mapnik/markers_placement.hpp @@ -47,7 +47,7 @@ public: * converted to a positive value with similar magnitude, but * choosen to optimize marker placement. 0 = no markers */ - markers_placement(Locator &locator, box2d size, agg::trans_affine const& tr, Detector &detector, double spacing, double max_error, bool allow_overlap); + markers_placement(Locator &locator, box2d const& size, agg::trans_affine const& tr, Detector &detector, double spacing, double max_error, bool allow_overlap); /** Start again at first marker. * \note Returns the same list of markers only works when they were NOT added * to the detector. diff --git a/include/mapnik/markers_symbolizer.hpp b/include/mapnik/markers_symbolizer.hpp index 90c1442c6..e8ba4cd0e 100644 --- a/include/mapnik/markers_symbolizer.hpp +++ b/include/mapnik/markers_symbolizer.hpp @@ -31,6 +31,9 @@ #include #include +// boost +#include + namespace mapnik { // TODO - consider merging with text_symbolizer label_placement_e @@ -46,9 +49,14 @@ struct MAPNIK_DECL markers_symbolizer : public symbolizer_with_image, public symbolizer_base { public: - explicit markers_symbolizer(); - markers_symbolizer(path_expression_ptr filename); + markers_symbolizer(); + markers_symbolizer(path_expression_ptr const& filename); markers_symbolizer(markers_symbolizer const& rhs); + + void set_width(expression_ptr const& width); + expression_ptr const& get_width() const; + void set_height(expression_ptr const& height); + expression_ptr const& get_height() const; void set_ignore_placement(bool ignore_placement); bool get_ignore_placement() const; void set_allow_overlap(bool overlap); @@ -57,28 +65,22 @@ public: double get_spacing() const; void set_max_error(double max_error); double get_max_error() const; - void set_fill(color fill); - color const& get_fill() const; - void set_width(expression_ptr width); - expression_ptr get_width() const; - void set_height(expression_ptr height); - expression_ptr get_height() const; - stroke const& get_stroke() const; + void set_fill(color const& fill); + boost::optional get_fill() const; void set_stroke(stroke const& stroke); + boost::optional get_stroke() const; void set_marker_placement(marker_placement_e marker_p); marker_placement_e get_marker_placement() const; - private: - bool ignore_placement_; - bool allow_overlap_; - color fill_; - double spacing_; - double max_error_; expression_ptr width_; expression_ptr height_; - stroke stroke_; + bool ignore_placement_; + bool allow_overlap_; + double spacing_; + double max_error_; + boost::optional fill_; + boost::optional stroke_; marker_placement_e marker_p_; - }; } diff --git a/include/mapnik/metawriter.hpp b/include/mapnik/metawriter.hpp index 693a9059a..7041286d1 100644 --- a/include/mapnik/metawriter.hpp +++ b/include/mapnik/metawriter.hpp @@ -110,7 +110,7 @@ public: virtual void add_box(box2d const& box, Feature const& feature, CoordTransform const& t, metawriter_properties const& properties)=0; - virtual void add_text(boost::ptr_vector &placements, + virtual void add_text(boost::ptr_vector const& placements, box2d const& extents, Feature const& feature, CoordTransform const& t, @@ -144,7 +144,11 @@ public: */ void set_size(int width, int height) { width_ = width; height_ = height; } /** Set Map object's srs. */ - virtual void set_map_srs(projection const& proj) { /* Not required when working with image coordinates. */ } + virtual void set_map_srs(projection const& proj) + { + boost::ignore_unused_variable_warning(proj); + } + /** Return the list of default properties. */ metawriter_properties const& get_default_properties() const { return dflt_properties_;} protected: diff --git a/include/mapnik/metawriter_inmem.hpp b/include/mapnik/metawriter_inmem.hpp index ee57f2a6b..6b77bf728 100644 --- a/include/mapnik/metawriter_inmem.hpp +++ b/include/mapnik/metawriter_inmem.hpp @@ -65,7 +65,7 @@ public: virtual void add_box(box2d const& box, Feature const& feature, CoordTransform const& t, metawriter_properties const& properties); - virtual void add_text(boost::ptr_vector &placements, + virtual void add_text(boost::ptr_vector const& placements, box2d const& extents, Feature const& feature, CoordTransform const& t, diff --git a/include/mapnik/metawriter_json.hpp b/include/mapnik/metawriter_json.hpp index 693824921..ab02d81b4 100644 --- a/include/mapnik/metawriter_json.hpp +++ b/include/mapnik/metawriter_json.hpp @@ -45,7 +45,7 @@ public: virtual void add_box(box2d const& box, Feature const& feature, CoordTransform const& t, metawriter_properties const& properties); - virtual void add_text(boost::ptr_vector &placements, + virtual void add_text(boost::ptr_vector const& placements, box2d const& extents, Feature const& feature, CoordTransform const& t, diff --git a/include/mapnik/placement_finder.hpp b/include/mapnik/placement_finder.hpp index dcc207ade..fb7cd13be 100644 --- a/include/mapnik/placement_finder.hpp +++ b/include/mapnik/placement_finder.hpp @@ -80,14 +80,10 @@ public: /** Remove old placements. */ void clear_placements(); - inline placements_type &get_results() { return placements_; } + inline placements_type const& get_results() { return placements_; } - /** Additional boxes to take into account when finding placement. - * Used for finding line placements where multiple placements are returned. - * Boxes are relative to starting point of current placement. - * Only used for point placements! - */ - std::vector > additional_boxes; + std::vector > & additional_boxes() { return additional_boxes_;} + std::vector > const& additional_boxes() const { return additional_boxes_;} void set_collect_extents(bool collect) { collect_extents_ = collect; } bool get_collect_extents() const { return collect_extents_; } @@ -160,6 +156,13 @@ private: box2d extents_; /** Collect a bounding box of all texts placed. */ bool collect_extents_; + + /** Additional boxes to take into account when finding placement. + * Used for finding line placements where multiple placements are returned. + * Boxes are relative to starting point of current placement. + * Only used for point placements! + */ + std::vector > additional_boxes_; }; } diff --git a/include/mapnik/raster_symbolizer.hpp b/include/mapnik/raster_symbolizer.hpp index 5f47e7053..192d70a7c 100644 --- a/include/mapnik/raster_symbolizer.hpp +++ b/include/mapnik/raster_symbolizer.hpp @@ -25,9 +25,12 @@ // mapnik #include +#include #include #include #include +#include +#include namespace mapnik { @@ -37,7 +40,7 @@ struct MAPNIK_DECL raster_symbolizer : public symbolizer_base raster_symbolizer() : symbolizer_base(), mode_("normal"), - scaling_("fast"), + scaling_(SCALING_NEAR), opacity_(1.0), colorizer_(), filter_factor_(-1), @@ -45,26 +48,40 @@ struct MAPNIK_DECL raster_symbolizer : public symbolizer_base raster_symbolizer(const raster_symbolizer &rhs) : symbolizer_base(rhs), - mode_(rhs.get_mode()), - scaling_(rhs.get_scaling()), - opacity_(rhs.get_opacity()), + mode_(rhs.mode_), + scaling_(rhs.scaling_), + opacity_(rhs.opacity_), colorizer_(rhs.colorizer_), filter_factor_(rhs.filter_factor_), mesh_size_(rhs.mesh_size_) {} std::string const& get_mode() const { + MAPNIK_LOG_ERROR(raster_symbolizer) << "getting 'mode' is deprecated and will be removed in Mapnik 3.x, use 'comp-op' with Mapnik >= 2.1.x"; return mode_; } void set_mode(std::string const& mode) { + MAPNIK_LOG_ERROR(raster_symbolizer) << "setting 'mode' is deprecated and will be removed in Mapnik 3.x, use 'comp-op' with Mapnik >= 2.1.x"; mode_ = mode; + if (mode == "normal") + { + this->set_comp_op(src_over); + } + else + { + boost::optional comp_op = comp_op_from_string(mode); + if (comp_op) + this->set_comp_op(*comp_op); + else + MAPNIK_LOG_ERROR(raster_symbolizer) << "could not convert mode into comp-op"; + } } - std::string const& get_scaling() const + scaling_method_e get_scaling_method() const { return scaling_; } - void set_scaling(std::string const& scaling) + void set_scaling_method(scaling_method_e scaling) { scaling_ = scaling; } @@ -99,13 +116,9 @@ struct MAPNIK_DECL raster_symbolizer : public symbolizer_base // respect explicitly specified values return filter_factor_; } else { - // No filter factor specified, calculate a sensible default value - // based on the scaling algorithm being employed. - scaling_method_e scaling = get_scaling_method_by_name (scaling_); - double ff = 1.0; - switch(scaling) + switch(scaling_) { case SCALING_NEAR: ff = 1.0; @@ -114,6 +127,7 @@ struct MAPNIK_DECL raster_symbolizer : public symbolizer_base // TODO potentially some of these algorithms would use filter_factor >2.0. // Contributions welcome from someone who knows more about them. case SCALING_BILINEAR: + case SCALING_BILINEAR8: case SCALING_BICUBIC: case SCALING_SPLINE16: case SCALING_SPLINE36: @@ -147,7 +161,7 @@ struct MAPNIK_DECL raster_symbolizer : public symbolizer_base private: std::string mode_; - std::string scaling_; + scaling_method_e scaling_; float opacity_; raster_colorizer_ptr colorizer_; double filter_factor_; diff --git a/include/mapnik/rule.hpp b/include/mapnik/rule.hpp index c073de1ef..6acb43cc9 100644 --- a/include/mapnik/rule.hpp +++ b/include/mapnik/rule.hpp @@ -200,6 +200,7 @@ private: template void copy_text_ptr(T & sym) const { + boost::ignore_unused_variable_warning(sym); MAPNIK_LOG_WARN(rule) << "rule: deep copying TextSymbolizers is broken!"; } diff --git a/include/mapnik/svg/svg_converter.hpp b/include/mapnik/svg/svg_converter.hpp index b2878544e..7e61a09ff 100644 --- a/include/mapnik/svg/svg_converter.hpp +++ b/include/mapnik/svg/svg_converter.hpp @@ -193,7 +193,7 @@ public: } // Attribute setting functions. - void fill(const agg::rgba8& f) + void fill(agg::rgba8 const& f) { path_attributes& attr = cur_attr(); double a = attr.fill_color.opacity(); @@ -202,19 +202,19 @@ public: attr.fill_flag = true; } - void add_fill_gradient(mapnik::gradient& grad) + void add_fill_gradient(mapnik::gradient const& grad) { path_attributes& attr = cur_attr(); attr.fill_gradient = grad; } - void add_stroke_gradient(mapnik::gradient& grad) + void add_stroke_gradient(mapnik::gradient const& grad) { path_attributes& attr = cur_attr(); attr.stroke_gradient = grad; } - void stroke(const agg::rgba8& s) + void stroke(agg::rgba8 const& s) { path_attributes& attr = cur_attr(); double a = attr.stroke_color.opacity(); @@ -264,16 +264,17 @@ public: void fill_opacity(double op) { - cur_attr().fill_color.opacity(op); + cur_attr().fill_opacity = op; } void stroke_opacity(double op) { - cur_attr().stroke_color.opacity(op); + cur_attr().stroke_opacity = op; } void opacity(double op) { - cur_attr().opacity = op; + cur_attr().stroke_opacity = op; + cur_attr().fill_opacity = op; } void line_join(agg::line_join_e join) diff --git a/include/mapnik/svg/svg_parser.hpp b/include/mapnik/svg/svg_parser.hpp index a3da60fe0..96559b6dc 100644 --- a/include/mapnik/svg/svg_parser.hpp +++ b/include/mapnik/svg/svg_parser.hpp @@ -44,7 +44,9 @@ namespace mapnik { namespace svg { explicit svg_parser(svg_converter_type & path); ~svg_parser(); void parse(std::string const& filename); + void parse_from_string(std::string const& svg); private: + bool parse_reader(xmlTextReaderPtr reader); void process_node(xmlTextReaderPtr reader); void start_element(xmlTextReaderPtr reader); void end_element(xmlTextReaderPtr reader); diff --git a/include/mapnik/svg/svg_path_adapter.hpp b/include/mapnik/svg/svg_path_adapter.hpp index 8dfc6fe7c..edf24f27b 100644 --- a/include/mapnik/svg/svg_path_adapter.hpp +++ b/include/mapnik/svg/svg_path_adapter.hpp @@ -47,9 +47,9 @@ public: typedef path_adapter self_type; //-------------------------------------------------------------------- - path_adapter(VertexContainer & vertices) : m_vertices(vertices), m_iterator(0) {} - //void remove_all() { m_vertices.remove_all(); m_iterator = 0; } - //void free_all() { m_vertices.free_all(); m_iterator = 0; } + path_adapter(VertexContainer & vertices) : vertices_(vertices), iterator_(0) {} + //void remove_all() { vertices_.remove_all(); iterator_ = 0; } + //void free_all() { vertices_.free_all(); iterator_ = 0; } // Make path functions //-------------------------------------------------------------------- @@ -109,8 +109,8 @@ public: // Accessors //-------------------------------------------------------------------- - const container_type& vertices() const { return m_vertices; } - container_type& vertices() { return m_vertices; } + const container_type& vertices() const { return vertices_; } + container_type& vertices() { return vertices_; } unsigned total_vertices() const; @@ -160,7 +160,7 @@ public: vs.rewind(path_id); while(!is_stop(cmd = vs.vertex(&x, &y))) { - m_vertices.add_vertex(x, y, cmd); + vertices_.add_vertex(x, y, cmd); } } @@ -185,7 +185,7 @@ public: if(calc_distance(x, y, x0, y0) > vertex_dist_epsilon) { if(is_move_to(cmd)) cmd = path_cmd_line_to; - m_vertices.add_vertex(x, y, cmd); + vertices_.add_vertex(x, y, cmd); } } else @@ -198,12 +198,12 @@ public: { if(is_move_to(cmd)) cmd = path_cmd_line_to; } - m_vertices.add_vertex(x, y, cmd); + vertices_.add_vertex(x, y, cmd); } } while(!is_stop(cmd = vs.vertex(&x, &y))) { - m_vertices.add_vertex(x, y, is_move_to(cmd) ? + vertices_.add_vertex(x, y, is_move_to(cmd) ? unsigned(path_cmd_line_to) : cmd); } @@ -218,16 +218,16 @@ public: template void transform(const Trans& trans, unsigned path_id=0) { - unsigned num_ver = m_vertices.total_vertices(); + unsigned num_ver = vertices_.total_vertices(); for(; path_id < num_ver; path_id++) { double x, y; - unsigned cmd = m_vertices.vertex(path_id, &x, &y); + unsigned cmd = vertices_.vertex(path_id, &x, &y); if(is_stop(cmd)) break; if(is_vertex(cmd)) { trans.transform(&x, &y); - m_vertices.modify_vertex(path_id, x, y); + vertices_.modify_vertex(path_id, x, y); } } } @@ -237,14 +237,14 @@ public: void transform_all_paths(const Trans& trans) { unsigned idx; - unsigned num_ver = m_vertices.total_vertices(); + unsigned num_ver = vertices_.total_vertices(); for(idx = 0; idx < num_ver; idx++) { double x, y; - if(is_vertex(m_vertices.vertex(idx, &x, &y))) + if(is_vertex(vertices_.vertex(idx, &x, &y))) { trans.transform(&x, &y); - m_vertices.modify_vertex(idx, x, y); + vertices_.modify_vertex(idx, x, y); } } } @@ -255,19 +255,21 @@ private: unsigned perceive_polygon_orientation(unsigned start, unsigned end); void invert_polygon(unsigned start, unsigned end); - VertexContainer & m_vertices; - unsigned m_iterator; + VertexContainer & vertices_; + unsigned iterator_; + double start_x_; + double start_y_; }; //------------------------------------------------------------------------ template unsigned path_adapter::start_new_path() { - if(!is_stop(m_vertices.last_command())) + if(!is_stop(vertices_.last_command())) { - m_vertices.add_vertex(0.0, 0.0, path_cmd_stop); + vertices_.add_vertex(0.0, 0.0, path_cmd_stop); } - return m_vertices.total_vertices(); + return vertices_.total_vertices(); } @@ -275,17 +277,12 @@ unsigned path_adapter::start_new_path() template inline void path_adapter::rel_to_abs(double* x, double* y) const { - if(m_vertices.total_vertices()) + if(vertices_.total_vertices()) { double x2; double y2; - if(is_vertex(m_vertices.last_vertex(&x2, &y2))) - { - *x += x2; - *y += y2; - } - else if (!is_stop(m_vertices.last_command()) && - is_vertex(m_vertices.prev_vertex(&x2, &y2))) + if(is_vertex(vertices_.last_vertex(&x2, &y2)) + || !is_stop(vertices_.last_command())) { *x += x2; *y += y2; @@ -297,7 +294,9 @@ inline void path_adapter::rel_to_abs(double* x, double* y) const template inline void path_adapter::move_to(double x, double y) { - m_vertices.add_vertex(x, y, path_cmd_move_to); + start_x_ = x; + start_y_ = y; + vertices_.add_vertex(x, y, path_cmd_move_to); } //------------------------------------------------------------------------ @@ -305,14 +304,14 @@ template inline void path_adapter::move_rel(double dx, double dy) { rel_to_abs(&dx, &dy); - m_vertices.add_vertex(dx, dy, path_cmd_move_to); + vertices_.add_vertex(dx, dy, path_cmd_move_to); } //------------------------------------------------------------------------ template inline void path_adapter::line_to(double x, double y) { - m_vertices.add_vertex(x, y, path_cmd_line_to); + vertices_.add_vertex(x, y, path_cmd_line_to); } //------------------------------------------------------------------------ @@ -320,14 +319,14 @@ template inline void path_adapter::line_rel(double dx, double dy) { rel_to_abs(&dx, &dy); - m_vertices.add_vertex(dx, dy, path_cmd_line_to); + vertices_.add_vertex(dx, dy, path_cmd_line_to); } //------------------------------------------------------------------------ template inline void path_adapter::hline_to(double x) { - m_vertices.add_vertex(x, last_y(), path_cmd_line_to); + vertices_.add_vertex(x, last_y(), path_cmd_line_to); } //------------------------------------------------------------------------ @@ -336,14 +335,14 @@ inline void path_adapter::hline_rel(double dx) { double dy = 0; rel_to_abs(&dx, &dy); - m_vertices.add_vertex(dx, dy, path_cmd_line_to); + vertices_.add_vertex(dx, dy, path_cmd_line_to); } //------------------------------------------------------------------------ template inline void path_adapter::vline_to(double y) { - m_vertices.add_vertex(last_x(), y, path_cmd_line_to); + vertices_.add_vertex(last_x(), y, path_cmd_line_to); } //------------------------------------------------------------------------ @@ -352,7 +351,7 @@ inline void path_adapter::vline_rel(double dy) { double dx = 0; rel_to_abs(&dx, &dy); - m_vertices.add_vertex(dx, dy, path_cmd_line_to); + vertices_.add_vertex(dx, dy, path_cmd_line_to); } //------------------------------------------------------------------------ @@ -363,12 +362,12 @@ void path_adapter::arc_to(double rx, double ry, bool sweep_flag, double x, double y) { - if(m_vertices.total_vertices() && is_vertex(m_vertices.last_command())) + if(vertices_.total_vertices() && is_vertex(vertices_.last_command())) { const double epsilon = 1e-30; double x0 = 0.0; double y0 = 0.0; - m_vertices.last_vertex(&x0, &y0); + vertices_.last_vertex(&x0, &y0); rx = fabs(rx); ry = fabs(ry); @@ -420,8 +419,8 @@ template void path_adapter::curve3(double x_ctrl, double y_ctrl, double x_to, double y_to) { - m_vertices.add_vertex(x_ctrl, y_ctrl, path_cmd_curve3); - m_vertices.add_vertex(x_to, y_to, path_cmd_curve3); + vertices_.add_vertex(x_ctrl, y_ctrl, path_cmd_curve3); + vertices_.add_vertex(x_to, y_to, path_cmd_curve3); } //------------------------------------------------------------------------ @@ -431,8 +430,8 @@ void path_adapter::curve3_rel(double dx_ctrl, double dy_ctrl, { rel_to_abs(&dx_ctrl, &dy_ctrl); rel_to_abs(&dx_to, &dy_to); - m_vertices.add_vertex(dx_ctrl, dy_ctrl, path_cmd_curve3); - m_vertices.add_vertex(dx_to, dy_to, path_cmd_curve3); + vertices_.add_vertex(dx_ctrl, dy_ctrl, path_cmd_curve3); + vertices_.add_vertex(dx_to, dy_to, path_cmd_curve3); } //------------------------------------------------------------------------ @@ -441,11 +440,11 @@ void path_adapter::curve3(double x_to, double y_to) { double x0; double y0; - if(is_vertex(m_vertices.last_vertex(&x0, &y0))) + if(is_vertex(vertices_.last_vertex(&x0, &y0))) { double x_ctrl; double y_ctrl; - unsigned cmd = m_vertices.prev_vertex(&x_ctrl, &y_ctrl); + unsigned cmd = vertices_.prev_vertex(&x_ctrl, &y_ctrl); if(is_curve(cmd)) { x_ctrl = x0 + x0 - x_ctrl; @@ -474,9 +473,9 @@ void path_adapter::curve4(double x_ctrl1, double y_ctrl1, double x_ctrl2, double y_ctrl2, double x_to, double y_to) { - m_vertices.add_vertex(x_ctrl1, y_ctrl1, path_cmd_curve4); - m_vertices.add_vertex(x_ctrl2, y_ctrl2, path_cmd_curve4); - m_vertices.add_vertex(x_to, y_to, path_cmd_curve4); + vertices_.add_vertex(x_ctrl1, y_ctrl1, path_cmd_curve4); + vertices_.add_vertex(x_ctrl2, y_ctrl2, path_cmd_curve4); + vertices_.add_vertex(x_to, y_to, path_cmd_curve4); } //------------------------------------------------------------------------ @@ -488,9 +487,9 @@ void path_adapter::curve4_rel(double dx_ctrl1, double dy_ctrl1, rel_to_abs(&dx_ctrl1, &dy_ctrl1); rel_to_abs(&dx_ctrl2, &dy_ctrl2); rel_to_abs(&dx_to, &dy_to); - m_vertices.add_vertex(dx_ctrl1, dy_ctrl1, path_cmd_curve4); - m_vertices.add_vertex(dx_ctrl2, dy_ctrl2, path_cmd_curve4); - m_vertices.add_vertex(dx_to, dy_to, path_cmd_curve4); + vertices_.add_vertex(dx_ctrl1, dy_ctrl1, path_cmd_curve4); + vertices_.add_vertex(dx_ctrl2, dy_ctrl2, path_cmd_curve4); + vertices_.add_vertex(dx_to, dy_to, path_cmd_curve4); } //------------------------------------------------------------------------ @@ -533,9 +532,9 @@ void path_adapter::curve4_rel(double dx_ctrl2, double dy_ctrl2, template inline void path_adapter::end_poly(unsigned flags) { - if(is_vertex(m_vertices.last_command())) + if(is_vertex(vertices_.last_command())) { - m_vertices.add_vertex(0.0, 0.0, path_cmd_end_poly | flags); + vertices_.add_vertex(start_x_, start_y_, path_cmd_end_poly | flags); } } @@ -550,85 +549,85 @@ inline void path_adapter::close_polygon(unsigned flags) template inline unsigned path_adapter::total_vertices() const { - return m_vertices.total_vertices(); + return vertices_.total_vertices(); } //------------------------------------------------------------------------ template inline unsigned path_adapter::last_vertex(double* x, double* y) const { - return m_vertices.last_vertex(x, y); + return vertices_.last_vertex(x, y); } //------------------------------------------------------------------------ template inline unsigned path_adapter::prev_vertex(double* x, double* y) const { - return m_vertices.prev_vertex(x, y); + return vertices_.prev_vertex(x, y); } //------------------------------------------------------------------------ template inline double path_adapter::last_x() const { - return m_vertices.last_x(); + return vertices_.last_x(); } //------------------------------------------------------------------------ template inline double path_adapter::last_y() const { - return m_vertices.last_y(); + return vertices_.last_y(); } //------------------------------------------------------------------------ template inline unsigned path_adapter::vertex(unsigned idx, double* x, double* y) const { - return m_vertices.vertex(idx, x, y); + return vertices_.vertex(idx, x, y); } //------------------------------------------------------------------------ template inline unsigned path_adapter::command(unsigned idx) const { - return m_vertices.command(idx); + return vertices_.command(idx); } //------------------------------------------------------------------------ template void path_adapter::modify_vertex(unsigned idx, double x, double y) { - m_vertices.modify_vertex(idx, x, y); + vertices_.modify_vertex(idx, x, y); } //------------------------------------------------------------------------ template void path_adapter::modify_vertex(unsigned idx, double x, double y, unsigned cmd) { - m_vertices.modify_vertex(idx, x, y, cmd); + vertices_.modify_vertex(idx, x, y, cmd); } //------------------------------------------------------------------------ template void path_adapter::modify_command(unsigned idx, unsigned cmd) { - m_vertices.modify_command(idx, cmd); + vertices_.modify_command(idx, cmd); } //------------------------------------------------------------------------ template inline void path_adapter::rewind(unsigned path_id) { - m_iterator = path_id; + iterator_ = path_id; } //------------------------------------------------------------------------ template inline unsigned path_adapter::vertex(double* x, double* y) { - if(m_iterator >= m_vertices.total_vertices()) return path_cmd_stop; - return m_vertices.vertex(m_iterator++, x, y); + if(iterator_ >= vertices_.total_vertices()) return path_cmd_stop; + return vertices_.vertex(iterator_++, x, y); } //------------------------------------------------------------------------ @@ -644,8 +643,8 @@ unsigned path_adapter::perceive_polygon_orientation(unsigned start, for(i = 0; i < np; i++) { double x1, y1, x2, y2; - m_vertices.vertex(start + i, &x1, &y1); - m_vertices.vertex(start + (i + 1) % np, &x2, &y2); + vertices_.vertex(start + i, &x1, &y1); + vertices_.vertex(start + (i + 1) % np, &x2, &y2); area += x1 * y2 - y1 * x2; } return (area < 0.0) ? path_flags_cw : path_flags_ccw; @@ -656,23 +655,23 @@ template void path_adapter::invert_polygon(unsigned start, unsigned end) { unsigned i; - unsigned tmp_cmd = m_vertices.command(start); + unsigned tmp_cmd = vertices_.command(start); --end; // Make "end" inclusive // Shift all commands to one position for(i = start; i < end; i++) { - m_vertices.modify_command(i, m_vertices.command(i + 1)); + vertices_.modify_command(i, vertices_.command(i + 1)); } // Assign starting command to the ending command - m_vertices.modify_command(end, tmp_cmd); + vertices_.modify_command(end, tmp_cmd); // Reverse the polygon while(end > start) { - m_vertices.swap_vertices(start++, end--); + vertices_.swap_vertices(start++, end--); } } @@ -681,18 +680,18 @@ template void path_adapter::invert_polygon(unsigned start) { // Skip all non-vertices at the beginning - while(start < m_vertices.total_vertices() && - !is_vertex(m_vertices.command(start))) ++start; + while(start < vertices_.total_vertices() && + !is_vertex(vertices_.command(start))) ++start; // Skip all insignificant move_to - while(start+1 < m_vertices.total_vertices() && - is_move_to(m_vertices.command(start)) && - is_move_to(m_vertices.command(start+1))) ++start; + while(start+1 < vertices_.total_vertices() && + is_move_to(vertices_.command(start)) && + is_move_to(vertices_.command(start+1))) ++start; // Find the last vertex unsigned end = start + 1; - while(end < m_vertices.total_vertices() && - !is_next_poly(m_vertices.command(end))) ++end; + while(end < vertices_.total_vertices() && + !is_next_poly(vertices_.command(end))) ++end; invert_polygon(start, end); } @@ -705,18 +704,18 @@ unsigned path_adapter::arrange_polygon_orientation(unsigned start, if(orientation == path_flags_none) return start; // Skip all non-vertices at the beginning - while(start < m_vertices.total_vertices() && - !is_vertex(m_vertices.command(start))) ++start; + while(start < vertices_.total_vertices() && + !is_vertex(vertices_.command(start))) ++start; // Skip all insignificant move_to - while(start+1 < m_vertices.total_vertices() && - is_move_to(m_vertices.command(start)) && - is_move_to(m_vertices.command(start+1))) ++start; + while(start+1 < vertices_.total_vertices() && + is_move_to(vertices_.command(start)) && + is_move_to(vertices_.command(start+1))) ++start; // Find the last vertex unsigned end = start + 1; - while(end < m_vertices.total_vertices() && - !is_next_poly(m_vertices.command(end))) ++end; + while(end < vertices_.total_vertices() && + !is_next_poly(vertices_.command(end))) ++end; if(end - start > 2) { @@ -725,10 +724,10 @@ unsigned path_adapter::arrange_polygon_orientation(unsigned start, // Invert polygon, set orientation flag, and skip all end_poly invert_polygon(start, end); unsigned cmd; - while(end < m_vertices.total_vertices() && - is_end_poly(cmd = m_vertices.command(end))) + while(end < vertices_.total_vertices() && + is_end_poly(cmd = vertices_.command(end))) { - m_vertices.modify_command(end++, set_orientation(cmd, orientation)); + vertices_.modify_command(end++, set_orientation(cmd, orientation)); } } } @@ -742,10 +741,10 @@ unsigned path_adapter::arrange_orientations(unsigned start, { if(orientation != path_flags_none) { - while(start < m_vertices.total_vertices()) + while(start < vertices_.total_vertices()) { start = arrange_polygon_orientation(start, orientation); - if(is_stop(m_vertices.command(start))) + if(is_stop(vertices_.command(start))) { ++start; break; @@ -762,7 +761,7 @@ void path_adapter::arrange_orientations_all_paths(path_flags_e orientation) if(orientation != path_flags_none) { unsigned start = 0; - while(start < m_vertices.total_vertices()) + while(start < vertices_.total_vertices()) { start = arrange_orientations(start, orientation); } @@ -775,12 +774,12 @@ void path_adapter::flip_x(double x1, double x2) { unsigned i; double x, y; - for(i = 0; i < m_vertices.total_vertices(); i++) + for(i = 0; i < vertices_.total_vertices(); i++) { - unsigned cmd = m_vertices.vertex(i, &x, &y); + unsigned cmd = vertices_.vertex(i, &x, &y); if(is_vertex(cmd)) { - m_vertices.modify_vertex(i, x2 - x + x1, y); + vertices_.modify_vertex(i, x2 - x + x1, y); } } } @@ -791,12 +790,12 @@ void path_adapter::flip_y(double y1, double y2) { unsigned i; double x, y; - for(i = 0; i < m_vertices.total_vertices(); i++) + for(i = 0; i < vertices_.total_vertices(); i++) { - unsigned cmd = m_vertices.vertex(i, &x, &y); + unsigned cmd = vertices_.vertex(i, &x, &y); if(is_vertex(cmd)) { - m_vertices.modify_vertex(i, x, y2 - y + y1); + vertices_.modify_vertex(i, x, y2 - y + y1); } } } @@ -805,17 +804,17 @@ void path_adapter::flip_y(double y1, double y2) template void path_adapter::translate(double dx, double dy, unsigned path_id) { - unsigned num_ver = m_vertices.total_vertices(); + unsigned num_ver = vertices_.total_vertices(); for(; path_id < num_ver; path_id++) { double x, y; - unsigned cmd = m_vertices.vertex(path_id, &x, &y); + unsigned cmd = vertices_.vertex(path_id, &x, &y); if(is_stop(cmd)) break; if(is_vertex(cmd)) { x += dx; y += dy; - m_vertices.modify_vertex(path_id, x, y); + vertices_.modify_vertex(path_id, x, y); } } } @@ -825,15 +824,15 @@ template void path_adapter::translate_all_paths(double dx, double dy) { unsigned idx; - unsigned num_ver = m_vertices.total_vertices(); + unsigned num_ver = vertices_.total_vertices(); for(idx = 0; idx < num_ver; idx++) { double x, y; - if(is_vertex(m_vertices.vertex(idx, &x, &y))) + if(is_vertex(vertices_.vertex(idx, &x, &y))) { x += dx; y += dy; - m_vertices.modify_vertex(idx, x, y); + vertices_.modify_vertex(idx, x, y); } } } @@ -847,25 +846,25 @@ public: typedef typename vertex_type::value_type value_type; explicit vertex_stl_adapter(Container & vertices) - : m_vertices(vertices) {} + : vertices_(vertices) {} void add_vertex(double x, double y, unsigned cmd) { - m_vertices.push_back(vertex_type(value_type(x), + vertices_.push_back(vertex_type(value_type(x), value_type(y), int8u(cmd))); } void modify_vertex(unsigned idx, double x, double y) { - vertex_type& v = m_vertices[idx]; + vertex_type& v = vertices_[idx]; v.x = value_type(x); v.y = value_type(y); } void modify_vertex(unsigned idx, double x, double y, unsigned cmd) { - vertex_type& v = m_vertices[idx]; + vertex_type& v = vertices_[idx]; v.x = value_type(x); v.y = value_type(y); v.cmd = int8u(cmd); @@ -873,61 +872,61 @@ public: void modify_command(unsigned idx, unsigned cmd) { - m_vertices[idx].cmd = int8u(cmd); + vertices_[idx].cmd = int8u(cmd); } void swap_vertices(unsigned v1, unsigned v2) { - vertex_type t = m_vertices[v1]; - m_vertices[v1] = m_vertices[v2]; - m_vertices[v2] = t; + vertex_type t = vertices_[v1]; + vertices_[v1] = vertices_[v2]; + vertices_[v2] = t; } unsigned last_command() const { - return m_vertices.size() ? - m_vertices[m_vertices.size() - 1].cmd : + return vertices_.size() ? + vertices_[vertices_.size() - 1].cmd : (unsigned)path_cmd_stop; } unsigned last_vertex(double* x, double* y) const { - if(m_vertices.size() == 0) + if(vertices_.size() == 0) { *x = *y = 0.0; return path_cmd_stop; } - return vertex(m_vertices.size() - 1, x, y); + return vertex(vertices_.size() - 1, x, y); } unsigned prev_vertex(double* x, double* y) const { - if(m_vertices.size() < 2) + if(vertices_.size() < 2) { *x = *y = 0.0; return path_cmd_stop; } - return vertex(m_vertices.size() - 2, x, y); + return vertex(vertices_.size() - 2, x, y); } double last_x() const { - return m_vertices.size() ? m_vertices[m_vertices.size() - 1].x : 0.0; + return vertices_.size() ? vertices_[vertices_.size() - 1].x : 0.0; } double last_y() const { - return m_vertices.size() ? m_vertices[m_vertices.size() - 1].y : 0.0; + return vertices_.size() ? vertices_[vertices_.size() - 1].y : 0.0; } unsigned total_vertices() const { - return m_vertices.size(); + return vertices_.size(); } unsigned vertex(unsigned idx, double* x, double* y) const { - const vertex_type& v = m_vertices[idx]; + const vertex_type& v = vertices_[idx]; *x = v.x; *y = v.y; return v.cmd; @@ -935,11 +934,11 @@ public: unsigned command(unsigned idx) const { - return m_vertices[idx].cmd; + return vertices_[idx].cmd; } private: - Container & m_vertices; + Container & vertices_; }; diff --git a/include/mapnik/svg/svg_path_attributes.hpp b/include/mapnik/svg/svg_path_attributes.hpp index 1c8a61c36..db14ccc28 100644 --- a/include/mapnik/svg/svg_path_attributes.hpp +++ b/include/mapnik/svg/svg_path_attributes.hpp @@ -39,8 +39,9 @@ struct path_attributes { unsigned index; agg::rgba8 fill_color; + double fill_opacity; agg::rgba8 stroke_color; - double opacity; + double stroke_opacity; bool fill_flag; bool stroke_flag; bool even_odd_flag; @@ -58,8 +59,9 @@ struct path_attributes path_attributes() : index(0), fill_color(agg::rgba(0,0,0)), + fill_opacity(1.0), stroke_color(agg::rgba(0,0,0)), - opacity(1.0), + stroke_opacity(1.0), fill_flag(true), stroke_flag(false), even_odd_flag(false), @@ -79,8 +81,9 @@ struct path_attributes path_attributes(const path_attributes& attr) : index(attr.index), fill_color(attr.fill_color), + fill_opacity(attr.fill_opacity), stroke_color(attr.stroke_color), - opacity(attr.opacity), + stroke_opacity(attr.stroke_opacity), fill_flag(attr.fill_flag), stroke_flag(attr.stroke_flag), even_odd_flag(attr.even_odd_flag), @@ -99,8 +102,9 @@ struct path_attributes path_attributes(path_attributes const& attr, unsigned idx) : index(idx), fill_color(attr.fill_color), + fill_opacity(attr.fill_opacity), stroke_color(attr.stroke_color), - opacity(attr.opacity), + stroke_opacity(attr.stroke_opacity), fill_flag(attr.fill_flag), stroke_flag(attr.stroke_flag), even_odd_flag(attr.even_odd_flag), diff --git a/include/mapnik/svg/svg_path_commands.hpp b/include/mapnik/svg/svg_path_commands.hpp index 3b1e09dee..e45b5b1c0 100644 --- a/include/mapnik/svg/svg_path_commands.hpp +++ b/include/mapnik/svg/svg_path_commands.hpp @@ -35,232 +35,232 @@ namespace mapnik { namespace svg { - using namespace boost::fusion; +using namespace boost::fusion; - inline double deg2rad(double deg) +inline double deg2rad(double deg) +{ + return (M_PI * deg)/180.0; +} + +template +struct move_to +{ + template + struct result { - return (M_PI * deg)/180.0; + typedef void type; + }; + + explicit move_to(PathType & path) + : path_(path) {} + + template + void operator() (T0 v, T1 rel) const + { + path_.move_to(at_c<0>(v),at_c<1>(v),rel); // impl } - template - struct move_to + PathType & path_; +}; + +template +struct hline_to +{ + template + struct result { - template - struct result - { - typedef void type; - }; - - explicit move_to(PathType & path) - : path_(path) {} - - template - void operator() (T0 v, T1 rel) const - { - path_.move_to(at_c<0>(v),at_c<1>(v),rel); // impl - } - - PathType & path_; + typedef void type; }; - template - struct hline_to + explicit hline_to(PathType & path) + : path_(path) {} + + template + void operator() (T0 const& x, T1 rel) const { - template - struct result - { - typedef void type; - }; + path_.hline_to(x,rel); + } - explicit hline_to(PathType & path) - : path_(path) {} + PathType & path_; +}; - template - void operator() (T0 const& x, T1 rel) const - { - path_.hline_to(x,rel); - } - PathType & path_; +template +struct vline_to +{ + template + struct result + { + typedef void type; }; + explicit vline_to(PathType & path) + : path_(path) {} - template - struct vline_to + template + void operator() (T0 const& y, T1 rel) const { - template - struct result - { - typedef void type; - }; + path_.vline_to(y,rel); + } - explicit vline_to(PathType & path) - : path_(path) {} + PathType & path_; +}; - template - void operator() (T0 const& y, T1 rel) const - { - path_.vline_to(y,rel); - } - - PathType & path_; +template +struct line_to +{ + template + struct result + { + typedef void type; }; - template - struct line_to + explicit line_to(PathType & path) + : path_(path) {} + + template + void operator() (T0 const& v, T1 rel) const { - template - struct result - { - typedef void type; - }; + path_.line_to(at_c<0>(v),at_c<1>(v),rel); // impl + } - explicit line_to(PathType & path) - : path_(path) {} + PathType & path_; +}; - template - void operator() (T0 const& v, T1 rel) const - { - path_.line_to(at_c<0>(v),at_c<1>(v),rel); // impl - } - PathType & path_; +template +struct curve4 +{ + template + struct result + { + typedef void type; }; + explicit curve4(PathType & path) + : path_(path) {} - template - struct curve4 + template + void operator() (T0 const& v0, T1 const& v1, T2 const& v2, T3 rel) const { - template - struct result - { - typedef void type; - }; + path_.curve4(at_c<0>(v0),at_c<1>(v0), + at_c<0>(v1),at_c<1>(v1), + at_c<0>(v2),at_c<1>(v2), + rel); // impl + } - explicit curve4(PathType & path) - : path_(path) {} + PathType & path_; +}; - template - void operator() (T0 const& v0, T1 const& v1, T2 const& v2, T3 rel) const - { - path_.curve4(at_c<0>(v0),at_c<1>(v0), - at_c<0>(v1),at_c<1>(v1), - at_c<0>(v2),at_c<1>(v2), - rel); // impl - } - PathType & path_; +template +struct curve4_smooth +{ + template + struct result + { + typedef void type; }; + explicit curve4_smooth(PathType & path) + : path_(path) {} - template - struct curve4_smooth + template + void operator() (T0 const& v0, T1 const& v1, T2 rel) const { - template - struct result - { - typedef void type; - }; + path_.curve4(at_c<0>(v0),at_c<1>(v0), + at_c<0>(v1),at_c<1>(v1), + rel); // impl + } + PathType & path_; +}; - explicit curve4_smooth(PathType & path) - : path_(path) {} - - template - void operator() (T0 const& v0, T1 const& v1, T2 rel) const - { - path_.curve4(at_c<0>(v0),at_c<1>(v0), - at_c<0>(v1),at_c<1>(v1), - rel); // impl - } - PathType & path_; +template +struct curve3 +{ + template + struct result + { + typedef void type; }; - template - struct curve3 + explicit curve3(PathType & path) + : path_(path) {} + + template + void operator() (T0 const& v0, T1 const& v1, T2 rel) const { - template - struct result - { - typedef void type; - }; + path_.curve3(at_c<0>(v0),at_c<1>(v0), + at_c<0>(v1),at_c<1>(v1), + rel); // impl + } - explicit curve3(PathType & path) - : path_(path) {} + PathType & path_; +}; - template - void operator() (T0 const& v0, T1 const& v1, T2 rel) const - { - path_.curve3(at_c<0>(v0),at_c<1>(v0), - at_c<0>(v1),at_c<1>(v1), - rel); // impl - } - - PathType & path_; +template +struct curve3_smooth +{ + template + struct result + { + typedef void type; }; - template - struct curve3_smooth + explicit curve3_smooth(PathType & path) + : path_(path) {} + + template + void operator() (T0 const& v0, T1 rel) const { - template - struct result - { - typedef void type; - }; + path_.curve3(at_c<0>(v0),at_c<1>(v0), + rel); // impl + } - explicit curve3_smooth(PathType & path) - : path_(path) {} + PathType & path_; +}; - template - void operator() (T0 const& v0, T1 rel) const - { - path_.curve3(at_c<0>(v0),at_c<1>(v0), - rel); // impl - } - - PathType & path_; +template +struct arc_to +{ + template + struct result + { + typedef void type; }; - template - struct arc_to + explicit arc_to(PathType & path) + : path_(path) {} + + template + void operator() (T0 const& rv, T1 const& angle, T2 large_arc_flag, T3 sweep_flag, T4 const& v, T5 rel) const { - template - struct result - { - typedef void type; - }; + path_.arc_to(at_c<0>(rv),at_c<1>(rv), + deg2rad(angle),large_arc_flag,sweep_flag, + at_c<0>(v),at_c<1>(v), + rel); + } - explicit arc_to(PathType & path) - : path_(path) {} + PathType & path_; +}; - template - void operator() (T0 const& rv, T1 const& angle, T2 large_arc_flag, T3 sweep_flag, T4 const& v, T5 rel) const - { - path_.arc_to(at_c<0>(rv),at_c<1>(rv), - deg2rad(angle),large_arc_flag,sweep_flag, - at_c<0>(v),at_c<1>(v), - rel); - } +template +struct close +{ + typedef void result_type; - PathType & path_; - }; + explicit close(PathType & path) + : path_(path) {} - template - struct close + void operator()() const { - typedef void result_type; + path_.close_subpath(); + } - explicit close(PathType & path) - : path_(path) {} + PathType & path_; +}; - void operator()() const - { - path_.close_subpath(); - } - - PathType & path_; - }; - - }} +}} #endif // MAPNIK_SVG_COMMANDS_HPP diff --git a/include/mapnik/svg/svg_renderer.hpp b/include/mapnik/svg/svg_renderer.hpp index 7538798ee..fad181e02 100644 --- a/include/mapnik/svg/svg_renderer.hpp +++ b/include/mapnik/svg/svg_renderer.hpp @@ -243,7 +243,7 @@ public: Renderer& ren, agg::trans_affine const& mtx, double opacity, - const box2d &symbol_bbox) + box2d const& symbol_bbox) { using namespace agg; @@ -292,13 +292,13 @@ public: if(attr.fill_gradient.get_gradient_type() != NO_GRADIENT) { - render_gradient(ras, sl, ren, attr.fill_gradient, transform, attr.opacity * opacity, symbol_bbox, path_bbox); + render_gradient(ras, sl, ren, attr.fill_gradient, transform, attr.fill_opacity * opacity, symbol_bbox, path_bbox); } else { ras.filling_rule(attr.even_odd_flag ? fill_even_odd : fill_non_zero); color = attr.fill_color; - color.opacity(color.opacity() * attr.opacity * opacity); + color.opacity(color.opacity() * attr.fill_opacity * opacity); ScanlineRenderer ren_s(ren); color.premultiply(); ren_s.color(color); @@ -328,13 +328,13 @@ public: if(attr.stroke_gradient.get_gradient_type() != NO_GRADIENT) { - render_gradient(ras, sl, ren, attr.stroke_gradient, transform, attr.opacity * opacity, symbol_bbox, path_bbox); + render_gradient(ras, sl, ren, attr.stroke_gradient, transform, attr.stroke_opacity * opacity, symbol_bbox, path_bbox); } else { ras.filling_rule(fill_non_zero); color = attr.stroke_color; - color.opacity(color.opacity() * attr.opacity * opacity); + color.opacity(color.opacity() * attr.stroke_opacity * opacity); ScanlineRenderer ren_s(ren); color.premultiply(); ren_s.color(color); diff --git a/include/mapnik/symbolizer_helpers.hpp b/include/mapnik/symbolizer_helpers.hpp index aafb8864b..bf1376071 100644 --- a/include/mapnik/symbolizer_helpers.hpp +++ b/include/mapnik/symbolizer_helpers.hpp @@ -85,10 +85,11 @@ public: bool next(); /** Get current placement. next() has to be called before! */ - placements_type & placements() const; + placements_type const& placements() const; protected: bool next_point_placement(); bool next_line_placement(); + bool next_line_placement_clipped(); bool next_placement(); void initialize_geometries(); void initialize_points(); diff --git a/include/mapnik/text_path.hpp b/include/mapnik/text_path.hpp index 90490d154..557519ed2 100644 --- a/include/mapnik/text_path.hpp +++ b/include/mapnik/text_path.hpp @@ -140,7 +140,7 @@ class text_path : boost::noncopyable ~character_node() {} - void vertex(char_info_ptr *c_, double *x_, double *y_, double *angle_) + void vertex(char_info_ptr *c_, double *x_, double *y_, double *angle_) const { *c_ = c; *x_ = pos.x; @@ -149,7 +149,7 @@ class text_path : boost::noncopyable } }; - int itr_; + mutable int itr_; public: typedef std::vector character_nodes_t; pixel_position center; @@ -172,13 +172,13 @@ public: } /** Return node. Always returns a new node. Has no way to report that there are no more nodes. */ - void vertex(char_info_ptr *c, double *x, double *y, double *angle) + void vertex(char_info_ptr *c, double *x, double *y, double *angle) const { nodes_[itr_++].vertex(c, x, y, angle); } /** Start again at first node. */ - void rewind() + void rewind() const { itr_ = 0; } diff --git a/include/mapnik/transform_expression.hpp b/include/mapnik/transform_expression.hpp index 069863470..53170f63f 100644 --- a/include/mapnik/transform_expression.hpp +++ b/include/mapnik/transform_expression.hpp @@ -115,7 +115,7 @@ namespace detail { // boost::spirit::traits::clear(T& val) [with T = boost::variant<...>] // attempts to assign to the variant's current value a default-constructed -// value ot the same type, which not only requires that each value-type is +// value of the same type, which not only requires that each value-type is // default-constructible, but also makes little sense with our variant of // transform nodes... diff --git a/include/mapnik/transform_expression_grammar.hpp b/include/mapnik/transform_expression_grammar.hpp index fe09f4e5c..4d4afae9f 100644 --- a/include/mapnik/transform_expression_grammar.hpp +++ b/include/mapnik/transform_expression_grammar.hpp @@ -39,65 +39,7 @@ namespace mapnik { struct transform_expression_grammar : qi::grammar { - explicit transform_expression_grammar(expression_grammar const& g) - : transform_expression_grammar::base_type(start) - { - using boost::phoenix::construct; - using qi::_a; using qi::_1; using qi::_4; - using qi::_b; using qi::_2; using qi::_5; - using qi::_c; using qi::_3; using qi::_6; - using qi::_val; - using qi::char_; - using qi::lit; - using qi::no_case; - using qi::no_skip; - - start = transform_ % no_skip[char_(", ")] ; - - transform_ = matrix | translate | scale | rotate | skewX | skewY ; - - matrix = no_case[lit("matrix")] - >> (lit('(') - >> expr >> -lit(',') - >> expr >> -lit(',') - >> expr >> -lit(',') - >> expr >> -lit(',') - >> expr >> -lit(',') - >> expr >> lit(')')) - [ _val = construct(_1,_2,_3,_4,_5,_6) ]; - - translate = no_case[lit("translate")] - >> (lit('(') - >> expr >> -lit(',') - >> -expr >> lit(')')) - [ _val = construct(_1,_2) ]; - - scale = no_case[lit("scale")] - >> (lit('(') - >> expr >> -lit(',') - >> -expr >> lit(')')) - [ _val = construct(_1,_2) ]; - - rotate = no_case[lit("rotate")] - >> lit('(') - >> expr[_a = _1] >> -lit(',') - >> -(expr [_b = _1] >> -lit(',') >> expr[_c = _1]) - >> lit(')') - [ _val = construct(_a,_b,_c) ]; - - skewX = no_case[lit("skewX")] - >> lit('(') - >> expr [ _val = construct(_1) ] - >> lit(')'); - - skewY = no_case[lit("skewY")] - >> lit('(') - >> expr [ _val = construct(_1) ] - >> lit(')'); - - expr = g.expr.alias(); - } - + explicit transform_expression_grammar(expression_grammar const& g); typedef qi::locals, boost::optional > rotate_locals; diff --git a/include/mapnik/util/geometry_svg_generator.hpp b/include/mapnik/util/geometry_svg_generator.hpp index 5b1a285bc..7dc8ef120 100644 --- a/include/mapnik/util/geometry_svg_generator.hpp +++ b/include/mapnik/util/geometry_svg_generator.hpp @@ -66,7 +66,7 @@ namespace mapnik { namespace util { geometry_type::value_type const operator() (geometry_type const& geom) const { geometry_type::value_type coord; - boost::get<0>(coord) = geom.get_vertex(0,&boost::get<1>(coord),&boost::get<2>(coord)); + boost::get<0>(coord) = geom.vertex(0,&boost::get<1>(coord),&boost::get<2>(coord)); return coord; } }; diff --git a/include/mapnik/util/geometry_to_wkb.hpp b/include/mapnik/util/geometry_to_wkb.hpp index 4f793bc0b..3b0159345 100644 --- a/include/mapnik/util/geometry_to_wkb.hpp +++ b/include/mapnik/util/geometry_to_wkb.hpp @@ -119,15 +119,16 @@ namespace mapnik { namespace util { wkb_buffer_ptr to_point_wkb( geometry_type const& g, wkbByteOrder byte_order) { - assert(g.num_points() == 1); + assert(g.size() == 1); std::size_t size = 1 + 4 + 8*2 ; // byteOrder + wkbType + Point wkb_buffer_ptr wkb = boost::make_shared(size); boost::interprocess::bufferstream ss(wkb->buffer(), wkb->size(), std::ios::out | std::ios::binary); ss.write(reinterpret_cast(&byte_order),1); int type = static_cast(mapnik::Point); write(ss,type,4,byte_order); - double x,y; - g.get_vertex(0,&x,&y); + double x(0); + double y(0); + g.vertex(0,&x,&y); write(ss,x,8,byte_order); write(ss,y,8,byte_order); assert(ss.good()); @@ -136,7 +137,7 @@ namespace mapnik { namespace util { wkb_buffer_ptr to_line_string_wkb( geometry_type const& g, wkbByteOrder byte_order) { - unsigned num_points = g.num_points(); + unsigned num_points = g.size(); assert(num_points > 1); std::size_t size = 1 + 4 + 4 + 8*2*num_points ; // byteOrder + wkbType + numPoints + Point*numPoints wkb_buffer_ptr wkb = boost::make_shared(size); @@ -145,10 +146,11 @@ namespace mapnik { namespace util { int type = static_cast(mapnik::LineString); write(ss,type,4,byte_order); write(ss,num_points,4,byte_order); - double x,y; + double x(0); + double y(0); for (unsigned i=0; i< num_points; ++i) { - g.get_vertex(i,&x,&y); + g.vertex(i,&x,&y); write(ss,x,8,byte_order); write(ss,y,8,byte_order); } @@ -158,18 +160,19 @@ namespace mapnik { namespace util { wkb_buffer_ptr to_polygon_wkb( geometry_type const& g, wkbByteOrder byte_order) { - unsigned num_points = g.num_points(); + unsigned num_points = g.size(); assert(num_points > 1); typedef std::pair point_type; typedef std::vector linear_ring; boost::ptr_vector rings; - double x,y; + double x(0); + double y(0); std::size_t size = 1 + 4 + 4 ; // byteOrder + wkbType + numRings for (unsigned i=0; i< num_points; ++i) { - unsigned command = g.get_vertex(i,&x,&y); + unsigned command = g.vertex(i,&x,&y); if (command == SEG_MOVETO) { rings.push_back(new linear_ring); // start new loop diff --git a/include/mapnik/util/geometry_wkt_generator.hpp b/include/mapnik/util/geometry_wkt_generator.hpp index 0318a050d..969b932d6 100644 --- a/include/mapnik/util/geometry_wkt_generator.hpp +++ b/include/mapnik/util/geometry_wkt_generator.hpp @@ -26,8 +26,6 @@ // mapnik #include #include -#include -#include // boost #include @@ -55,161 +53,88 @@ struct is_container namespace mapnik { namespace util { - namespace karma = boost::spirit::karma; - namespace phoenix = boost::phoenix; - - namespace { - - struct get_type - { - template - struct result { typedef int type; }; - - int operator() (geometry_type const& geom) const - { - return static_cast(geom.type()); - } - }; - - struct get_first - { - template - struct result { typedef geometry_type::value_type const type; }; - - geometry_type::value_type const operator() (geometry_type const& geom) const - { - geometry_type::value_type coord; - boost::get<0>(coord) = geom.get_vertex(0,&boost::get<1>(coord),&boost::get<2>(coord)); - return coord; - } - }; - - - struct multi_geometry_ - { - template - struct result { typedef bool type; }; - - bool operator() (geometry_container const& geom) const - { - return geom.size() > 1 ? true : false; - } - }; - - struct multi_geometry_type - { - template - struct result { typedef boost::tuple type; }; - - boost::tuple operator() (geometry_container const& geom) const - { - unsigned type = 0u; - bool collection = false; - - geometry_container::const_iterator itr = geom.begin(); - geometry_container::const_iterator end = geom.end(); - - for ( ; itr != end; ++itr) - { - if (type != 0 && itr->type() != type) - { - collection = true; - break; - } - type = itr->type(); - } - return boost::tuple(type, collection); - } - }; +namespace karma = boost::spirit::karma; +namespace phoenix = boost::phoenix; +namespace { +struct get_type +{ template - struct wkt_coordinate_policy : karma::real_policies - { - typedef boost::spirit::karma::real_policies base_type; - static int floatfield(T n) { return base_type::fmtflags::fixed; } - static unsigned precision(T n) { return 6 ;} - }; + struct result { typedef int type; }; + int operator() (geometry_type const& geom) const + { + return static_cast(geom.type()); } +}; - template - struct wkt_generator : - karma::grammar +struct get_first +{ + template + struct result { typedef geometry_type::value_type const type; }; + + 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)); + return coord; + } +}; - wkt_generator(bool single = false) - : wkt_generator::base_type(wkt) - { - using boost::spirit::karma::uint_; - using boost::spirit::karma::_val; - using boost::spirit::karma::_1; - using boost::spirit::karma::lit; - using boost::spirit::karma::_a; - using boost::spirit::karma::_r1; - using boost::spirit::karma::eps; - using boost::spirit::karma::string; - wkt = point | linestring | polygon - ; +struct multi_geometry_ +{ + template + struct result { typedef bool type; }; - point = &uint_(mapnik::Point)[_1 = _type(_val)] - << string[ phoenix::if_ (single) [_1 = "Point("] - .else_[_1 = "("]] - << point_coord [_1 = _first(_val)] << lit(')') - ; + bool operator() (geometry_container const& geom) const + { + return geom.size() > 1 ? true : false; + } +}; - linestring = &uint_(mapnik::LineString)[_1 = _type(_val)] - << string[ phoenix::if_ (single) [_1 = "LineString("] - .else_[_1 = "("]] - << coords - << lit(')') - ; +struct multi_geometry_type +{ + template + struct result { typedef boost::tuple type; }; - polygon = &uint_(mapnik::Polygon)[_1 = _type(_val)] - << string[ phoenix::if_ (single) [_1 = "Polygon("] - .else_[_1 = "("]] - << coords2 - << lit("))") - ; + boost::tuple operator() (geometry_container const& geom) const; +}; - point_coord = &uint_ << coord_type << lit(' ') << coord_type - ; - polygon_coord %= ( &uint_(mapnik::SEG_MOVETO) << eps[_r1 += 1] - << string[ if_ (_r1 > 1) [_1 = "),("] - .else_[_1 = "("] ] | &uint_ << ",") - << coord_type - << lit(' ') - << coord_type - ; +template +struct wkt_coordinate_policy : karma::real_policies +{ + typedef boost::spirit::karma::real_policies base_type; + static int floatfield(T n) { return base_type::fmtflags::fixed; } + static unsigned precision(T n) { return 6 ;} +}; - coords2 %= *polygon_coord(_a) - ; +} - coords = point_coord % lit(',') - ; +template +struct wkt_generator : + karma::grammar +{ + wkt_generator(bool single = false); + // rules + karma::rule wkt; + karma::rule point; + karma::rule linestring; + karma::rule polygon; - } - // rules - karma::rule wkt; - karma::rule point; - karma::rule linestring; - karma::rule polygon; - - karma::rule coords; - karma::rule, geometry_type const& ()> coords2; - karma::rule point_coord; - karma::rule polygon_coord; - - // phoenix functions - phoenix::function _type; - phoenix::function _first; - // - karma::real_generator > coord_type; - - }; + karma::rule coords; + karma::rule, geometry_type const& ()> coords2; + karma::rule point_coord; + karma::rule polygon_coord; + // phoenix functions + phoenix::function _type; + phoenix::function _first; + // + karma::real_generator > coord_type; +}; template @@ -217,38 +142,7 @@ struct wkt_multi_generator : karma::grammar >, geometry_container const& ()> { - wkt_multi_generator() - : wkt_multi_generator::base_type(wkt) - { - using boost::spirit::karma::lit; - using boost::spirit::karma::eps; - using boost::spirit::karma::_val; - using boost::spirit::karma::_1; - using boost::spirit::karma::_a; - - geometry_types.add - (mapnik::Point,"Point") - (mapnik::LineString,"LineString") - (mapnik::Polygon,"Polygon") - ; - - wkt = eps(phoenix::at_c<1>(_a))[_a = _multi_type(_val)] - << lit("GeometryCollection(") << geometry << lit(")") - | eps(is_multi(_val)) << lit("Multi") << geometry_types[_1 = phoenix::at_c<0>(_a)] - << "(" << multi_geometry << ")" - | geometry - ; - - geometry = -(single_geometry % lit(',')) - ; - - single_geometry = geometry_types[_1 = _type(_val)] << path - ; - - multi_geometry = -(path % lit(',')) - ; - - } + wkt_multi_generator(); // rules karma::rule >, geometry_container const& ()> wkt; karma::rule geometry; diff --git a/include/mapnik/value.hpp b/include/mapnik/value.hpp index 185539d3e..cfe807d7a 100644 --- a/include/mapnik/value.hpp +++ b/include/mapnik/value.hpp @@ -71,19 +71,39 @@ inline void to_utf8(UnicodeString const& input, std::string & target) struct value_null { template - value_null operator+ (T const& other) const { return *this; } + value_null operator+ (T const& other) const + { + boost::ignore_unused_variable_warning(other); + return *this; + } template - value_null operator- (T const& other) const { return *this; } + value_null operator- (T const& other) const + { + boost::ignore_unused_variable_warning(other); + return *this; + } template - value_null operator* (T const& other) const { return *this; } + value_null operator* (T const& other) const + { + boost::ignore_unused_variable_warning(other); + return *this; + } template - value_null operator/ (T const& other) const { return *this; } + value_null operator/ (T const& other) const + { + boost::ignore_unused_variable_warning(other); + return *this; + } template - value_null operator% (T const& other) const { return *this; } + value_null operator% (T const& other) const + { + boost::ignore_unused_variable_warning(other); + return *this; + } }; typedef boost::variant value_base; @@ -352,7 +372,7 @@ struct add : public boost::static_visitor { return lhs + rhs; } - + value_type operator() (UnicodeString const& lhs, value_null rhs) const { boost::ignore_unused_variable_warning(rhs); @@ -557,6 +577,11 @@ struct negate : public boost::static_visitor return val; } + value_type operator() (bool val) const + { + return val ? -1 : 0; + } + value_type operator() (UnicodeString const& ustr) const { UnicodeString inplace(ustr); diff --git a/include/mapnik/warp.hpp b/include/mapnik/warp.hpp index 035df63c0..f7e5ddcd9 100644 --- a/include/mapnik/warp.hpp +++ b/include/mapnik/warp.hpp @@ -26,16 +26,17 @@ // mapnik #include #include +#include namespace mapnik { -void reproject_raster(raster &target, raster const& source, - proj_transform const& prj_trans, - double offset_x, double offset_y, - unsigned mesh_size, - double filter_radius, - double scale_factor, - std::string scaling_method_name); +void reproject_and_scale_raster(raster & target, + raster const& source, + proj_transform const& prj_trans, + double offset_x, double offset_y, + unsigned mesh_size, + double filter_radius, + scaling_method_e scaling_method); } diff --git a/include/mapnik/wkb.hpp b/include/mapnik/wkb.hpp index a7284bb30..38fa2b259 100644 --- a/include/mapnik/wkb.hpp +++ b/include/mapnik/wkb.hpp @@ -55,7 +55,7 @@ class MAPNIK_DECL geometry_utils : private boost::noncopyable { public: - static void from_wkb (boost::ptr_vector& paths, + static bool from_wkb (boost::ptr_vector& paths, const char* wkb, unsigned size, wkbFormat format = wkbGeneric); diff --git a/plugins/input/csv/csv_datasource.cpp b/plugins/input/csv/csv_datasource.cpp index 3c5b4b439..b10729d3a 100644 --- a/plugins/input/csv/csv_datasource.cpp +++ b/plugins/input/csv/csv_datasource.cpp @@ -277,9 +277,9 @@ void csv_datasource::parse_csv(T& stream, bool has_wkt_field = false; bool has_lat_field = false; bool has_lon_field = false; - unsigned wkt_idx; - unsigned lat_idx; - unsigned lon_idx; + unsigned wkt_idx(0); + unsigned lat_idx(0); + unsigned lon_idx(0); if (!manual_headers_.empty()) { @@ -852,7 +852,7 @@ void csv_datasource::parse_csv(T& stream, } } -std::string csv_datasource::name() +const char * csv_datasource::name() { return "csv"; } diff --git a/plugins/input/csv/csv_datasource.hpp b/plugins/input/csv/csv_datasource.hpp index 86bcfd4f9..22a99a2b8 100644 --- a/plugins/input/csv/csv_datasource.hpp +++ b/plugins/input/csv/csv_datasource.hpp @@ -35,7 +35,7 @@ public: csv_datasource(mapnik::parameters const& params, bool bind=true); virtual ~csv_datasource (); mapnik::datasource::datasource_t type() const; - static std::string name(); + static const char * name(); mapnik::featureset_ptr features(mapnik::query const& q) const; mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; mapnik::box2d envelope() const; diff --git a/plugins/input/gdal/gdal_datasource.cpp b/plugins/input/gdal/gdal_datasource.cpp index 05fe41626..a324b3825 100644 --- a/plugins/input/gdal/gdal_datasource.cpp +++ b/plugins/input/gdal/gdal_datasource.cpp @@ -200,7 +200,7 @@ datasource::datasource_t gdal_datasource::type() const return datasource::Raster; } -std::string gdal_datasource::name() +const char * gdal_datasource::name() { return "gdal"; } diff --git a/plugins/input/gdal/gdal_datasource.hpp b/plugins/input/gdal/gdal_datasource.hpp index eb196ee28..989b30135 100644 --- a/plugins/input/gdal/gdal_datasource.hpp +++ b/plugins/input/gdal/gdal_datasource.hpp @@ -38,7 +38,7 @@ public: gdal_datasource(mapnik::parameters const& params, bool bind = true); virtual ~gdal_datasource(); mapnik::datasource::datasource_t type() const; - static std::string name(); + static const char * name(); mapnik::featureset_ptr features(mapnik::query const& q) const; mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; mapnik::box2d envelope() const; diff --git a/plugins/input/geojson/geojson_datasource.cpp b/plugins/input/geojson/geojson_datasource.cpp index 068bf4c1f..3ce9140e8 100644 --- a/plugins/input/geojson/geojson_datasource.cpp +++ b/plugins/input/geojson/geojson_datasource.cpp @@ -106,11 +106,9 @@ void geojson_datasource::bind() const geojson_datasource::~geojson_datasource() { } -std::string const geojson_datasource::name_="geojson"; - -std::string geojson_datasource::name() +const char * geojson_datasource::name() { - return name_; + return "geojson"; } boost::optional geojson_datasource::get_geometry_type() const diff --git a/plugins/input/geojson/geojson_datasource.hpp b/plugins/input/geojson/geojson_datasource.hpp index 079cb7e3c..231339cc0 100644 --- a/plugins/input/geojson/geojson_datasource.hpp +++ b/plugins/input/geojson/geojson_datasource.hpp @@ -44,7 +44,7 @@ public: geojson_datasource(mapnik::parameters const& params, bool bind=true); virtual ~geojson_datasource (); mapnik::datasource::datasource_t type() const; - static std::string name(); + static const char * name(); mapnik::featureset_ptr features(mapnik::query const& q) const; mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; mapnik::box2d envelope() const; @@ -52,8 +52,7 @@ public: std::map get_statistics() const; boost::optional get_geometry_type() const; void bind() const; -private: - static const std::string name_; +private: mapnik::datasource::datasource_t type_; mutable std::map statistics_; mutable mapnik::layer_descriptor desc_; diff --git a/plugins/input/geos/geos_datasource.cpp b/plugins/input/geos/geos_datasource.cpp index 8dd6fef13..8bd2bcff8 100644 --- a/plugins/input/geos/geos_datasource.cpp +++ b/plugins/input/geos/geos_datasource.cpp @@ -226,7 +226,7 @@ void geos_datasource::bind() const is_bound_ = true; } -std::string geos_datasource::name() +const char * geos_datasource::name() { return "geos"; } diff --git a/plugins/input/geos/geos_datasource.hpp b/plugins/input/geos/geos_datasource.hpp index ba39c44f1..752a89ffc 100644 --- a/plugins/input/geos/geos_datasource.hpp +++ b/plugins/input/geos/geos_datasource.hpp @@ -39,7 +39,7 @@ public: geos_datasource(mapnik::parameters const& params, bool bind = true); virtual ~geos_datasource (); mapnik::datasource::datasource_t type() const; - static std::string name(); + static const char * name(); mapnik::featureset_ptr features(mapnik::query const& q) const; mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; mapnik::box2d envelope() const; diff --git a/plugins/input/geos/geos_featureset.cpp b/plugins/input/geos/geos_featureset.cpp index 6c5ab0ef8..d3058a989 100644 --- a/plugins/input/geos/geos_featureset.cpp +++ b/plugins/input/geos/geos_featureset.cpp @@ -117,10 +117,10 @@ feature_ptr geos_featureset::next() { feature_ptr feature(feature_factory::create(ctx_,identifier_)); - geometry_utils::from_wkb(feature->paths(), + if (geometry_utils::from_wkb(feature->paths(), wkb.data(), - wkb.size()); - if (field_ != "") + wkb.size()) + && field_ != "") { feature->put(field_name_, tr_->transcode(field_.c_str())); } diff --git a/plugins/input/kismet/kismet_datasource.cpp b/plugins/input/kismet/kismet_datasource.cpp index ea5f6a2cd..07607af6d 100644 --- a/plugins/input/kismet/kismet_datasource.cpp +++ b/plugins/input/kismet/kismet_datasource.cpp @@ -122,7 +122,7 @@ kismet_datasource::~kismet_datasource() { } -std::string kismet_datasource::name() +const char * kismet_datasource::name() { return "kismet"; } diff --git a/plugins/input/kismet/kismet_datasource.hpp b/plugins/input/kismet/kismet_datasource.hpp index 1d49475ca..6e54d9c23 100644 --- a/plugins/input/kismet/kismet_datasource.hpp +++ b/plugins/input/kismet/kismet_datasource.hpp @@ -46,7 +46,7 @@ public: kismet_datasource(mapnik::parameters const& params, bool bind = true); virtual ~kismet_datasource (); datasource::datasource_t type() const; - static std::string name(); + static const char * name(); mapnik::featureset_ptr features(mapnik::query const& q) const; mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; mapnik::box2d envelope() const; diff --git a/plugins/input/kismet/kismet_featureset.hpp b/plugins/input/kismet/kismet_featureset.hpp index 0efdf537c..7fd1ba551 100644 --- a/plugins/input/kismet/kismet_featureset.hpp +++ b/plugins/input/kismet/kismet_featureset.hpp @@ -49,7 +49,6 @@ public: private: std::list const& knd_list_; boost::scoped_ptr tr_; - mapnik::wkbFormat format_; int feature_id_; std::list::const_iterator knd_list_it; mapnik::projection source_; diff --git a/plugins/input/occi/occi_datasource.cpp b/plugins/input/occi/occi_datasource.cpp index d60271e17..daa7dcd4a 100644 --- a/plugins/input/occi/occi_datasource.cpp +++ b/plugins/input/occi/occi_datasource.cpp @@ -352,7 +352,7 @@ void occi_datasource::bind() const is_bound_ = true; } -std::string occi_datasource::name() +const char * occi_datasource::name() { return "occi"; } diff --git a/plugins/input/occi/occi_datasource.hpp b/plugins/input/occi/occi_datasource.hpp index e9507d8b3..bbc57970d 100644 --- a/plugins/input/occi/occi_datasource.hpp +++ b/plugins/input/occi/occi_datasource.hpp @@ -41,7 +41,7 @@ public: occi_datasource(mapnik::parameters const& params, bool bind = true); virtual ~occi_datasource (); mapnik::datasource::datasource_t type() const; - static std::string name(); + static const char * name(); mapnik::featureset_ptr features(mapnik::query const& q) const; mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; mapnik::box2d envelope() const; diff --git a/plugins/input/ogr/ogr_datasource.cpp b/plugins/input/ogr/ogr_datasource.cpp index 9237f0a0b..ea35829cf 100644 --- a/plugins/input/ogr/ogr_datasource.cpp +++ b/plugins/input/ogr/ogr_datasource.cpp @@ -333,7 +333,7 @@ void ogr_datasource::bind() const is_bound_ = true; } -std::string ogr_datasource::name() +const char * ogr_datasource::name() { return "ogr"; } @@ -502,7 +502,6 @@ featureset_ptr ogr_datasource::features(query const& q) const filter_in_box filter(q.get_bbox()); return featureset_ptr(new ogr_index_featureset(ctx, - *dataset_, *layer, filter, index_name_, @@ -510,8 +509,7 @@ featureset_ptr ogr_datasource::features(query const& q) const } else { - return featureset_ptr(new ogr_featureset (ctx, - *dataset_, + return featureset_ptr(new ogr_featureset(ctx, *layer, q.get_bbox(), desc_.get_encoding())); @@ -546,7 +544,6 @@ featureset_ptr ogr_datasource::features_at_point(coord2d const& pt) const filter_at_point filter(pt); return featureset_ptr(new ogr_index_featureset (ctx, - *dataset_, *layer, filter, index_name_, @@ -559,7 +556,6 @@ featureset_ptr ogr_datasource::features_at_point(coord2d const& pt) const point.setY (pt.y); return featureset_ptr(new ogr_featureset (ctx, - *dataset_, *layer, point, desc_.get_encoding())); diff --git a/plugins/input/ogr/ogr_datasource.hpp b/plugins/input/ogr/ogr_datasource.hpp index 0b283800f..1898397e0 100644 --- a/plugins/input/ogr/ogr_datasource.hpp +++ b/plugins/input/ogr/ogr_datasource.hpp @@ -42,7 +42,7 @@ public: ogr_datasource(mapnik::parameters const& params, bool bind=true); virtual ~ogr_datasource (); mapnik::datasource::datasource_t type() const; - static std::string name(); + static const char * name(); mapnik::featureset_ptr features(mapnik::query const& q) const; mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; mapnik::box2d envelope() const; diff --git a/plugins/input/ogr/ogr_featureset.cpp b/plugins/input/ogr/ogr_featureset.cpp index de9f185b7..2d675c964 100644 --- a/plugins/input/ogr/ogr_featureset.cpp +++ b/plugins/input/ogr/ogr_featureset.cpp @@ -48,12 +48,10 @@ using mapnik::feature_factory; ogr_featureset::ogr_featureset(mapnik::context_ptr const & ctx, - OGRDataSource & dataset, OGRLayer & layer, OGRGeometry & extent, std::string const& encoding) : ctx_(ctx), - dataset_(dataset), layer_(layer), layerdef_(layer.GetLayerDefn()), tr_(new transcoder(encoding)), @@ -65,12 +63,10 @@ ogr_featureset::ogr_featureset(mapnik::context_ptr const & ctx, } ogr_featureset::ogr_featureset(mapnik::context_ptr const& ctx, - OGRDataSource & dataset, OGRLayer & layer, mapnik::box2d const& extent, std::string const& encoding) : ctx_(ctx), - dataset_(dataset), layer_(layer), layerdef_(layer.GetLayerDefn()), tr_(new transcoder(encoding)), diff --git a/plugins/input/ogr/ogr_featureset.hpp b/plugins/input/ogr/ogr_featureset.hpp index 9ca9b2ad9..fdeb20c29 100644 --- a/plugins/input/ogr/ogr_featureset.hpp +++ b/plugins/input/ogr/ogr_featureset.hpp @@ -38,29 +38,24 @@ class ogr_featureset : public mapnik::Featureset { public: ogr_featureset(mapnik::context_ptr const& ctx, - OGRDataSource & dataset, OGRLayer & layer, OGRGeometry & extent, std::string const& encoding); ogr_featureset(mapnik::context_ptr const& ctx, - OGRDataSource & dataset, OGRLayer & layer, mapnik::box2d const& extent, std::string const& encoding); virtual ~ogr_featureset(); mapnik::feature_ptr next(); - private: mapnik::context_ptr ctx_; - OGRDataSource& dataset_; OGRLayer& layer_; OGRFeatureDefn* layerdef_; boost::scoped_ptr tr_; const char* fidcolumn_; mutable int count_; - }; #endif // OGR_FEATURESET_HPP diff --git a/plugins/input/ogr/ogr_index_featureset.cpp b/plugins/input/ogr/ogr_index_featureset.cpp index 7a37b04b1..98cb9da3b 100644 --- a/plugins/input/ogr/ogr_index_featureset.cpp +++ b/plugins/input/ogr/ogr_index_featureset.cpp @@ -53,13 +53,11 @@ using mapnik::feature_factory; template ogr_index_featureset::ogr_index_featureset(mapnik::context_ptr const & ctx, - OGRDataSource & dataset, OGRLayer & layer, filterT const& filter, std::string const& index_file, std::string const& encoding) : ctx_(ctx), - dataset_(dataset), layer_(layer), layerdef_(layer.GetLayerDefn()), filter_(filter), diff --git a/plugins/input/ogr/ogr_index_featureset.hpp b/plugins/input/ogr/ogr_index_featureset.hpp index cde9c68c5..a285ad3b9 100644 --- a/plugins/input/ogr/ogr_index_featureset.hpp +++ b/plugins/input/ogr/ogr_index_featureset.hpp @@ -33,7 +33,6 @@ class ogr_index_featureset : public mapnik::Featureset { public: ogr_index_featureset(mapnik::context_ptr const& ctx, - OGRDataSource& dataset, OGRLayer& layer, filterT const& filter, std::string const& index_file, @@ -41,10 +40,8 @@ public: virtual ~ogr_index_featureset(); mapnik::feature_ptr next(); - private: mapnik::context_ptr ctx_; - OGRDataSource& dataset_; OGRLayer& layer_; OGRFeatureDefn* layerdef_; filterT filter_; diff --git a/plugins/input/osm/basiccurl.cpp b/plugins/input/osm/basiccurl.cpp index ef8c32f4e..600f2f30b 100755 --- a/plugins/input/osm/basiccurl.cpp +++ b/plugins/input/osm/basiccurl.cpp @@ -22,6 +22,8 @@ #include "basiccurl.h" +#include + CURL_LOAD_DATA* grab_http_response(const char* url) { CURL_LOAD_DATA* data; @@ -39,7 +41,6 @@ CURL_LOAD_DATA* grab_http_response(const char* url) CURL_LOAD_DATA* do_grab(CURL* curl,const char* url) { - CURLcode res; CURL_LOAD_DATA* data = (CURL_LOAD_DATA*)malloc(sizeof(CURL_LOAD_DATA)); data->data = NULL; data->nbytes = 0; @@ -48,7 +49,10 @@ CURL_LOAD_DATA* do_grab(CURL* curl,const char* url) curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, response_callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, data); - res = curl_easy_perform(curl); + CURLcode res = curl_easy_perform(curl); + if (res !=0) { + std::clog << "error grabbing data\n"; + } return data; } diff --git a/plugins/input/osm/osm_datasource.cpp b/plugins/input/osm/osm_datasource.cpp index 8835e0339..dbc8dfd7d 100644 --- a/plugins/input/osm/osm_datasource.cpp +++ b/plugins/input/osm/osm_datasource.cpp @@ -130,7 +130,7 @@ osm_datasource::~osm_datasource() //delete osm_data_; } -std::string osm_datasource::name() +const char * osm_datasource::name() { return "osm"; } diff --git a/plugins/input/osm/osm_datasource.hpp b/plugins/input/osm/osm_datasource.hpp index dc0c8fe51..1b99718ed 100644 --- a/plugins/input/osm/osm_datasource.hpp +++ b/plugins/input/osm/osm_datasource.hpp @@ -43,7 +43,7 @@ public: osm_datasource(const parameters& params, bool bind = true); virtual ~osm_datasource(); mapnik::datasource::datasource_t type() const; - static std::string name(); + static const char * name(); featureset_ptr features(const query& q) const; featureset_ptr features_at_point(coord2d const& pt) const; box2d envelope() const; diff --git a/plugins/input/postgis/postgis_datasource.cpp b/plugins/input/postgis/postgis_datasource.cpp index b2ae1a46f..3f95865cd 100644 --- a/plugins/input/postgis/postgis_datasource.cpp +++ b/plugins/input/postgis/postgis_datasource.cpp @@ -313,7 +313,7 @@ void postgis_datasource::bind() const { srid_ = -1; - MAPNIK_LOG_DEBUG(postgis) << "postgis_datasource: Table " << table_ << " is using SRID=-1"; + MAPNIK_LOG_DEBUG(postgis) << "postgis_datasource: Table " << table_ << " is using SRID=" << srid_; } // At this point the geometry_field may still not be known @@ -439,7 +439,7 @@ postgis_datasource::~postgis_datasource() } } -std::string postgis_datasource::name() +const char * postgis_datasource::name() { return "postgis"; } diff --git a/plugins/input/postgis/postgis_datasource.hpp b/plugins/input/postgis/postgis_datasource.hpp index afb840c08..f484837c8 100644 --- a/plugins/input/postgis/postgis_datasource.hpp +++ b/plugins/input/postgis/postgis_datasource.hpp @@ -51,7 +51,7 @@ public: postgis_datasource(const parameters ¶ms, bool bind=true); ~postgis_datasource(); mapnik::datasource::datasource_t type() const; - static std::string name(); + static const char * name(); featureset_ptr features(const query& q) const; featureset_ptr features_at_point(coord2d const& pt) const; mapnik::box2d envelope() const; diff --git a/plugins/input/postgis/postgis_featureset.cpp b/plugins/input/postgis/postgis_featureset.cpp index 7c227894e..dd121a36d 100644 --- a/plugins/input/postgis/postgis_featureset.cpp +++ b/plugins/input/postgis/postgis_featureset.cpp @@ -62,7 +62,7 @@ postgis_featureset::postgis_featureset(boost::shared_ptr const& rs, feature_ptr postgis_featureset::next() { - if (rs_->next()) + while (rs_->next()) { // new feature unsigned pos = 1; @@ -107,10 +107,12 @@ feature_ptr postgis_featureset::next() // parse geometry int size = rs_->getFieldLength(0); const char *data = rs_->getValue(0); - geometry_utils::from_wkb(feature->paths(), data, size); + if (!geometry_utils::from_wkb(feature->paths(), data, size)) + continue; + totalGeomSize_ += size; - int num_attrs = ctx_->size() + 1; + unsigned num_attrs = ctx_->size() + 1; for (; pos < num_attrs; ++pos) { std::string name = rs_->getFieldName(pos); @@ -207,11 +209,7 @@ feature_ptr postgis_featureset::next() } return feature; } - else - { - rs_->close(); - return feature_ptr(); - } + return feature_ptr(); } diff --git a/plugins/input/postgis/postgis_featureset.hpp b/plugins/input/postgis/postgis_featureset.hpp index 80c011c83..013a7de0f 100644 --- a/plugins/input/postgis/postgis_featureset.hpp +++ b/plugins/input/postgis/postgis_featureset.hpp @@ -55,7 +55,7 @@ private: boost::shared_ptr rs_; context_ptr ctx_; boost::scoped_ptr tr_; - int totalGeomSize_; + unsigned totalGeomSize_; int feature_id_; bool key_field_; }; diff --git a/plugins/input/raster/raster_datasource.cpp b/plugins/input/raster/raster_datasource.cpp index f0d98c8b3..efbd38233 100644 --- a/plugins/input/raster/raster_datasource.cpp +++ b/plugins/input/raster/raster_datasource.cpp @@ -159,7 +159,7 @@ mapnik::datasource::datasource_t raster_datasource::type() const return datasource::Raster; } -std::string raster_datasource::name() +const char * raster_datasource::name() { return "raster"; } diff --git a/plugins/input/raster/raster_datasource.hpp b/plugins/input/raster/raster_datasource.hpp index 5e373142a..9b84380e5 100644 --- a/plugins/input/raster/raster_datasource.hpp +++ b/plugins/input/raster/raster_datasource.hpp @@ -34,7 +34,7 @@ public: raster_datasource(const mapnik::parameters& params, bool bind=true); virtual ~raster_datasource(); datasource::datasource_t type() const; - static std::string name(); + static const char * name(); mapnik::featureset_ptr features(const mapnik::query& q) const; mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; mapnik::box2d envelope() const; diff --git a/plugins/input/rasterlite/rasterlite_datasource.cpp b/plugins/input/rasterlite/rasterlite_datasource.cpp index 3fd3c73ef..bc8817745 100644 --- a/plugins/input/rasterlite/rasterlite_datasource.cpp +++ b/plugins/input/rasterlite/rasterlite_datasource.cpp @@ -166,7 +166,7 @@ rasterlite_datasource::~rasterlite_datasource() { } -std::string rasterlite_datasource::name() +const char * rasterlite_datasource::name() { return "rasterlite"; } diff --git a/plugins/input/rasterlite/rasterlite_datasource.hpp b/plugins/input/rasterlite/rasterlite_datasource.hpp index 18580935e..4971b2d1d 100644 --- a/plugins/input/rasterlite/rasterlite_datasource.hpp +++ b/plugins/input/rasterlite/rasterlite_datasource.hpp @@ -37,7 +37,7 @@ public: rasterlite_datasource(mapnik::parameters const& params, bool bind = true); virtual ~rasterlite_datasource (); mapnik::datasource::datasource_t type() const; - static std::string name(); + static const char * name(); mapnik::featureset_ptr features(mapnik::query const& q) const; mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; mapnik::box2d envelope() const; diff --git a/plugins/input/shape/shape_datasource.cpp b/plugins/input/shape/shape_datasource.cpp index 5ceb23284..caf401e81 100644 --- a/plugins/input/shape/shape_datasource.cpp +++ b/plugins/input/shape/shape_datasource.cpp @@ -238,7 +238,7 @@ void shape_datasource::init(shape_io& shape) const MAPNIK_LOG_DEBUG(shape) << "shape_datasource: Shape type=" << shape_type_; } -std::string shape_datasource::name() +const char * shape_datasource::name() { return "shape"; } diff --git a/plugins/input/shape/shape_datasource.hpp b/plugins/input/shape/shape_datasource.hpp index 641f9e373..522365dde 100644 --- a/plugins/input/shape/shape_datasource.hpp +++ b/plugins/input/shape/shape_datasource.hpp @@ -45,7 +45,7 @@ public: shape_datasource(const parameters ¶ms, bool bind=true); virtual ~shape_datasource(); datasource::datasource_t type() const; - static std::string name(); + static const char * name(); featureset_ptr features(const query& q) const; featureset_ptr features_at_point(coord2d const& pt) const; box2d envelope() const; diff --git a/plugins/input/sqlite/sqlite_datasource.cpp b/plugins/input/sqlite/sqlite_datasource.cpp index bab062485..0eec7e5f4 100644 --- a/plugins/input/sqlite/sqlite_datasource.cpp +++ b/plugins/input/sqlite/sqlite_datasource.cpp @@ -473,7 +473,7 @@ void sqlite_datasource::parse_attachdb(std::string const& attachdb) const } } -std::string sqlite_datasource::name() +const char * sqlite_datasource::name() { return "sqlite"; } @@ -522,17 +522,19 @@ boost::optional sqlite_datasource::get_geometry_ if (data) { boost::ptr_vector paths; - mapnik::geometry_utils::from_wkb(paths, data, size, mapnik::wkbAuto); - mapnik::util::to_ds_type(paths,result); - if (result) + if (mapnik::geometry_utils::from_wkb(paths, data, size, mapnik::wkbAuto)) { - int type = static_cast(*result); - if (multi_type > 0 && multi_type != type) + mapnik::util::to_ds_type(paths,result); + if (result) { - result.reset(mapnik::datasource::Collection); - return result; + int type = static_cast(*result); + if (multi_type > 0 && multi_type != type) + { + result.reset(mapnik::datasource::Collection); + return result; + } + multi_type = type; } - multi_type = type; } } } diff --git a/plugins/input/sqlite/sqlite_datasource.hpp b/plugins/input/sqlite/sqlite_datasource.hpp index 11ec7cf7f..c1f840212 100644 --- a/plugins/input/sqlite/sqlite_datasource.hpp +++ b/plugins/input/sqlite/sqlite_datasource.hpp @@ -43,7 +43,7 @@ public: sqlite_datasource(mapnik::parameters const& params, bool bind = true); virtual ~sqlite_datasource (); datasource::datasource_t type() const; - static std::string name(); + static const char * name(); mapnik::featureset_ptr features(mapnik::query const& q) const; mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; mapnik::box2d envelope() const; diff --git a/plugins/input/sqlite/sqlite_featureset.cpp b/plugins/input/sqlite/sqlite_featureset.cpp index 5e822671d..df2203710 100644 --- a/plugins/input/sqlite/sqlite_featureset.cpp +++ b/plugins/input/sqlite/sqlite_featureset.cpp @@ -75,7 +75,8 @@ feature_ptr sqlite_featureset::next() } feature_ptr feature = feature_factory::create(ctx_,rs_->column_integer(1)); - geometry_utils::from_wkb(feature->paths(), data, size, format_); + if (!geometry_utils::from_wkb(feature->paths(), data, size, format_)) + continue; if (!spatial_index_) { diff --git a/plugins/input/sqlite/sqlite_utils.hpp b/plugins/input/sqlite/sqlite_utils.hpp index d9074d09f..891150506 100644 --- a/plugins/input/sqlite/sqlite_utils.hpp +++ b/plugins/input/sqlite/sqlite_utils.hpp @@ -190,21 +190,22 @@ public: if (data) { boost::ptr_vector paths; - mapnik::geometry_utils::from_wkb(paths, data, size, mapnik::wkbAuto); - for (unsigned i=0; i const& bbox = paths[i].envelope(); - - if (bbox.valid()) + for (unsigned i=0; i const& bbox = paths[i].envelope(); + if (bbox.valid()) { - first = false; - extent = bbox; - } - else - { - extent.expand_to_include(bbox); + if (first) + { + first = false; + extent = bbox; + } + else + { + extent.expand_to_include(bbox); + } } } } @@ -276,24 +277,24 @@ public: if (data) { boost::ptr_vector paths; - mapnik::geometry_utils::from_wkb(paths, data, size, mapnik::wkbAuto); mapnik::box2d bbox; - for (unsigned i=0; icolumn_type(1); if (type_oid != SQLITE_INTEGER) { @@ -303,7 +304,6 @@ public: << "' type was: " << type_oid << ""; throw mapnik::datasource_exception(error_msg.str()); } - const sqlite_int64 pkid = rs->column_integer64(1); ps.bind(pkid); } @@ -314,7 +314,6 @@ public: << rs->column_name(1) << "' == " << rs->column_integer64(1); throw mapnik::datasource_exception(error_msg.str()); } - ps.step_next(); one_success = true; } @@ -365,45 +364,41 @@ public: if (data) { boost::ptr_vector paths; - mapnik::geometry_utils::from_wkb(paths, data, size, mapnik::wkbAuto); - for (unsigned i=0; i const& bbox = paths[i].envelope(); - if (bbox.valid()) + for (unsigned i=0; icolumn_type(1); - if (type_oid != SQLITE_INTEGER) + mapnik::box2d const& bbox = paths[i].envelope(); + if (bbox.valid()) + { + const int type_oid = rs->column_type(1); + if (type_oid != SQLITE_INTEGER) + { + std::ostringstream error_msg; + error_msg << "Sqlite Plugin: invalid type for key field '" + << rs->column_name(1) << "' when creating index " + << "type was: " << type_oid << ""; + throw mapnik::datasource_exception(error_msg.str()); + } + const sqlite_int64 pkid = rs->column_integer64(1); + rtree_type entry = rtree_type(); + entry.pkid = pkid; + entry.bbox = bbox; + rtree_list.push_back(entry); + } + else { std::ostringstream error_msg; - error_msg << "Sqlite Plugin: invalid type for key field '" - << rs->column_name(1) << "' when creating index " - << "type was: " << type_oid << ""; + error_msg << "SQLite Plugin: encountered invalid bbox at '" + << rs->column_name(1) << "' == " << rs->column_integer64(1); throw mapnik::datasource_exception(error_msg.str()); } - - const sqlite_int64 pkid = rs->column_integer64(1); - - rtree_type entry = rtree_type(); - entry.pkid = pkid; - entry.bbox = bbox; - rtree_list.push_back(entry); - - } - else - { - std::ostringstream error_msg; - error_msg << "SQLite Plugin: encountered invalid bbox at '" - << rs->column_name(1) << "' == " << rs->column_integer64(1); - throw mapnik::datasource_exception(error_msg.str()); } } } } } - - static bool create_spatial_index2(std::string const& index_db, std::string const& index_table, std::vector const& rtree_list) diff --git a/plugins/input/templates/README b/plugins/input/templates/README.md similarity index 58% rename from plugins/input/templates/README rename to plugins/input/templates/README.md index 2b80be843..d4232f0c6 100644 --- a/plugins/input/templates/README +++ b/plugins/input/templates/README.md @@ -1,13 +1,15 @@ -template plugins ----------------- +## template plugins Directory to hold sample plugin templates. These are NOT intended to be used except for testing by developers. -Build these plugins with: +Build these plugins with the Mapnik build system: -$ scons SAMPLE_INPUT_PLUGINS=True + ./configure SAMPLE_INPUT_PLUGINS=True + make install + +Or develop them locally using the `Makefile` provided. Only an ultra-simple hello world is available currently, but planned are example plugins templates for file-based diff --git a/plugins/input/templates/helloworld/Makefile b/plugins/input/templates/helloworld/Makefile new file mode 100644 index 000000000..2caf7fcc9 --- /dev/null +++ b/plugins/input/templates/helloworld/Makefile @@ -0,0 +1,30 @@ +CXX = clang++ + +CXXFLAGS = $(shell mapnik-config --cflags) + +LIBS = $(shell mapnik-config --libs --ldflags --dep-libs) + +SRC = $(wildcard *.cpp) + +OBJ = $(SRC:.cpp=.o) + +BIN = hello.input + +all : $(SRC) $(BIN) + +$(BIN) : $(OBJ) + $(CXX) -shared $(OBJ) $(LIBS) -o $@ + +.cpp.o : + $(CXX) -c $(CXXFLAGS) $< -o $@ + +.PHONY : clean + +clean: + rm -f $(OBJ) + rm -f $(BIN) + +deploy : all + cp hello.input $(shell mapnik-config --input-plugins) + +install: clean all deploy \ No newline at end of file diff --git a/plugins/input/templates/helloworld/README b/plugins/input/templates/helloworld/README.md similarity index 89% rename from plugins/input/templates/helloworld/README rename to plugins/input/templates/helloworld/README.md index 90fbd736f..0b8e4520c 100644 --- a/plugins/input/templates/helloworld/README +++ b/plugins/input/templates/helloworld/README.md @@ -1,9 +1,11 @@ -hello world plugin ------------------- +## hello world plugin This is a very simple sample plugin. It is designed to help developers see the skeletal basics needed to achieve a functional datasource plugin. +It is not a model plugin of best practices as much as a model of the bare +minimum you need to have a working plugin that returns a single feature. + Code comments attempt to highlight which code is mandatory, which is simply recommended, and which is purely fluff used to get the plugin to actually show some data. diff --git a/plugins/input/templates/helloworld/hello_datasource.cpp b/plugins/input/templates/helloworld/hello_datasource.cpp index 8bcd2283c..897b40829 100644 --- a/plugins/input/templates/helloworld/hello_datasource.cpp +++ b/plugins/input/templates/helloworld/hello_datasource.cpp @@ -39,11 +39,9 @@ void hello_datasource::bind() const hello_datasource::~hello_datasource() { } // This name must match the plugin filename, eg 'hello.input' -std::string const hello_datasource::name_="hello"; - -std::string hello_datasource::name() +const char * hello_datasource::name() { - return name_; + return "hello"; } mapnik::datasource::datasource_t hello_datasource::type() const diff --git a/plugins/input/templates/helloworld/hello_datasource.hpp b/plugins/input/templates/helloworld/hello_datasource.hpp index a2c136246..f2e172f56 100644 --- a/plugins/input/templates/helloworld/hello_datasource.hpp +++ b/plugins/input/templates/helloworld/hello_datasource.hpp @@ -18,7 +18,7 @@ public: mapnik::datasource::datasource_t type() const; // mandatory: name of the plugin - static std::string name(); + static const char * name(); // mandatory: function to query features by box2d // this is called when rendering, specifically in feature_style_processor.hpp diff --git a/plugins/input/templates/helloworld/hello_featureset.cpp b/plugins/input/templates/helloworld/hello_featureset.cpp index eb3f19a10..b24d4d37e 100644 --- a/plugins/input/templates/helloworld/hello_featureset.cpp +++ b/plugins/input/templates/helloworld/hello_featureset.cpp @@ -16,6 +16,12 @@ mapnik::feature_ptr hello_featureset::next() { if (feature_id_ == 1) { + // let us pretend it just has one column/attribute name + std::string attribute("key"); + + // the featureset context needs to know the field schema + ctx_->push(attribute); + // create a new feature mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_,feature_id_)); @@ -24,7 +30,7 @@ mapnik::feature_ptr hello_featureset::next() // create an attribute pair of key:value UnicodeString ustr = tr_->transcode("hello world!"); - feature->put("key",ustr); + feature->put(attribute,ustr); // we need a geometry to display so just for fun here // we take the center of the bbox that was used to query diff --git a/src/agg/agg_renderer.cpp b/src/agg/agg_renderer.cpp index c7a480780..46f048063 100644 --- a/src/agg/agg_renderer.cpp +++ b/src/agg/agg_renderer.cpp @@ -42,7 +42,11 @@ #include "agg_rendering_buffer.h" #include "agg_pixfmt_rgba.h" #include "agg_scanline_u.h" - +#include "agg_image_filters.h" +#include "agg_trans_bilinear.h" +#include "agg_span_allocator.h" +#include "agg_image_accessors.h" +#include "agg_span_image_filter_rgba.h" // boost #include #include @@ -235,7 +239,7 @@ void agg_renderer::end_style_processing(feature_type_style const& st) { blend_from = true; mapnik::filter::filter_visitor visitor(*current_buffer_); - BOOST_FOREACH(mapnik::filter::filter_type filter_tag, st.image_filters()) + BOOST_FOREACH(mapnik::filter::filter_type const& filter_tag, st.image_filters()) { boost::apply_visitor(visitor, filter_tag); } @@ -252,7 +256,7 @@ void agg_renderer::end_style_processing(feature_type_style const& st) // apply any 'direct' image filters mapnik::filter::filter_visitor visitor(pixmap_); - BOOST_FOREACH(mapnik::filter::filter_type filter_tag, st.direct_image_filters()) + BOOST_FOREACH(mapnik::filter::filter_type const& filter_tag, st.direct_image_filters()) { boost::apply_visitor(visitor, filter_tag); } @@ -264,24 +268,24 @@ template void agg_renderer::render_marker(pixel_position const& pos, marker const& marker, agg::trans_affine const& tr, double opacity, composite_mode_e comp_op) { + typedef agg::rgba8 color_type; + typedef agg::order_rgba order_type; + typedef agg::pixel32_type pixel_type; + typedef agg::comp_op_adaptor_rgba blender_type; // comp blender + typedef agg::pixfmt_custom_blend_rgba pixfmt_comp_type; + typedef agg::renderer_base renderer_base; + typedef agg::renderer_scanline_aa_solid renderer_type; + + ras_ptr->reset(); + ras_ptr->gamma(agg::gamma_power()); + agg::scanline_u8 sl; + agg::rendering_buffer buf(current_buffer_->raw_data(), width_, height_, width_ * 4); + pixfmt_comp_type pixf(buf); + pixf.comp_op(static_cast(comp_op)); + renderer_base renb(pixf); + if (marker.is_vector()) { - typedef agg::rgba8 color_type; - typedef agg::order_rgba order_type; - typedef agg::pixel32_type pixel_type; - typedef agg::comp_op_adaptor_rgba blender_type; // comp blender - typedef agg::pixfmt_custom_blend_rgba pixfmt_comp_type; - typedef agg::renderer_base renderer_base; - typedef agg::renderer_scanline_aa_solid renderer_type; - - ras_ptr->reset(); - ras_ptr->gamma(agg::gamma_power()); - agg::scanline_u8 sl; - agg::rendering_buffer buf(current_buffer_->raw_data(), width_, height_, width_ * 4); - pixfmt_comp_type pixf(buf); - pixf.comp_op(static_cast(comp_op)); - renderer_base renb(pixf); - box2d const& bbox = (*marker.get_vector_data())->bounding_box(); coord c = bbox.center(); // center the svg marker on '0,0' @@ -304,12 +308,12 @@ void agg_renderer::render_marker(pixel_position const& pos, marker const& mar } else { - double w = (*marker.get_bitmap_data())->width(); - double h = (*marker.get_bitmap_data())->height(); - double cx = 0.5 * w; - double cy = 0.5 * h; + double width = (*marker.get_bitmap_data())->width(); + double height = (*marker.get_bitmap_data())->height(); + double cx = 0.5 * width; + double cy = 0.5 * height; - if (std::fabs(1.0 - scale_factor_) < 0.001) + if (std::fabs(1.0 - scale_factor_) < 0.001 && tr.is_identity()) { composite(current_buffer_->data(), **marker.get_bitmap_data(), comp_op, opacity, @@ -319,15 +323,52 @@ void agg_renderer::render_marker(pixel_position const& pos, marker const& mar } else { - double scaled_width = w * scale_factor_; - double scaled_height = h * scale_factor_; - image_data_32 buf(std::ceil(scaled_width),std::ceil(scaled_height)); - scale_image_agg(buf, **marker.get_bitmap_data(), SCALING_BILINEAR, scale_factor_); - composite(current_buffer_->data(), buf, - comp_op, opacity, - boost::math::iround(pos.x - 0.5*scaled_width), - boost::math::iround(pos.y - 0.5*scaled_height), - false); + + double p[8]; + double x0 = pos.x - 0.5 * width; + double y0 = pos.y - 0.5 * height; + p[0] = x0; p[1] = y0; + p[2] = x0 + width; p[3] = y0; + p[4] = x0 + width; p[5] = y0 + height; + p[6] = x0; p[7] = y0 + height; + + agg::trans_affine marker_tr; + + marker_tr *= agg::trans_affine_translation(-pos.x,-pos.y); + marker_tr *= tr; + marker_tr *= agg::trans_affine_scaling(scale_factor_); + marker_tr *= agg::trans_affine_translation(pos.x,pos.y); + + marker_tr.transform(&p[0], &p[1]); + marker_tr.transform(&p[2], &p[3]); + marker_tr.transform(&p[4], &p[5]); + marker_tr.transform(&p[6], &p[7]); + + ras_ptr->move_to_d(p[0],p[1]); + ras_ptr->line_to_d(p[2],p[3]); + ras_ptr->line_to_d(p[4],p[5]); + ras_ptr->line_to_d(p[6],p[7]); + + + agg::span_allocator sa; + agg::image_filter_bilinear filter_kernel; + agg::image_filter_lut filter(filter_kernel, false); + + image_data_32 const& src = **marker.get_bitmap_data(); + agg::rendering_buffer marker_buf((unsigned char *)src.getBytes(), + src.width(), + src.height(), + src.width()*4); + agg::pixfmt_rgba32_pre pixf(marker_buf); + + typedef agg::image_accessor_clone img_accessor_type; + typedef agg::span_interpolator_linear interpolator_type; + typedef agg::span_image_filter_rgba_2x2 span_gen_type; + img_accessor_type ia(pixf); + interpolator_type interpolator(agg::trans_affine(p, 0, 0, width, height) ); + span_gen_type sg(ia, interpolator, filter); + agg::render_scanlines_aa(*ras_ptr, sl, renb, sa, sg); } } } diff --git a/src/agg/process_building_symbolizer.cpp b/src/agg/process_building_symbolizer.cpp index 7863fd566..8f82ca2b8 100644 --- a/src/agg/process_building_symbolizer.cpp +++ b/src/agg/process_building_symbolizer.cpp @@ -77,7 +77,7 @@ void agg_renderer::process(building_symbolizer const& sym, for (unsigned i=0;i 2) + if (geom.size() > 2) { boost::scoped_ptr frame(new geometry_type(LineString)); boost::scoped_ptr roof(new geometry_type(Polygon)); @@ -87,7 +87,7 @@ void agg_renderer::process(building_symbolizer const& sym, geom.rewind(0); unsigned cm = geom.vertex(&x0,&y0); - for (unsigned j=1;j::process(building_symbolizer const& sym, } geom.rewind(0); - for (unsigned j=0;j::process(line_pattern_symbolizer const& sym, BOOST_FOREACH(geometry_type & geom, feature.paths()) { - if (geom.num_points() > 1) + if (geom.size() > 1) { converter.apply(geom); } diff --git a/src/agg/process_line_symbolizer.cpp b/src/agg/process_line_symbolizer.cpp index 9edf59b4a..1d5388aa3 100644 --- a/src/agg/process_line_symbolizer.cpp +++ b/src/agg/process_line_symbolizer.cpp @@ -109,7 +109,7 @@ void agg_renderer::process(line_symbolizer const& sym, BOOST_FOREACH( geometry_type & geom, feature.paths()) { - if (geom.num_points() > 1) + if (geom.size() > 1) { converter.apply(geom); } @@ -132,7 +132,7 @@ void agg_renderer::process(line_symbolizer const& sym, BOOST_FOREACH( geometry_type & geom, feature.paths()) { - if (geom.num_points() > 1) + if (geom.size() > 1) { converter.apply(geom); } diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp index 111b03f9b..11f90def7 100644 --- a/src/agg/process_markers_symbolizer.cpp +++ b/src/agg/process_markers_symbolizer.cpp @@ -23,40 +23,41 @@ // mapnik #include #include +#include #include #include #include -#include +#include #include #include +#include #include #include #include -#include #include +// agg #include "agg_basics.h" #include "agg_rendering_buffer.h" #include "agg_pixfmt_rgba.h" #include "agg_rasterizer_scanline_aa.h" #include "agg_scanline_u.h" -#include "agg_scanline_p.h" #include "agg_path_storage.h" -#include "agg_ellipse.h" -#include "agg_conv_stroke.h" #include "agg_conv_clip_polyline.h" #include "agg_conv_transform.h" +#include "agg_image_filters.h" +#include "agg_trans_bilinear.h" +#include "agg_span_allocator.h" +#include "agg_image_accessors.h" +#include "agg_span_image_filter_rgba.h" +// boost +#include namespace mapnik { -template -void agg_renderer::process(markers_symbolizer const& sym, - mapnik::feature_impl & feature, - proj_transform const& prj_trans) +template +struct vector_markers_rasterizer_dispatch { - typedef agg::conv_clip_polyline clipped_geometry_type; - typedef coord_transform path_type; - typedef agg::conv_transform transformed_path_type; typedef agg::rgba8 color_type; typedef agg::order_rgba order_type; typedef agg::pixel32_type pixel_type; @@ -65,111 +66,317 @@ void agg_renderer::process(markers_symbolizer const& sym, typedef agg::renderer_base renderer_base; typedef agg::renderer_scanline_aa_solid renderer_type; - ras_ptr->reset(); - ras_ptr->gamma(agg::gamma_power()); - agg::scanline_u8 sl; - agg::rendering_buffer buf(current_buffer_->raw_data(), width_, height_, width_ * 4); - pixfmt_comp_type pixf(buf); - pixf.comp_op(static_cast(sym.comp_op())); - renderer_base renb(pixf); - renderer_type ren(renb); - agg::trans_affine tr; - evaluate_transform(tr, feature, sym.get_image_transform()); - tr = agg::trans_affine_scaling(scale_factor_) * tr; + vector_markers_rasterizer_dispatch(BufferType & image_buffer, + SvgRenderer & svg_renderer, + Rasterizer & ras, + box2d const& bbox, + agg::trans_affine const& marker_trans, + markers_symbolizer const& sym, + Detector & detector, + double scale_factor) + : buf_(image_buffer.raw_data(), image_buffer.width(), image_buffer.height(), image_buffer.width() * 4), + pixf_(buf_), + renb_(pixf_), + svg_renderer_(svg_renderer), + ras_(ras), + bbox_(bbox), + marker_trans_(marker_trans), + sym_(sym), + detector_(detector), + scale_factor_(scale_factor) + { + pixf_.comp_op(static_cast(sym_.comp_op())); + } - agg::trans_affine geom_tr; - evaluate_transform(geom_tr, feature, sym.get_transform()); + template + void add_path(T & path) + { + marker_placement_e placement_method = sym_.get_marker_placement(); + + if (placement_method == MARKER_POINT_PLACEMENT) + { + double x,y; + path.rewind(0); + label::interior_position(path, x, y); + agg::trans_affine matrix = marker_trans_; + matrix.translate(x,y); + box2d transformed_bbox = bbox_ * matrix; + + if (sym_.get_allow_overlap() || + detector_.has_placement(transformed_bbox)) + { + svg_renderer_.render(ras_, sl_, renb_, matrix, sym_.get_opacity(), bbox_); + + if (!sym_.get_ignore_placement()) + detector_.insert(transformed_bbox); + } + } + else + { + markers_placement placement(path, bbox_, marker_trans_, detector_, + sym_.get_spacing() * scale_factor_, + sym_.get_max_error(), + sym_.get_allow_overlap()); + double x, y, angle; + while (placement.get_point(x, y, angle)) + { + agg::trans_affine matrix = marker_trans_; + matrix.rotate(angle); + matrix.translate(x, y); + svg_renderer_.render(ras_, sl_, renb_, matrix, sym_.get_opacity(), bbox_); + } + } + } +private: + agg::scanline_u8 sl_; + agg::rendering_buffer buf_; + pixfmt_comp_type pixf_; + renderer_base renb_; + SvgRenderer & svg_renderer_; + Rasterizer & ras_; + box2d const& bbox_; + agg::trans_affine const& marker_trans_; + markers_symbolizer const& sym_; + Detector & detector_; + double scale_factor_; +}; + +template +void render_raster_marker(Rasterizer & ras, RendererBuffer & renb, agg::scanline_u8 & sl, + pixel_position const& pos, image_data_32 const& src, + agg::trans_affine const& tr,double opacity, + double scale_factor) +{ + + double width = src.width(); + double height = src.height(); + double p[8]; + p[0] = pos.x; p[1] = pos.y; + p[2] = pos.x + width; p[3] = pos.y; + p[4] = pos.x + width; p[5] = pos.y + height; + p[6] = pos.x; p[7] = pos.y + height; + + agg::trans_affine marker_tr; + + marker_tr *= agg::trans_affine_translation(-pos.x,-pos.y); + marker_tr *= tr; + marker_tr *= agg::trans_affine_scaling(scale_factor); + marker_tr *= agg::trans_affine_translation(pos.x,pos.y); + + marker_tr.transform(&p[0], &p[1]); + marker_tr.transform(&p[2], &p[3]); + marker_tr.transform(&p[4], &p[5]); + marker_tr.transform(&p[6], &p[7]); + + ras.move_to_d(p[0],p[1]); + ras.line_to_d(p[2],p[3]); + ras.line_to_d(p[4],p[5]); + ras.line_to_d(p[6],p[7]); + + typedef agg::rgba8 color_type; + agg::span_allocator sa; + agg::image_filter_bilinear filter_kernel; + agg::image_filter_lut filter(filter_kernel, false); + + agg::rendering_buffer marker_buf((unsigned char *)src.getBytes(), + src.width(), + src.height(), + src.width()*4); + agg::pixfmt_rgba32_pre pixf(marker_buf); + + typedef agg::image_accessor_clone img_accessor_type; + typedef agg::span_interpolator_linear interpolator_type; + typedef agg::span_image_filter_rgba_2x2 span_gen_type; + img_accessor_type ia(pixf); + interpolator_type interpolator(agg::trans_affine(p, 0, 0, width, height) ); + span_gen_type sg(ia, interpolator, filter); + agg::render_scanlines_aa(ras, sl, renb, sa, sg); +} + +template +struct raster_markers_rasterizer_dispatch +{ + typedef agg::rgba8 color_type; + typedef agg::order_rgba order_type; + typedef agg::pixel32_type pixel_type; + typedef agg::comp_op_adaptor_rgba_pre blender_type; // comp blender + typedef agg::pixfmt_custom_blend_rgba pixfmt_comp_type; + typedef agg::renderer_base renderer_base; + typedef agg::renderer_scanline_aa_solid renderer_type; + + raster_markers_rasterizer_dispatch(BufferType & image_buffer, + Rasterizer & ras, + image_data_32 const& src, + agg::trans_affine const& marker_trans, + markers_symbolizer const& sym, + Detector & detector, + double scale_factor) + : buf_(image_buffer.raw_data(), image_buffer.width(), image_buffer.height(), image_buffer.width() * 4), + pixf_(buf_), + renb_(pixf_), + ras_(ras), + src_(src), + marker_trans_(marker_trans), + sym_(sym), + detector_(detector), + scale_factor_(scale_factor) + { + pixf_.comp_op(static_cast(sym_.comp_op())); + } + + template + void add_path(T & path) + { + marker_placement_e placement_method = sym_.get_marker_placement(); + box2d bbox_(0,0, src_.width(),src_.height()); + + if (placement_method == MARKER_POINT_PLACEMENT) + { + double x,y; + path.rewind(0); + label::interior_position(path, x, y); + agg::trans_affine matrix = marker_trans_; + matrix.translate(x,y); + box2d transformed_bbox = bbox_ * matrix; + + if (sym_.get_allow_overlap() || + detector_.has_placement(transformed_bbox)) + { + + render_raster_marker(ras_, renb_, sl_, pixel_position(x,y), src_, + marker_trans_, sym_.get_opacity(), scale_factor_); + if (!sym_.get_ignore_placement()) + detector_.insert(transformed_bbox); + } + } + else + { + markers_placement placement(path, bbox_, marker_trans_, detector_, + sym_.get_spacing() * scale_factor_, + sym_.get_max_error(), + sym_.get_allow_overlap()); + double x, y, angle; + while (placement.get_point(x, y, angle)) + { + agg::trans_affine matrix = marker_trans_; + matrix.rotate(angle); + render_raster_marker(ras_, renb_, sl_, pixel_position(x,y), src_, + matrix, sym_.get_opacity(), scale_factor_); + } + } + } +private: + agg::scanline_u8 sl_; + agg::rendering_buffer buf_; + pixfmt_comp_type pixf_; + renderer_base renb_; + Rasterizer & ras_; + image_data_32 const& src_; + agg::trans_affine const& marker_trans_; + markers_symbolizer const& sym_; + Detector & detector_; + double scale_factor_; +}; + + +template +void agg_renderer::process(markers_symbolizer const& sym, + feature_impl & feature, + proj_transform const& prj_trans) +{ + typedef agg::rgba8 color_type; + typedef agg::order_rgba order_type; + typedef agg::pixel32_type pixel_type; + typedef agg::comp_op_adaptor_rgba_pre blender_type; // comp blender + typedef agg::pixfmt_custom_blend_rgba pixfmt_comp_type; + typedef agg::renderer_base renderer_base; + typedef agg::renderer_scanline_aa_solid renderer_type; + typedef label_collision_detector4 detector_type; + typedef boost::mpl::vector conv_types; std::string filename = path_processor_type::evaluate(*sym.get_filename(), feature); - marker_placement_e placement_method = sym.get_marker_placement(); if (!filename.empty()) { boost::optional mark = mapnik::marker_cache::instance()->find(filename, true); if (mark && *mark) { - if (!(*mark)->is_vector()) + ras_ptr->reset(); + ras_ptr->gamma(agg::gamma_power()); + + agg::trans_affine geom_tr; + evaluate_transform(geom_tr, feature, sym.get_transform()); + + box2d const& bbox = (*mark)->bounding_box(); + agg::trans_affine tr; + setup_label_transform(tr, bbox, feature, sym); + tr = agg::trans_affine_scaling(scale_factor_) * tr; + coord2d center = bbox.center(); + agg::trans_affine_translation recenter(-center.x, -center.y); + agg::trans_affine marker_trans = recenter * tr; + + if ((*mark)->is_vector()) { - MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: markers_symbolizer does not yet support non-SVG markers"; + using namespace mapnik::svg; + boost::optional marker = (*mark)->get_vector_data(); - return; - } - boost::optional marker = (*mark)->get_vector_data(); - box2d const& bbox = (*marker)->bounding_box(); - coord2d const center = bbox.center(); - agg::trans_affine_translation const recenter(-center.x, -center.y); - agg::trans_affine const marker_trans = recenter * tr; + vertex_stl_adapter stl_storage((*marker)->source()); + svg_path_adapter svg_path(stl_storage); - using namespace mapnik::svg; - vertex_stl_adapter stl_storage((*marker)->source()); - svg_path_adapter svg_path(stl_storage); + agg::pod_bvector attributes; + bool result = push_explicit_style( (*marker)->attributes(), attributes, sym); - svg_renderer, - renderer_type, - agg::pixfmt_rgba32 > svg_renderer(svg_path,(*marker)->attributes()); + typedef svg_renderer, + renderer_type, + agg::pixfmt_rgba32 > svg_renderer_type; + typedef vector_markers_rasterizer_dispatch dispatch_type; - for (unsigned i=0; iattributes()); + + dispatch_type rasterizer_dispatch(*current_buffer_,svg_renderer,*ras_ptr, + bbox, marker_trans, sym, *detector_, scale_factor_); + + + vertex_converter, dispatch_type, markers_symbolizer, + CoordTransform, proj_transform, agg::trans_affine, conv_types> + converter(query_extent_* 1.1,rasterizer_dispatch, sym,t_,prj_trans,tr,scale_factor_); + + if (sym.clip()) converter.template set(); //optional clip (default: true) + converter.template set(); //always transform + if (sym.smooth() > 0.0) converter.template set(); // optional smooth converter + + BOOST_FOREACH(geometry_type & geom, feature.paths()) { - double x; - double y; - double z=0; - geom.label_interior_position(&x, &y); - prj_trans.backward(x,y,z); - t_.forward(&x,&y); - geom_tr.transform(&x,&y); - agg::trans_affine matrix = marker_trans; - matrix.translate(x,y); - box2d transformed_bbox = bbox * matrix; - - if (sym.get_allow_overlap() || - detector_->has_placement(transformed_bbox)) - { - svg_renderer.render(*ras_ptr, sl, renb, matrix, sym.get_opacity(), bbox); - if (/* DEBUG */ 0) - { - debug_draw_box(buf, transformed_bbox, 0, 0, 0.0); - } - - if (!sym.get_ignore_placement()) - detector_->insert(transformed_bbox); - } + converter.apply(geom); } - else - { - clipped_geometry_type clipped(geom); - clipped.clip_box(query_extent_.minx(),query_extent_.miny(),query_extent_.maxx(),query_extent_.maxy()); - path_type path(t_,clipped,prj_trans); - transformed_path_type path_transformed(path,geom_tr); - markers_placement placement(path_transformed, bbox, marker_trans, *detector_, - sym.get_spacing() * scale_factor_, - sym.get_max_error(), - sym.get_allow_overlap()); - double x, y, angle; - while (placement.get_point(x, y, angle)) - { - agg::trans_affine matrix = marker_trans; - matrix.rotate(angle); - matrix.translate(x, y); - svg_renderer.render(*ras_ptr, sl, renb, matrix, sym.get_opacity(), bbox); + } + else // raster markers + { + boost::optional marker = (*mark)->get_bitmap_data(); + typedef raster_markers_rasterizer_dispatch dispatch_type; + dispatch_type rasterizer_dispatch(*current_buffer_,*ras_ptr, **marker, + marker_trans, sym, *detector_, scale_factor_); + vertex_converter, dispatch_type, markers_symbolizer, + CoordTransform, proj_transform, agg::trans_affine, conv_types> + converter(query_extent_* 1.1, rasterizer_dispatch, sym,t_,prj_trans,tr,scale_factor_); - if (/* DEBUG */ 0) - { - debug_draw_box(buf, bbox*matrix, 0, 0, 0.0); - } - } + if (sym.clip()) converter.template set(); //optional clip (default: true) + converter.template set(); //always transform + if (sym.smooth() > 0.0) converter.template set(); // optional smooth converter + + BOOST_FOREACH(geometry_type & geom, feature.paths()) + { + converter.apply(geom); } } } } } - template void agg_renderer::process(markers_symbolizer const&, mapnik::feature_impl &, proj_transform const&); diff --git a/src/agg/process_point_symbolizer.cpp b/src/agg/process_point_symbolizer.cpp index 22395799f..aac4355a2 100644 --- a/src/agg/process_point_symbolizer.cpp +++ b/src/agg/process_point_symbolizer.cpp @@ -23,6 +23,7 @@ // mapnik #include #include +#include #include #include #include @@ -64,14 +65,14 @@ void agg_renderer::process(point_symbolizer const& sym, if (marker) { box2d const& bbox = (*marker)->bounding_box(); - coord2d const center = bbox.center(); + coord2d center = bbox.center(); agg::trans_affine tr; evaluate_transform(tr, feature, sym.get_image_transform()); tr = agg::trans_affine_scaling(scale_factor_) * tr; - agg::trans_affine_translation const recenter(-center.x, -center.y); - agg::trans_affine const recenter_tr = recenter * tr; + agg::trans_affine_translation recenter(-center.x, -center.y); + agg::trans_affine recenter_tr = recenter * tr; box2d label_ext = bbox * recenter_tr; for (unsigned i=0; i::process(point_symbolizer const& sym, double y; double z=0; if (sym.get_point_placement() == CENTROID_POINT_PLACEMENT) - geom.label_position(&x, &y); + label::centroid(geom, x, y); else - geom.label_interior_position(&x, &y); + label::interior_position(geom ,x, y); prj_trans.backward(x,y,z); t_.forward(&x,&y); @@ -93,7 +94,11 @@ void agg_renderer::process(point_symbolizer const& sym, detector_->has_placement(label_ext)) { - render_marker(pixel_position(x, y), **marker, tr, sym.get_opacity(), sym.comp_op()); + render_marker(pixel_position(x, y), + **marker, + tr, + sym.get_opacity(), + sym.comp_op()); if (/* DEBUG */ 0) { debug_draw_box(label_ext, 0, 0, 0.0); @@ -114,4 +119,3 @@ template void agg_renderer::process(point_symbolizer const&, proj_transform const&); } - diff --git a/src/agg/process_polygon_pattern_symbolizer.cpp b/src/agg/process_polygon_pattern_symbolizer.cpp index f567db071..2a5ec53d3 100644 --- a/src/agg/process_polygon_pattern_symbolizer.cpp +++ b/src/agg/process_polygon_pattern_symbolizer.cpp @@ -151,7 +151,7 @@ void agg_renderer::process(polygon_pattern_symbolizer const& sym, BOOST_FOREACH( geometry_type & geom, feature.paths()) { - if (geom.num_points() > 2) + if (geom.size() > 2) { converter.apply(geom); } diff --git a/src/agg/process_polygon_symbolizer.cpp b/src/agg/process_polygon_symbolizer.cpp index 9f5047162..2b1266659 100644 --- a/src/agg/process_polygon_symbolizer.cpp +++ b/src/agg/process_polygon_symbolizer.cpp @@ -65,7 +65,7 @@ void agg_renderer::process(polygon_symbolizer const& sym, BOOST_FOREACH( geometry_type & geom, feature.paths()) { - if (geom.num_points() > 2) + if (geom.size() > 2) { converter.apply(geom); } diff --git a/src/agg/process_raster_symbolizer.cpp b/src/agg/process_raster_symbolizer.cpp index ccf2c3d65..ec4fdc97a 100644 --- a/src/agg/process_raster_symbolizer.cpp +++ b/src/agg/process_raster_symbolizer.cpp @@ -22,6 +22,7 @@ // mapnik #include +#include #include #include #include @@ -44,7 +45,7 @@ void agg_renderer::process(raster_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { - raster_ptr const& source=feature.get_raster(); + raster_ptr const& source = feature.get_raster(); if (source) { // If there's a colorizer defined, use it to color the raster in-place @@ -54,28 +55,44 @@ void agg_renderer::process(raster_symbolizer const& sym, box2d target_ext = box2d(source->ext_); prj_trans.backward(target_ext, PROJ_ENVELOPE_POINTS); - - box2d ext=t_.forward(target_ext); - int start_x = (int)ext.minx(); - int start_y = (int)ext.miny(); - int end_x = (int)ceil(ext.maxx()); - int end_y = (int)ceil(ext.maxy()); + box2d ext = t_.forward(target_ext); + int start_x = static_cast(ext.minx()); + int start_y = static_cast(ext.miny()); + int end_x = static_cast(ceil(ext.maxx())); + int end_y = static_cast(ceil(ext.maxy())); int raster_width = end_x - start_x; int raster_height = end_y - start_y; - double err_offs_x = ext.minx() - start_x; - double err_offs_y = ext.miny() - start_y; - if (raster_width > 0 && raster_height > 0) { image_data_32 target_data(raster_width,raster_height); raster target(target_ext, target_data); - - reproject_raster(target, *source, prj_trans, err_offs_x, err_offs_y, - sym.get_mesh_size(), - sym.calculate_filter_factor(), - scale_factor_, - sym.get_scaling()); - + scaling_method_e scaling_method = sym.get_scaling_method(); + double filter_radius = sym.calculate_filter_factor(); + double offset_x = ext.minx() - start_x; + double offset_y = ext.miny() - start_y; + if (!prj_trans.equal()) + { + reproject_and_scale_raster(target, *source, prj_trans, + offset_x, offset_y, + sym.get_mesh_size(), + filter_radius, + scaling_method); + } + else + { + if (scaling_method == SCALING_BILINEAR8){ + scale_image_bilinear8(target.data_,source->data_, offset_x, offset_y); + } else { + double scaling_ratio = ext.width() / source->data_.width(); + scale_image_agg(target.data_, + source->data_, + scaling_method, + scaling_ratio, + offset_x, + offset_y, + filter_radius); + } + } composite(current_buffer_->data(), target.data_, sym.comp_op(), sym.get_opacity(), start_x, start_y, true); } } diff --git a/src/agg/process_shield_symbolizer.cpp b/src/agg/process_shield_symbolizer.cpp index b900c3bca..f33381f0b 100644 --- a/src/agg/process_shield_symbolizer.cpp +++ b/src/agg/process_shield_symbolizer.cpp @@ -42,9 +42,10 @@ void agg_renderer::process(shield_symbolizer const& sym, shield_symbolizer_helper, label_collision_detector4> helper( sym, feature, prj_trans, - detector_->extent().width(), detector_->extent().height(), + width_, height_, scale_factor_, - t_, font_manager_, *detector_, query_extent_); + t_, font_manager_, *detector_, + query_extent_); text_renderer ren(*current_buffer_, font_manager_, @@ -52,8 +53,9 @@ void agg_renderer::process(shield_symbolizer const& sym, sym.comp_op(), scale_factor_); - while (helper.next()) { - placements_type &placements = helper.placements(); + while (helper.next()) + { + placements_type const& placements = helper.placements(); for (unsigned int ii = 0; ii < placements.size(); ++ii) { // get_marker_position returns (minx,miny) corner position, @@ -70,7 +72,7 @@ void agg_renderer::process(shield_symbolizer const& sym, sym.get_opacity(), sym.comp_op()); - ren.prepare_glyphs(&(placements[ii])); + ren.prepare_glyphs(placements[ii]); ren.render(placements[ii].center); } } diff --git a/src/agg/process_text_symbolizer.cpp b/src/agg/process_text_symbolizer.cpp index 52ed7a823..7bd1fbe77 100644 --- a/src/agg/process_text_symbolizer.cpp +++ b/src/agg/process_text_symbolizer.cpp @@ -35,9 +35,10 @@ void agg_renderer::process(text_symbolizer const& sym, text_symbolizer_helper, label_collision_detector4> helper( sym, feature, prj_trans, - detector_->extent().width(), detector_->extent().height(), + width_,height_, scale_factor_, - t_, font_manager_, *detector_, query_extent_); + t_, font_manager_, *detector_, + query_extent_); text_renderer ren(*current_buffer_, font_manager_, @@ -47,10 +48,10 @@ void agg_renderer::process(text_symbolizer const& sym, while (helper.next()) { - placements_type &placements = helper.placements(); + placements_type const& placements = helper.placements(); for (unsigned int ii = 0; ii < placements.size(); ++ii) { - ren.prepare_glyphs(&(placements[ii])); + ren.prepare_glyphs(placements[ii]); ren.render(placements[ii].center); } } diff --git a/src/arrow.cpp b/src/arrow.cpp deleted file mode 100644 index 5cd0ff4e1..000000000 --- a/src/arrow.cpp +++ /dev/null @@ -1,64 +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 - * - *****************************************************************************/ - -#include - -#include - -namespace mapnik { - -arrow::arrow() - : pos_(0) -{ - x_[0] = -7.0; y_[0] = 1.0; cmd_[0] = agg::path_cmd_move_to; - x_[1] = 1.0; y_[1] = 1.0; cmd_[1] = agg::path_cmd_line_to; - x_[2] = 1.0; y_[2] = 3.0; cmd_[2] = agg::path_cmd_line_to; - x_[3] = 7.0; y_[3] = 0.0; cmd_[3] = agg::path_cmd_line_to; - x_[4] = 1.0; y_[4] =-3.0; cmd_[4] = agg::path_cmd_line_to; - x_[5] = 1.0; y_[5] =-1.0; cmd_[5] = agg::path_cmd_line_to; - x_[6] = -7.0; y_[6] =-1.0; cmd_[6] = agg::path_cmd_line_to; - cmd_[7] = agg::path_cmd_end_poly | agg::path_flags_close | agg::path_flags_ccw; - cmd_[8] = agg::path_cmd_stop; -} - -void arrow::rewind(unsigned ) -{ - pos_ = 0; -} - -unsigned arrow::vertex(double* x, double* y) -{ - if(pos_ < 7 ) - { - *x = x_[pos_]; - *y = y_[pos_]; - return cmd_[pos_++]; - } - return agg::path_cmd_stop; -} - -box2d arrow::extent() const -{ - return box2d(-7,-3,7,3); -} -} - diff --git a/src/build.py b/src/build.py index f34a067d8..cf75e6b20 100644 --- a/src/build.py +++ b/src/build.py @@ -103,13 +103,17 @@ source = Split( color.cpp conversions.cpp image_compositing.cpp + image_scaling.cpp box2d.cpp building_symbolizer.cpp datasource_cache.cpp debug.cpp deepcopy.cpp + expression_node.cpp + expression_grammar.cpp expression_string.cpp expression.cpp + transform_expression_grammar.cpp transform_expression.cpp feature_kv_iterator.cpp feature_type_style.cpp @@ -140,6 +144,7 @@ source = Split( text_symbolizer.cpp tiff_reader.cpp wkb.cpp + wkb_generator.cpp projection.cpp proj_transform.cpp distance.cpp @@ -148,7 +153,6 @@ source = Split( stroke.cpp symbolizer.cpp symbolizer_helpers.cpp - arrow.cpp unicode.cpp markers_symbolizer.cpp metawriter.cpp @@ -163,6 +167,7 @@ source = Split( svg_points_parser.cpp svg_transform_parser.cpp warp.cpp + json/feature_grammar.cpp json/feature_collection_parser.cpp json/geojson_generator.cpp markers_placement.cpp diff --git a/src/cairo_renderer.cpp b/src/cairo_renderer.cpp index b7aa80f7f..e8120444d 100644 --- a/src/cairo_renderer.cpp +++ b/src/cairo_renderer.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -684,9 +683,10 @@ public: context_->glyph_path(glyphs); } - void add_text(text_path & path, + void add_text(text_path const& path, cairo_face_manager & manager, - face_manager &font_manager) + face_manager &font_manager, + double scale_factor = 1.0) { double sx = path.center.x; double sy = path.center.y; @@ -701,7 +701,7 @@ public: path.vertex(&c, &x, &y, &angle); face_set_ptr faces = font_manager.get_face_set(c->format->face_name, c->format->fontset); - float text_size = c->format->text_size; + float text_size = c->format->text_size * scale_factor; faces->set_character_sizes(text_size); glyph_ptr glyph = faces->get_glyph(c->c); @@ -722,7 +722,7 @@ public: set_font_face(manager, glyph->get_face()); glyph_path(glyph->get_index(), sx + x, sy - y); - set_line_width(c->format->halo_radius); + set_line_width(c->format->halo_radius * scale_factor); set_line_join(ROUND_JOIN); set_color(c->format->halo_fill); stroke(); @@ -737,9 +737,16 @@ private: Cairo::RefPtr context_; }; -cairo_renderer_base::cairo_renderer_base(Map const& m, Cairo::RefPtr const& context, unsigned offset_x, unsigned offset_y) +cairo_renderer_base::cairo_renderer_base(Map const& m, + Cairo::RefPtr const& context, + double scale_factor, + unsigned offset_x, + unsigned offset_y) : m_(m), context_(context), + width_(m.width()), + height_(m.height()), + scale_factor_(scale_factor), t_(m.width(),m.height(),m.get_current_extent(),offset_x,offset_y), font_engine_(boost::make_shared()), font_manager_(*font_engine_), @@ -750,18 +757,14 @@ cairo_renderer_base::cairo_renderer_base(Map const& m, Cairo::RefPtr -cairo_renderer::cairo_renderer(Map const& m, Cairo::RefPtr const& context, unsigned offset_x, unsigned offset_y) - : feature_style_processor(m), - cairo_renderer_base(m,context,offset_x,offset_y) -{ -} +cairo_renderer::cairo_renderer(Map const& m, Cairo::RefPtr const& context, double scale_factor, unsigned offset_x, unsigned offset_y) + : feature_style_processor(m,scale_factor), + cairo_renderer_base(m,context,scale_factor,offset_x,offset_y) {} template <> -cairo_renderer::cairo_renderer(Map const& m, Cairo::RefPtr const& surface, unsigned offset_x, unsigned offset_y) - : feature_style_processor(m), - cairo_renderer_base(m,Cairo::Context::create(surface),offset_x,offset_y) -{ -} +cairo_renderer::cairo_renderer(Map const& m, Cairo::RefPtr const& surface, double scale_factor, unsigned offset_x, unsigned offset_y) + : feature_style_processor(m,scale_factor), + cairo_renderer_base(m,Cairo::Context::create(surface),scale_factor,offset_x,offset_y) {} cairo_renderer_base::~cairo_renderer_base() {} @@ -851,7 +854,7 @@ void cairo_renderer_base::process(polygon_symbolizer const& sym, BOOST_FOREACH( geometry_type & geom, feature.paths()) { - if (geom.num_points() > 2) + if (geom.size() > 2) { converter.apply(geom); } @@ -874,14 +877,14 @@ void cairo_renderer_base::process(building_symbolizer const& sym, if (height_expr) { value_type result = boost::apply_visitor(evaluate(feature), *height_expr); - height = result.to_double(); //scale_factor is always 1.0 atm + height = result.to_double() * scale_factor_; } for (unsigned i = 0; i < feature.num_geometries(); ++i) { geometry_type const& geom = feature.get_geometry(i); - if (geom.num_points() > 2) + if (geom.size() > 2) { boost::scoped_ptr frame(new geometry_type(LineString)); boost::scoped_ptr roof(new geometry_type(Polygon)); @@ -892,7 +895,7 @@ void cairo_renderer_base::process(building_symbolizer const& sym, geom.rewind(0); unsigned cm = geom.vertex(&x0, &y0); - for (unsigned j = 1; j < geom.num_points(); ++j) + for (unsigned j = 1; j < geom.size(); ++j) { double x=0; double y=0; @@ -939,7 +942,7 @@ void cairo_renderer_base::process(building_symbolizer const& sym, } geom.rewind(0); - for (unsigned j = 0; j < geom.num_points(); ++j) + for (unsigned j = 0; j < geom.size(); ++j) { double x, y; unsigned cm = geom.vertex(&x, &y); @@ -981,7 +984,7 @@ void cairo_renderer_base::process(line_symbolizer const& sym, context.set_line_join(stroke_.get_line_join()); context.set_line_cap(stroke_.get_line_cap()); context.set_miter_limit(stroke_.get_miterlimit()); - context.set_line_width(stroke_.get_width()); + context.set_line_width(stroke_.get_width() * scale_factor_); if (stroke_.has_dash()) { context.set_dash(stroke_.get_dash_array()); @@ -994,7 +997,7 @@ void cairo_renderer_base::process(line_symbolizer const& sym, typedef boost::mpl::vector conv_types; vertex_converter, cairo_context, line_symbolizer, CoordTransform, proj_transform, agg::trans_affine, conv_types> - converter(ext,context,sym,t_,prj_trans,tr,1.0); + converter(ext,context,sym,t_,prj_trans,tr,scale_factor_); if (sym.clip()) converter.set(); // optional clip (default: true) converter.set(); // always transform @@ -1005,7 +1008,7 @@ void cairo_renderer_base::process(line_symbolizer const& sym, BOOST_FOREACH( geometry_type & geom, feature.paths()) { - if (geom.num_points() > 1) + if (geom.size() > 1) { converter.apply(geom); } @@ -1079,14 +1082,14 @@ void cairo_renderer_base::render_marker(pixel_position const& pos, marker const& } if(attr.fill_gradient.get_gradient_type() != NO_GRADIENT) { - cairo_gradient g(attr.fill_gradient,attr.opacity*opacity); + cairo_gradient g(attr.fill_gradient,attr.fill_opacity*opacity); context.set_gradient(g,bbox); context.fill(); } else if(attr.fill_flag) { - double fill_opacity = attr.opacity * opacity * attr.fill_color.opacity(); + double fill_opacity = attr.fill_opacity * opacity * attr.fill_color.opacity(); context.set_color(attr.fill_color.r,attr.fill_color.g,attr.fill_color.b, fill_opacity); context.fill(); } @@ -1101,13 +1104,13 @@ void cairo_renderer_base::render_marker(pixel_position const& pos, marker const& context.set_line_cap(line_cap_enum(attr.line_cap)); context.set_line_join(line_join_enum(attr.line_join)); context.set_miter_limit(attr.miter_limit); - cairo_gradient g(attr.stroke_gradient,attr.opacity*opacity); + cairo_gradient g(attr.stroke_gradient,attr.fill_opacity*opacity); context.set_gradient(g,bbox); context.stroke(); } else if (attr.stroke_flag) { - double stroke_opacity = attr.opacity * opacity * attr.stroke_color.opacity(); + double stroke_opacity = attr.stroke_opacity * opacity * attr.stroke_color.opacity(); context.set_color(attr.stroke_color.r,attr.stroke_color.g,attr.stroke_color.b, stroke_opacity); context.set_line_width(attr.stroke_width); context.set_line_cap(line_cap_enum(attr.line_cap)); @@ -1155,9 +1158,9 @@ void cairo_renderer_base::process(point_symbolizer const& sym, double z = 0; if (sym.get_point_placement() == CENTROID_POINT_PLACEMENT) - geom.label_position(&x, &y); + label::centroid(geom, x, y); else - geom.label_interior_position(&x, &y); + label::interior_position(geom, x, y); prj_trans.backward(x, y, z); t_.forward(&x, &y); @@ -1185,24 +1188,24 @@ void cairo_renderer_base::process(shield_symbolizer const& sym, proj_transform const& prj_trans) { shield_symbolizer_helper, - label_collision_detector4> helper( - sym, feature, prj_trans, - detector_.extent().width(), detector_.extent().height(), - 1.0 /*scale_factor*/, - t_, font_manager_, detector_, query_extent_); + label_collision_detector4> helper( + sym, feature, prj_trans, + width_, height_, + scale_factor_, + t_, font_manager_, detector_, query_extent_); cairo_context context(context_); context.set_operator(sym.comp_op()); while (helper.next()) { - placements_type &placements = helper.placements(); + placements_type const& placements = helper.placements(); for (unsigned int ii = 0; ii < placements.size(); ++ii) { pixel_position marker_pos = helper.get_marker_position(placements[ii]); render_marker(marker_pos, helper.get_marker(), helper.get_image_transform(), sym.get_opacity()); - context.add_text(placements[ii], face_manager_, font_manager_); + context.add_text(placements[ii], face_manager_, font_manager_, scale_factor_); } } } @@ -1227,13 +1230,13 @@ void cairo_renderer_base::process(line_pattern_symbolizer const& sym, pattern.set_extend(Cairo::EXTEND_REPEAT); pattern.set_filter(Cairo::FILTER_BILINEAR); - context.set_line_width(height); + context.set_line_width(height * scale_factor_); for (unsigned i = 0; i < feature.num_geometries(); ++i) { geometry_type & geom = feature.get_geometry(i); - if (geom.num_points() > 1) + if (geom.size() > 1) { clipped_geometry_type clipped(geom); clipped.clip_box(query_extent_.minx(),query_extent_.miny(),query_extent_.maxx(),query_extent_.maxy()); @@ -1313,7 +1316,7 @@ void cairo_renderer_base::process(polygon_pattern_symbolizer const& sym, BOOST_FOREACH( geometry_type & geom, feature.paths()) { - if (geom.num_points() > 2) + if (geom.size() > 2) { converter.apply(geom); } @@ -1337,32 +1340,46 @@ void cairo_renderer_base::process(raster_symbolizer const& sym, box2d target_ext = box2d(source->ext_); prj_trans.backward(target_ext, PROJ_ENVELOPE_POINTS); - - box2d ext=t_.forward(target_ext); - int start_x = (int)ext.minx(); - int start_y = (int)ext.miny(); - int end_x = (int)ceil(ext.maxx()); - int end_y = (int)ceil(ext.maxy()); + box2d ext = t_.forward(target_ext); + int start_x = static_cast(ext.minx()); + int start_y = static_cast(ext.miny()); + int end_x = static_cast(ceil(ext.maxx())); + int end_y = static_cast(ceil(ext.maxy())); int raster_width = end_x - start_x; int raster_height = end_y - start_y; - double err_offs_x = ext.minx() - start_x; - double err_offs_y = ext.miny() - start_y; - if (raster_width > 0 && raster_height > 0) { - double scale_factor = ext.width() / source->data_.width(); image_data_32 target_data(raster_width,raster_height); raster target(target_ext, target_data); - - reproject_raster(target, *source, prj_trans, err_offs_x, err_offs_y, - sym.get_mesh_size(), - sym.calculate_filter_factor(), - scale_factor, - sym.get_scaling()); - + scaling_method_e scaling_method = sym.get_scaling_method(); + double filter_radius = sym.calculate_filter_factor(); + double offset_x = ext.minx() - start_x; + double offset_y = ext.miny() - start_y; + if (!prj_trans.equal()) + { + reproject_and_scale_raster(target, *source, prj_trans, + offset_x, offset_y, + sym.get_mesh_size(), + filter_radius, + scaling_method); + } + else + { + if (scaling_method == SCALING_BILINEAR8){ + scale_image_bilinear8(target.data_,source->data_, offset_x, offset_y); + } else { + double scaling_ratio = ext.width() / source->data_.width(); + scale_image_agg(target.data_, + source->data_, + scaling_method, + scaling_ratio, + offset_x, + offset_y, + filter_radius); + } + } cairo_context context(context_); context.set_operator(sym.comp_op()); - //TODO -- support for advanced image merging context.add_image(start_x, start_y, target.data_, sym.get_opacity()); } } @@ -1374,14 +1391,14 @@ void cairo_renderer_base::process(markers_symbolizer const& sym, { cairo_context context(context_); context.set_operator(sym.comp_op()); - double scale_factor_ = 1; + //double scale_factor_ = 1; typedef agg::conv_clip_polyline clipped_geometry_type; typedef coord_transform path_type; agg::trans_affine tr; evaluate_transform(tr, feature, sym.get_image_transform()); - + tr = agg::trans_affine_scaling(scale_factor_) * tr; std::string filename = path_processor_type::evaluate(*sym.get_filename(), feature); marker_placement_e placement_method = sym.get_marker_placement(); @@ -1416,12 +1433,12 @@ void cairo_renderer_base::process(markers_symbolizer const& sym, { geometry_type & geom = feature.get_geometry(i); // TODO - merge this code with point_symbolizer rendering - if (placement_method == MARKER_POINT_PLACEMENT || geom.num_points() <= 1) + if (placement_method == MARKER_POINT_PLACEMENT || geom.size() <= 1) { double x; double y; double z=0; - geom.label_interior_position(&x, &y); + label::interior_position(geom, x, y); prj_trans.backward(x,y,z); t_.forward(&x,&y); extent.re_center(x,y); @@ -1431,9 +1448,8 @@ void cairo_renderer_base::process(markers_symbolizer const& sym, { render_marker(pixel_position(x - 0.5 * w, y - 0.5 * h) ,**mark, tr, sym.get_opacity()); - // TODO - impl this for markers? - //if (!sym.get_ignore_placement()) - // detector_.insert(label_ext); + if (!sym.get_ignore_placement()) + detector_.insert(extent); } } else @@ -1462,16 +1478,22 @@ void cairo_renderer_base::process(text_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { - text_symbolizer_helper, label_collision_detector4> helper(sym, feature, prj_trans, detector_.extent().width(), detector_.extent().height(), 1.0 /*scale_factor*/, t_, font_manager_, detector_, query_extent_); + text_symbolizer_helper, + label_collision_detector4> helper( + sym, feature, prj_trans, + width_, height_, + scale_factor_, + t_, font_manager_, detector_, query_extent_); cairo_context context(context_); context.set_operator(sym.comp_op()); - while (helper.next()) { - placements_type &placements = helper.placements(); + while (helper.next()) + { + placements_type const& placements = helper.placements(); for (unsigned int ii = 0; ii < placements.size(); ++ii) { - context.add_text(placements[ii], face_manager_, font_manager_); + context.add_text(placements[ii], face_manager_, font_manager_, scale_factor_); } } } @@ -1480,4 +1502,4 @@ template class cairo_renderer; template class cairo_renderer; } -#endif +#endif // HAVE_CAIRO diff --git a/src/expression_grammar.cpp b/src/expression_grammar.cpp new file mode 100644 index 000000000..fcc2575f8 --- /dev/null +++ b/src/expression_grammar.cpp @@ -0,0 +1,174 @@ +/***************************************************************************** + * + * 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 + * + *****************************************************************************/ + +#include + +namespace mapnik +{ + +template +expr_node regex_match_impl::operator() (T0 & node, T1 const& pattern) const +{ +#if defined(BOOST_REGEX_HAS_ICU) + return regex_match_node(node,tr_.transcode(pattern.c_str())); +#else + return regex_match_node(node,pattern); +#endif +} + +template +expr_node regex_replace_impl::operator() (T0 & node, T1 const& pattern, T2 const& format) const +{ +#if defined(BOOST_REGEX_HAS_ICU) + return regex_replace_node(node,tr_.transcode(pattern.c_str()),tr_.transcode(format.c_str())); +#else + return regex_replace_node(node,pattern,format); +#endif +} + +template +expression_grammar::expression_grammar(mapnik::transcoder const& tr) + : expression_grammar::base_type(expr), + unicode_(unicode_impl(tr)), + regex_match_(regex_match_impl(tr)), + regex_replace_(regex_replace_impl(tr)) +{ + using boost::phoenix::construct; + using qi::_1; + using qi::_a; + using qi::_b; + using qi::_r1; +#if BOOST_VERSION > 104200 + using qi::no_skip; +#endif + using qi::lexeme; + using qi::_val; + using qi::lit; + using qi::int_; + using qi::double_; + using qi::hex; + using qi::omit; + using standard_wide::char_; + using standard_wide::no_case; + expr = logical_expr.alias(); + + logical_expr = not_expr [_val = _1] + >> + *( ( ( lit("and") | lit("&&")) >> not_expr [_val && _1] ) + | (( lit("or") | lit("||")) >> not_expr [_val || _1]) + ) + ; + + not_expr = + cond_expr [_val = _1 ] + | ((lit("not") | lit('!')) >> cond_expr [ _val = !_1 ]) + ; + + cond_expr = equality_expr [_val = _1] | additive_expr [_val = _1] + ; + + equality_expr = + relational_expr [_val = _1] + >> *( ( (lit("=") | lit("eq") | lit("is")) >> relational_expr [_val == _1]) + | (( lit("!=") | lit("<>") | lit("neq") ) >> relational_expr [_val != _1]) + ) + ; + + regex_match_expr = lit(".match") + >> lit('(') + >> ustring [_val = _1] + >> lit(')') + ; + + regex_replace_expr = + lit(".replace") + >> lit('(') + >> ustring [_a = _1] + >> lit(',') + >> ustring [_b = _1] + >> lit(')') [_val = regex_replace_(_r1,_a,_b)] + ; + + relational_expr = additive_expr[_val = _1] + >> + *( ( (lit("<=") | lit("le") ) >> additive_expr [ _val <= _1 ]) + | ( (lit('<') | lit("lt") ) >> additive_expr [ _val < _1 ]) + | ( (lit(">=") | lit("ge") ) >> additive_expr [ _val >= _1 ]) + | ( (lit('>') | lit("gt") ) >> additive_expr [ _val > _1 ]) + ) + ; + + additive_expr = multiplicative_expr [_val = _1] + >> * ( '+' >> multiplicative_expr[_val += _1] + | '-' >> multiplicative_expr[_val -= _1] + ) + ; + + multiplicative_expr = unary_expr [_val = _1] + >> *( '*' >> unary_expr [_val *= _1] + | '/' >> unary_expr [_val /= _1] + | '%' >> unary_expr [_val %= _1] + | regex_match_expr[_val = regex_match_(_val, _1)] + | regex_replace_expr(_val) [_val = _1] + ) + ; + + unary_expr = primary_expr [_val = _1] + | '+' >> primary_expr [_val = _1] + | '-' >> primary_expr [_val = -_1] + ; + + primary_expr = strict_double [_val = _1] + | int_ [_val = _1] + | no_case[lit("true")] [_val = true] + | no_case[lit("false")] [_val = false] + | no_case[lit("null")] [_val = value_null() ] + | no_case[geom_type][_val = _1 ] + | ustring [_val = unicode_(_1) ] + | lit("[mapnik::geometry_type]")[_val = construct()] + | attr [_val = construct( _1 ) ] + | '(' >> expr [_val = _1 ] >> ')' + ; + + unesc_char.add("\\a", '\a')("\\b", '\b')("\\f", '\f')("\\n", '\n') + ("\\r", '\r')("\\t", '\t')("\\v", '\v')("\\\\", '\\') + ("\\\'", '\'')("\\\"", '\"') + ; + +#if BOOST_VERSION > 104500 + quote_char %= char_('\'') | char_('"'); + ustring %= omit[quote_char[_a = _1]] + >> *(unesc_char | "\\x" >> hex | (char_ - lit(_a))) + >> lit(_a); + attr %= '[' >> no_skip[+~char_(']')] >> ']'; +#else + ustring %= lit('\'') + >> *(unesc_char | "\\x" >> hex | (char_ - lit('\''))) + >> lit('\''); + attr %= '[' >> lexeme[+(char_ - ']')] >> ']'; +#endif + +} + +template struct mapnik::expression_grammar; + +} \ No newline at end of file diff --git a/include/mapnik/arrow.hpp b/src/expression_node.cpp similarity index 55% rename from include/mapnik/arrow.hpp rename to src/expression_node.cpp index 0391228a5..5c997044d 100644 --- a/include/mapnik/arrow.hpp +++ b/src/expression_node.cpp @@ -2,7 +2,7 @@ * * This file is part of Mapnik (c++ mapping toolkit) * - * Copyright (C) 2011 Artem Pavlenko + * 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 @@ -20,26 +20,33 @@ * *****************************************************************************/ -#ifndef MAPNIK_ARROW_HPP -#define MAPNIK_ARROW_HPP +#include -#include - -namespace mapnik { - -class arrow +namespace mapnik { -public: - arrow(); - void rewind(unsigned path_id); - unsigned vertex(double* x, double* y); - box2d extent() const; -private: - unsigned pos_; - double x_[7]; - double y_[7]; - unsigned cmd_[9]; -}; -} -#endif // MAPNIK_ARROW_HPP +#if defined(BOOST_REGEX_HAS_ICU) + +regex_match_node::regex_match_node (expr_node const& a, UnicodeString const& ustr) + : expr(a), + pattern(boost::make_u32regex(ustr)) {} + +regex_replace_node::regex_replace_node (expr_node const& a, UnicodeString const& ustr, UnicodeString const& f) + : expr(a), + pattern(boost::make_u32regex(ustr)), + format(f) {} + +#else +regex_match_node::pattern boost::regex; + +regex_match_node::regex_match_node (expr_node const& a, std::string const& str) + : expr(a), + pattern(str) {} + +regex_replace_node::regex_replace_node (expr_node const& a, std::string const& str, std::string const& f) + : expr(a), + pattern(str), + format(f) {} +#endif + +} \ No newline at end of file diff --git a/src/expression_string.cpp b/src/expression_string.cpp index 231e7a5d5..87a082af8 100644 --- a/src/expression_string.cpp +++ b/src/expression_string.cpp @@ -50,6 +50,11 @@ struct expression_string : boost::static_visitor str_ += "]"; } + void operator() (geometry_type_attribute const& attr) const + { + str_ += "[mapnik::geometry_type]"; + } + template void operator() (binary_node const& x) const { diff --git a/src/font_engine_freetype.cpp b/src/font_engine_freetype.cpp index 418684cbb..94eb77248 100644 --- a/src/font_engine_freetype.cpp +++ b/src/font_engine_freetype.cpp @@ -327,7 +327,7 @@ text_renderer::text_renderer (pixmap_type & pixmap, scale_factor_(scale_factor) {} template -box2d text_renderer::prepare_glyphs(text_path *path) +box2d text_renderer::prepare_glyphs(text_path const& path) { //clear glyphs glyphs_.clear(); @@ -340,12 +340,12 @@ box2d text_renderer::prepare_glyphs(text_path *path) bbox.xMin = bbox.yMin = 32000; // Initialize these so we can tell if we bbox.xMax = bbox.yMax = -32000; // properly grew the bbox later - for (int i = 0; i < path->num_nodes(); i++) + for (int i = 0; i < path.num_nodes(); i++) { char_info_ptr c; double x, y, angle; - path->vertex(&c, &x, &y, &angle); + path.vertex(&c, &x, &y, &angle); // TODO Enable when we have support for setting verbosity // MAPNIK_LOG_DEBUG(font_engine_freetype) << "text_renderer: prepare_glyphs=" @@ -531,9 +531,9 @@ boost::mutex freetype_engine::mutex_; std::map > freetype_engine::name2file_; template void text_renderer::render(pixel_position); template text_renderer::text_renderer(image_32&, face_manager&, stroker&, composite_mode_e, double); -template box2dtext_renderer::prepare_glyphs(text_path*); +template box2dtext_renderer::prepare_glyphs(text_path const&); template void text_renderer::render_id(int, pixel_position, double ); template text_renderer::text_renderer(grid&, face_manager&, stroker&, composite_mode_e, double); -template box2dtext_renderer::prepare_glyphs(text_path*); +template box2dtext_renderer::prepare_glyphs(text_path const& ); } diff --git a/src/grid/grid.cpp b/src/grid/grid.cpp index ade783a7b..9d870379a 100644 --- a/src/grid/grid.cpp +++ b/src/grid/grid.cpp @@ -26,6 +26,106 @@ namespace mapnik { -template<> const grid::value_type grid::base_mask = std::numeric_limits::min(); +template +const typename hit_grid::value_type hit_grid::base_mask = std::numeric_limits::min(); + +template +hit_grid::hit_grid(int width, int height, std::string const& key, unsigned int resolution) + : width_(width), + height_(height), + key_(key), + data_(width,height), + resolution_(resolution), + id_name_("__id__"), + painted_(false), + names_(), + f_keys_(), + features_(), + ctx_(boost::make_shared()) + { + f_keys_[base_mask] = ""; + data_.set(base_mask); + } + +template +hit_grid::hit_grid(hit_grid const& rhs) + : width_(rhs.width_), + height_(rhs.height_), + key_(rhs.key_), + data_(rhs.data_), + resolution_(rhs.resolution_), + id_name_("__id__"), + painted_(rhs.painted_), + names_(rhs.names_), + f_keys_(rhs.f_keys_), + features_(rhs.features_), + ctx_(rhs.ctx_) + { + f_keys_[base_mask] = ""; + data_.set(base_mask); + } + +template +void hit_grid::add_feature(mapnik::feature_impl & feature) +{ + int feature_id = feature.id(); + // avoid adding duplicate features (e.g. in the case of both a line symbolizer and a polygon symbolizer) + typename feature_key_type::const_iterator feature_pos = f_keys_.find(feature_id); + if (feature_pos != f_keys_.end()) + { + return; + } + + if (ctx_->size() == 0) { + context_type::map_type::const_iterator itr = feature.context()->begin(); + context_type::map_type::const_iterator end = feature.context()->end(); + for ( ;itr!=end; ++itr) + { + ctx_->add(itr->first,itr->second); + } + } + // NOTE: currently lookup keys must be strings, + // but this should be revisited + lookup_type lookup_value; + if (key_ == id_name_) + { + mapnik::util::to_string(lookup_value,feature_id); + } + else + { + if (feature.has_key(key_)) + { + lookup_value = feature.get(key_).to_string(); + } + else + { + MAPNIK_LOG_DEBUG(grid) << "hit_grid: Should not get here: key '" << key_ << "' not found in feature properties"; + } + } + + if (!lookup_value.empty()) + { + // TODO - consider shortcutting f_keys if feature_id == lookup_value + // create a mapping between the pixel id and the feature key + f_keys_.insert(std::make_pair(feature_id,lookup_value)); + // if extra fields have been supplied, push them into grid memory + if (!names_.empty()) + { + // it is ~ 2x faster to copy feature attributes compared + // to building up a in-memory cache of feature_ptrs + // https://github.com/mapnik/mapnik/issues/1198 + mapnik::feature_ptr feature2(mapnik::feature_factory::create(ctx_,feature_id)); + feature2->set_data(feature.get_data()); + features_.insert(std::make_pair(lookup_value,feature2)); + } + } + else + { + MAPNIK_LOG_DEBUG(grid) << "hit_grid: Warning - key '" << key_ << "' was blank for " << feature; + } +} + + +template class hit_grid; } diff --git a/src/grid/grid_renderer.cpp b/src/grid/grid_renderer.cpp index 6f58c9754..fdbe834dd 100644 --- a/src/grid/grid_renderer.cpp +++ b/src/grid/grid_renderer.cpp @@ -91,6 +91,7 @@ void grid_renderer::start_layer_processing(layer const& lay, box2d co { detector_.clear(); } + query_extent_ = query_extent; } template @@ -100,7 +101,7 @@ void grid_renderer::end_layer_processing(layer const&) } template -void grid_renderer::render_marker(mapnik::feature_impl & feature, unsigned int step, pixel_position const& pos, marker const& marker, agg::trans_affine const& tr, double opacity) +void grid_renderer::render_marker(mapnik::feature_impl & feature, unsigned int step, pixel_position const& pos, marker const& marker, agg::trans_affine const& tr, double opacity, composite_mode_e comp_op) { if (marker.is_vector()) { @@ -125,7 +126,7 @@ void grid_renderer::render_marker(mapnik::feature_impl & feature, unsigned in mtx *= tr; mtx *= agg::trans_affine_scaling(scale_factor_*(1.0/step)); // render the marker at the center of the marker box - mtx.translate(pos.x+0.5 * marker.width(), pos.y+0.5 * marker.height()); + mtx.translate(pos.x, pos.y); using namespace mapnik::svg; vertex_stl_adapter stl_storage((*marker.get_vector_data())->source()); svg_path_adapter svg_path(stl_storage); diff --git a/src/grid/process_building_symbolizer.cpp b/src/grid/process_building_symbolizer.cpp index e09d17218..d89898d37 100644 --- a/src/grid/process_building_symbolizer.cpp +++ b/src/grid/process_building_symbolizer.cpp @@ -70,7 +70,7 @@ void grid_renderer::process(building_symbolizer const& sym, for (unsigned i=0;i 2) + if (geom.size() > 2) { boost::scoped_ptr frame(new geometry_type(LineString)); boost::scoped_ptr roof(new geometry_type(Polygon)); @@ -78,7 +78,7 @@ void grid_renderer::process(building_symbolizer const& sym, double x0(0); double y0(0); unsigned cm = geom.vertex(&x0,&y0); - for (unsigned j=1;j::process(building_symbolizer const& sym, } geom.rewind(0); - for (unsigned j=0;j::process(line_pattern_symbolizer const& sym, for (unsigned i=0;i 1) + if (geom.size() > 1) { path_type path(t_,geom,prj_trans); agg::conv_stroke stroke(path); diff --git a/src/grid/process_line_symbolizer.cpp b/src/grid/process_line_symbolizer.cpp index 606d0a31a..debb189e9 100644 --- a/src/grid/process_line_symbolizer.cpp +++ b/src/grid/process_line_symbolizer.cpp @@ -27,6 +27,7 @@ #include #include #include +#include // agg #include "agg_rasterizer_scanline_aa.h" @@ -35,6 +36,9 @@ #include "agg_conv_stroke.h" #include "agg_conv_dash.h" +// boost +#include + // stl #include @@ -60,76 +64,29 @@ void grid_renderer::process(line_symbolizer const& sym, stroke const& stroke_ = sym.get_stroke(); - for (unsigned i=0;i ext = query_extent_ * 1.1; + + typedef boost::mpl::vector conv_types; + vertex_converter, grid_rasterizer, line_symbolizer, + CoordTransform, proj_transform, agg::trans_affine, conv_types> + converter(ext,*ras_ptr,sym,t_,prj_trans,tr,scale_factor_); + + if (sym.clip()) converter.set(); // optional clip (default: true) + converter.set(); // always transform + if (fabs(sym.offset()) > 0.0) converter.set(); // parallel offset + converter.set(); // optional affine transform + if (sym.smooth() > 0.0) converter.set(); // optional smooth converter + if (stroke_.has_dash()) converter.set(); + converter.set(); //always stroke + + BOOST_FOREACH( geometry_type & geom, feature.paths()) { - geometry_type & geom = feature.get_geometry(i); - if (geom.num_points() > 1) + if (geom.size() > 1) { - path_type path(t_,geom,prj_trans); - - if (stroke_.has_dash()) - { - agg::conv_dash dash(path); - dash_array const& d = stroke_.get_dash_array(); - dash_array::const_iterator itr = d.begin(); - dash_array::const_iterator end = d.end(); - for (;itr != end;++itr) - { - dash.add_dash(itr->first * scale_factor_, - itr->second * scale_factor_); - } - - agg::conv_stroke > stroke(dash); - - line_join_e join=stroke_.get_line_join(); - if ( join == MITER_JOIN) - stroke.generator().line_join(agg::miter_join); - else if( join == MITER_REVERT_JOIN) - stroke.generator().line_join(agg::miter_join); - else if( join == ROUND_JOIN) - stroke.generator().line_join(agg::round_join); - else - stroke.generator().line_join(agg::bevel_join); - - line_cap_e cap=stroke_.get_line_cap(); - if (cap == BUTT_CAP) - stroke.generator().line_cap(agg::butt_cap); - else if (cap == SQUARE_CAP) - stroke.generator().line_cap(agg::square_cap); - else - stroke.generator().line_cap(agg::round_cap); - - stroke.generator().miter_limit(stroke_.get_miterlimit()); - stroke.generator().width(stroke_.get_width() * scale_factor_); - - ras_ptr->add_path(stroke); - - } - else - { - agg::conv_stroke stroke(path); - line_join_e join=stroke_.get_line_join(); - if ( join == MITER_JOIN) - stroke.generator().line_join(agg::miter_join); - else if( join == MITER_REVERT_JOIN) - stroke.generator().line_join(agg::miter_join); - else if( join == ROUND_JOIN) - stroke.generator().line_join(agg::round_join); - else - stroke.generator().line_join(agg::bevel_join); - - line_cap_e cap=stroke_.get_line_cap(); - if (cap == BUTT_CAP) - stroke.generator().line_cap(agg::butt_cap); - else if (cap == SQUARE_CAP) - stroke.generator().line_cap(agg::square_cap); - else - stroke.generator().line_cap(agg::round_cap); - - stroke.generator().miter_limit(stroke_.get_miterlimit()); - stroke.generator().width(stroke_.get_width() * scale_factor_); - ras_ptr->add_path(stroke); - } + converter.apply(geom); } } diff --git a/src/grid/process_markers_symbolizer.cpp b/src/grid/process_markers_symbolizer.cpp index fd89b7b16..c3a81468d 100644 --- a/src/grid/process_markers_symbolizer.cpp +++ b/src/grid/process_markers_symbolizer.cpp @@ -28,21 +28,27 @@ #include #include #include +#include +#include #include #include #include #include #include #include -#include // agg +#include "agg_basics.h" +#include "agg_rendering_buffer.h" +#include "agg_pixfmt_rgba.h" #include "agg_rasterizer_scanline_aa.h" -#include "agg_renderer_scanline.h" -#include "agg_scanline_bin.h" +#include "agg_scanline_u.h" #include "agg_path_storage.h" -#include "agg_ellipse.h" -#include "agg_conv_stroke.h" +#include "agg_conv_clip_polyline.h" +#include "agg_conv_transform.h" + +// boost +#include // stl #include @@ -55,97 +61,139 @@ void grid_renderer::process(markers_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { - typedef coord_transform path_type; - typedef agg::renderer_base ren_base; - typedef agg::renderer_scanline_bin_solid renderer; - agg::scanline_bin sl; + typedef agg::renderer_base renderer_base; + typedef agg::renderer_scanline_bin_solid renderer_type; - grid_rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_); - mapnik::pixfmt_gray32 pixf(buf); - - ren_base renb(pixf); - renderer ren(renb); - - ras_ptr->reset(); - - agg::trans_affine tr; - evaluate_transform(tr, feature, sym.get_image_transform()); - unsigned int res = pixmap_.get_resolution(); - tr = agg::trans_affine_scaling(scale_factor_*(1.0/res)) * tr; std::string filename = path_processor_type::evaluate(*sym.get_filename(), feature); - marker_placement_e placement_method = sym.get_marker_placement(); if (!filename.empty()) { boost::optional mark = mapnik::marker_cache::instance()->find(filename, true); - if (mark && *mark && (*mark)->is_vector()) + if (mark && *mark) { + if (!(*mark)->is_vector()) + { + MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: markers_symbolizer does not yet support non-SVG markers"; + return; + } + + ras_ptr->reset(); + agg::scanline_bin sl; + grid_rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_); + mapnik::pixfmt_gray32 pixf(buf); + renderer_base renb(pixf); + renderer_type ren(renb); + + agg::trans_affine geom_tr; + evaluate_transform(geom_tr, feature, sym.get_transform()); + boost::optional marker = (*mark)->get_vector_data(); box2d const& bbox = (*marker)->bounding_box(); - double x1 = bbox.minx(); - double y1 = bbox.miny(); - double x2 = bbox.maxx(); - double y2 = bbox.maxy(); - double w = (*mark)->width(); - double h = (*mark)->height(); - // clamp sizes - w = std::max(w,4.0); - h = std::max(w,4.0); - agg::trans_affine recenter = agg::trans_affine_translation(-0.5*(x1+x2),-0.5*(y1+y2)); - tr.transform(&x1,&y1); - tr.transform(&x2,&y2); - box2d extent(x1,y1,x2,y2); + agg::trans_affine tr; + setup_label_transform(tr, bbox, feature, sym); + // - clamp sizes to > 4 pixels of interactivity + if (tr.scale() < 0.5) + { + agg::trans_affine tr2; + tr2 *= agg::trans_affine_scaling(0.5); + tr = tr2; + } + tr *= agg::trans_affine_scaling(scale_factor_*(1.0/pixmap_.get_resolution())); + + coord2d center = bbox.center(); + agg::trans_affine_translation recenter(-center.x, -center.y); + agg::trans_affine marker_trans = recenter * tr; + using namespace mapnik::svg; vertex_stl_adapter stl_storage((*marker)->source()); svg_path_adapter svg_path(stl_storage); + + agg::pod_bvector attributes; + bool result = push_explicit_style( (*marker)->attributes(), attributes, sym); + svg_renderer, - renderer, - mapnik::pixfmt_gray32 > svg_renderer(svg_path,(*marker)->attributes()); + agg::pod_bvector, + renderer_type, + mapnik::pixfmt_gray32 > svg_renderer(svg_path, result ? attributes : (*marker)->attributes()); + + marker_placement_e placement_method = sym.get_marker_placement(); bool placed = false; - for (unsigned i=0; i transformed_bbox = bbox * matrix; if (sym.get_allow_overlap() || - detector_.has_placement(extent)) + detector_.has_placement(transformed_bbox)) { - - render_marker(feature, - pixmap_.get_resolution(), - pixel_position(x - 0.5 * w, y - 0.5 * h), - **mark, - tr, - sym.get_opacity()); + placed = true; + svg_renderer.render_id(*ras_ptr, sl, renb, feature.id(), matrix, sym.get_opacity(), bbox); + if (!sym.get_ignore_placement()) + detector_.insert(transformed_bbox); } } - - path_type path(t_,geom,prj_trans); - markers_placement placement(path, bbox, recenter, detector_, - sym.get_spacing() * scale_factor_, - sym.get_max_error(), - sym.get_allow_overlap()); - double x, y, angle; - while (placement.get_point(x, y, angle)) + else if (sym.clip()) { - placed = true; - agg::trans_affine matrix = recenter * tr *agg::trans_affine_rotation(angle) * agg::trans_affine_translation(x, y); - svg_renderer.render_id(*ras_ptr, sl, renb, feature.id(), matrix, sym.get_opacity(),bbox); + typedef agg::conv_clip_polyline clipped_geometry_type; + typedef coord_transform path_type; + typedef agg::conv_transform transformed_path_type; + + clipped_geometry_type clipped(geom); + clipped.clip_box(query_extent_.minx(),query_extent_.miny(),query_extent_.maxx(),query_extent_.maxy()); + path_type path(t_,clipped,prj_trans); + transformed_path_type path_transformed(path,geom_tr); + markers_placement placement(path_transformed, bbox, marker_trans, detector_, + sym.get_spacing() * scale_factor_, + sym.get_max_error(), + sym.get_allow_overlap()); + double x, y, angle; + while (placement.get_point(x, y, angle)) + { + placed = true; + agg::trans_affine matrix = marker_trans; + matrix.rotate(angle); + matrix.translate(x, y); + svg_renderer.render_id(*ras_ptr, sl, renb, feature.id(), matrix, sym.get_opacity(), bbox); + } + } + else + { + typedef coord_transform path_type; + typedef agg::conv_transform transformed_path_type; + path_type path(t_,geom,prj_trans); + transformed_path_type path_transformed(path,geom_tr); + markers_placement placement(path_transformed, bbox, marker_trans, detector_, + sym.get_spacing() * scale_factor_, + sym.get_max_error(), + sym.get_allow_overlap()); + double x, y, angle; + while (placement.get_point(x, y, angle)) + { + placed = true; + agg::trans_affine matrix = marker_trans; + matrix.rotate(angle); + matrix.translate(x, y); + svg_renderer.render_id(*ras_ptr, sl, renb, feature.id(), matrix, sym.get_opacity(), bbox); + } } } if (placed) + { pixmap_.add_feature(feature); + } } } } diff --git a/src/grid/process_point_symbolizer.cpp b/src/grid/process_point_symbolizer.cpp index b7e60b916..d1689f03b 100644 --- a/src/grid/process_point_symbolizer.cpp +++ b/src/grid/process_point_symbolizer.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -55,43 +56,48 @@ void grid_renderer::process(point_symbolizer const& sym, if (marker) { + box2d const& bbox = (*marker)->bounding_box(); + coord2d const center = bbox.center(); + agg::trans_affine tr; evaluate_transform(tr, feature, sym.get_image_transform()); + tr = agg::trans_affine_scaling(scale_factor_) * tr; + + agg::trans_affine_translation const recenter(-center.x, -center.y); + agg::trans_affine const recenter_tr = recenter * tr; + box2d label_ext = bbox * recenter_tr; for (unsigned i=0; iwidth() * (1.0/pixmap_.get_resolution()); - double h = (*marker)->height() * (1.0/pixmap_.get_resolution()); - - double px = x - 0.5 * w; - double py = y - 0.5 * h; - box2d label_ext (px, py, px + w, py + h); + label_ext.re_center(x,y); if (sym.get_allow_overlap() || detector_.has_placement(label_ext)) { - render_marker(feature, pixmap_.get_resolution(), - pixel_position(px, py), - **marker, tr, - sym.get_opacity()); + + render_marker(feature, + pixmap_.get_resolution(), + pixel_position(x, y), + **marker, + tr, + sym.get_opacity(), + sym.comp_op()); if (!sym.get_ignore_placement()) detector_.insert(label_ext); } } } - } template void grid_renderer::process(point_symbolizer const&, @@ -99,4 +105,3 @@ template void grid_renderer::process(point_symbolizer const&, proj_transform const&); } - diff --git a/src/grid/process_polygon_pattern_symbolizer.cpp b/src/grid/process_polygon_pattern_symbolizer.cpp index 154a24103..aae06ff45 100644 --- a/src/grid/process_polygon_pattern_symbolizer.cpp +++ b/src/grid/process_polygon_pattern_symbolizer.cpp @@ -60,7 +60,7 @@ void grid_renderer::process(polygon_pattern_symbolizer const& sym, for (unsigned i=0;i 2) + if (geom.size() > 2) { path_type path(t_,geom,prj_trans); ras_ptr->add_path(path); diff --git a/src/grid/process_polygon_symbolizer.cpp b/src/grid/process_polygon_symbolizer.cpp index 68d5f1ae9..355e493b3 100644 --- a/src/grid/process_polygon_symbolizer.cpp +++ b/src/grid/process_polygon_symbolizer.cpp @@ -20,6 +20,9 @@ * *****************************************************************************/ +// boost +#include + // mapnik #include #include @@ -27,6 +30,7 @@ #include #include #include +#include // agg #include "agg_rasterizer_scanline_aa.h" @@ -44,10 +48,34 @@ void grid_renderer::process(polygon_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { - typedef coord_transform path_type; + ras_ptr->reset(); + + box2d inflated_extent = query_extent_ * 1.0; + + agg::trans_affine tr; + evaluate_transform(tr, feature, sym.get_transform()); + + typedef boost::mpl::vector conv_types; + vertex_converter, grid_rasterizer, polygon_symbolizer, + CoordTransform, proj_transform, agg::trans_affine, conv_types> + converter(inflated_extent,*ras_ptr,sym,t_,prj_trans,tr,scale_factor_); + + if (sym.clip()) converter.set(); //optional clip (default: true) + converter.set(); //always transform + converter.set(); + if (sym.smooth() > 0.0) converter.set(); // optional smooth converter + + + BOOST_FOREACH( geometry_type & geom, feature.paths()) + { + if (geom.size() > 2) + { + converter.apply(geom); + } + } + typedef agg::renderer_base ren_base; typedef agg::renderer_scanline_bin_solid renderer; - agg::scanline_bin sl; grid_rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_); mapnik::pixfmt_gray32 pixf(buf); @@ -55,19 +83,9 @@ void grid_renderer::process(polygon_symbolizer const& sym, ren_base renb(pixf); renderer ren(renb); - ras_ptr->reset(); - for (unsigned i=0;i 2) - { - path_type path(t_,geom,prj_trans); - ras_ptr->add_path(path); - } - } - // render id ren.color(mapnik::gray32(feature.id())); + agg::scanline_bin sl; agg::render_scanlines(*ras_ptr, sl, ren); // add feature properties to grid cache diff --git a/src/grid/process_shield_symbolizer.cpp b/src/grid/process_shield_symbolizer.cpp index 820e9b31b..e57266509 100644 --- a/src/grid/process_shield_symbolizer.cpp +++ b/src/grid/process_shield_symbolizer.cpp @@ -41,14 +41,13 @@ void grid_renderer::process(shield_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { - box2d query_extent; shield_symbolizer_helper, label_collision_detector4> helper( sym, feature, prj_trans, width_, height_, scale_factor_, - t_, font_manager_, detector_, query_extent); - + t_, font_manager_, detector_, + query_extent_); bool placement_found = false; text_renderer ren(pixmap_, @@ -58,17 +57,29 @@ void grid_renderer::process(shield_symbolizer const& sym, scale_factor_); text_placement_info_ptr placement; - while (helper.next()) { + while (helper.next()) + { placement_found = true; - placements_type &placements = helper.placements(); + placements_type const& placements = helper.placements(); for (unsigned int ii = 0; ii < placements.size(); ++ii) { - render_marker(feature, pixmap_.get_resolution(), - helper.get_marker_position(placements[ii]), - helper.get_marker(), helper.get_image_transform(), - sym.get_opacity()); + // get_marker_position returns (minx,miny) corner position, + // while (currently only) agg_renderer::render_marker newly + // expects center position; + // until all renderers and shield_symbolizer_helper are + // modified accordingly, we must adjust the position here + pixel_position pos = helper.get_marker_position(placements[ii]); + pos.x += 0.5 * helper.get_marker_width(); + pos.y += 0.5 * helper.get_marker_height(); + render_marker(feature, + pixmap_.get_resolution(), + pos, + helper.get_marker(), + helper.get_image_transform(), + sym.get_opacity(), + sym.comp_op()); - ren.prepare_glyphs(&(placements[ii])); + ren.prepare_glyphs(placements[ii]); ren.render_id(feature.id(), placements[ii].center, 2); } } diff --git a/src/grid/process_text_symbolizer.cpp b/src/grid/process_text_symbolizer.cpp index 41c7881f4..22e6e7d18 100644 --- a/src/grid/process_text_symbolizer.cpp +++ b/src/grid/process_text_symbolizer.cpp @@ -31,14 +31,13 @@ void grid_renderer::process(text_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { - box2d query_extent; text_symbolizer_helper, label_collision_detector4> helper( sym, feature, prj_trans, - detector_.extent().width(), detector_.extent().height(), + width_, height_, scale_factor_ * (1.0/pixmap_.get_resolution()), t_, font_manager_, detector_, - query_extent); + query_extent_); bool placement_found = false; text_renderer ren(pixmap_, @@ -49,10 +48,10 @@ void grid_renderer::process(text_symbolizer const& sym, while (helper.next()) { placement_found = true; - placements_type &placements = helper.placements(); + placements_type const& placements = helper.placements(); for (unsigned int ii = 0; ii < placements.size(); ++ii) { - ren.prepare_glyphs(&(placements[ii])); + ren.prepare_glyphs(placements[ii]); ren.render_id(feature.id(), placements[ii].center, 2); } } diff --git a/src/image_compositing.cpp b/src/image_compositing.cpp index 8eff43bb5..e6c64100e 100644 --- a/src/image_compositing.cpp +++ b/src/image_compositing.cpp @@ -88,6 +88,17 @@ boost::optional comp_op_from_string(std::string const& name) return mode; } +boost::optional comp_op_to_string(composite_mode_e comp_op) +{ + boost::optional mode; + comp_op_lookup_type::left_const_iterator left_iter = comp_lookup.left.find(comp_op); + if (left_iter != comp_lookup.left.end()) + { + mode.reset(left_iter->second); + } + return mode; +} + template void composite(T1 & dst, T2 & src, composite_mode_e mode, float opacity, diff --git a/src/image_scaling.cpp b/src/image_scaling.cpp new file mode 100644 index 000000000..2e5961751 --- /dev/null +++ b/src/image_scaling.cpp @@ -0,0 +1,360 @@ +/***************************************************************************** + * + * 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 + * + *****************************************************************************/ + +// mapnik +#include +#include +#include + +// boost +#include +#include + +// agg +#include "agg_image_accessors.h" +#include "agg_pixfmt_rgba.h" +#include "agg_rasterizer_scanline_aa.h" +#include "agg_renderer_scanline.h" +#include "agg_rendering_buffer.h" +#include "agg_scanline_u.h" +#include "agg_span_allocator.h" +#include "agg_span_image_filter_rgba.h" +#include "agg_span_interpolator_linear.h" +#include "agg_trans_affine.h" +#include "agg_image_filters.h" + +namespace mapnik +{ + +typedef boost::bimap scaling_method_lookup_type; +static const scaling_method_lookup_type scaling_lookup = boost::assign::list_of + (SCALING_NEAR,"near") + (SCALING_BILINEAR,"bilinear") + (SCALING_BICUBIC,"bicubic") + (SCALING_SPLINE16,"spline16") + (SCALING_SPLINE36,"spline36") + (SCALING_HANNING,"hanning") + (SCALING_HAMMING,"hamming") + (SCALING_HERMITE,"hermite") + (SCALING_KAISER,"kaiser") + (SCALING_QUADRIC,"quadric") + (SCALING_CATROM,"catrom") + (SCALING_GAUSSIAN,"gaussian") + (SCALING_BESSEL,"bessel") + (SCALING_MITCHELL,"mitchell") + (SCALING_SINC,"sinc") + (SCALING_LANCZOS,"lanczos") + (SCALING_BLACKMAN,"blackman") + (SCALING_BILINEAR8,"bilinear8") + ; + +boost::optional scaling_method_from_string(std::string const& name) +{ + boost::optional mode; + scaling_method_lookup_type::right_const_iterator right_iter = scaling_lookup.right.find(name); + if (right_iter != scaling_lookup.right.end()) + { + mode.reset(right_iter->second); + } + return mode; +} + +boost::optional scaling_method_to_string(scaling_method_e scaling_method) +{ + boost::optional mode; + scaling_method_lookup_type::left_const_iterator left_iter = scaling_lookup.left.find(scaling_method); + if (left_iter != scaling_lookup.left.end()) + { + mode.reset(left_iter->second); + } + return mode; +} + +// this has been replaced by agg impl - see https://trac.mapnik.org/ticket/656 +template +void scale_image_bilinear_old (Image & target,Image const& source, double x_off_f, double y_off_f) +{ + + int source_width=source.width(); + int source_height=source.height(); + + int target_width=target.width(); + int target_height=target.height(); + + if (source_width<1 || source_height<1 || + target_width<1 || target_height<1) return; + int x=0,y=0,xs=0,ys=0; + int tw2 = target_width/2; + int th2 = target_height/2; + int offs_x = rint((source_width-target_width-x_off_f*2*source_width)/2); + int offs_y = rint((source_height-target_height-y_off_f*2*source_height)/2); + unsigned yprt, yprt1, xprt, xprt1; + + //no scaling or subpixel offset + if (target_height == source_height && target_width == source_width && offs_x == 0 && offs_y == 0){ + for (y=0;y=source_height) + ys1--; + if (ys<0) + ys=ys1=0; + if (source_height/2=source_width) + xs1--; + if (xs<0) + xs=xs1=0; + + unsigned a = source(xs,ys); + unsigned b = source(xs1,ys); + unsigned c = source(xs,ys1); + unsigned d = source(xs1,ys1); + unsigned out=0; + unsigned t = 0; + + for(int i=0; i<4; i++){ + unsigned p,r,s; + // X axis + p = a&0xff; + r = b&0xff; + if (p!=r) + r = (r*xprt+p*xprt1+tw2)/target_width; + p = c&0xff; + s = d&0xff; + if (p!=s) + s = (s*xprt+p*xprt1+tw2)/target_width; + // Y axis + if (r!=s) + r = (s*yprt+r*yprt1+th2)/target_height; + // channel up + out |= r << t; + t += 8; + a >>= 8; + b >>= 8; + c >>= 8; + d >>= 8; + } + target(x,y)=out; + } + } +} + + +template +void scale_image_bilinear8 (Image & target,Image const& source, double x_off_f, double y_off_f) +{ + + int source_width=source.width(); + int source_height=source.height(); + + int target_width=target.width(); + int target_height=target.height(); + + if (source_width<1 || source_height<1 || + target_width<1 || target_height<1) return; + int x=0,y=0,xs=0,ys=0; + int tw2 = target_width/2; + int th2 = target_height/2; + int offs_x = rint((source_width-target_width-x_off_f*2*source_width)/2); + int offs_y = rint((source_height-target_height-y_off_f*2*source_height)/2); + unsigned yprt, yprt1, xprt, xprt1; + + //no scaling or subpixel offset + if (target_height == source_height && target_width == source_width && offs_x == 0 && offs_y == 0){ + for (y=0;y=source_height) + ys1--; + if (ys<0) + ys=ys1=0; + if (source_height/2=source_width) + xs1--; + if (xs<0) + xs=xs1=0; + + unsigned a = source(xs,ys); + unsigned b = source(xs1,ys); + unsigned c = source(xs,ys1); + unsigned d = source(xs1,ys1); + unsigned p,r,s; + // X axis + p = a&0xff; + r = b&0xff; + if (p!=r) + r = (r*xprt+p*xprt1+tw2)/target_width; + p = c&0xff; + s = d&0xff; + if (p!=s) + s = (s*xprt+p*xprt1+tw2)/target_width; + // Y axis + if (r!=s) + r = (s*yprt+r*yprt1+th2)/target_height; + target(x,y)=(0xff<<24) | (r<<16) | (r<<8) | r; + } + } +} + +template +void scale_image_agg(Image & target, + Image const& source, + scaling_method_e scaling_method, + double image_ratio, + double x_off_f, + double y_off_f, + double filter_radius, + double ratio) +{ + typedef agg::pixfmt_rgba32 pixfmt; + typedef agg::pixfmt_rgba32_pre pixfmt_pre; + typedef agg::renderer_base renderer_base; + + // define some stuff we'll use soon + agg::rasterizer_scanline_aa<> ras; + agg::scanline_u8 sl; + agg::span_allocator sa; + agg::image_filter_lut filter; + + // initialize source AGG buffer + agg::rendering_buffer rbuf_src((unsigned char*)source.getBytes(), source.width(), source.height(), source.width() * 4); + pixfmt pixf_src(rbuf_src); + typedef agg::image_accessor_clone img_src_type; + img_src_type img_src(pixf_src); + + // initialise destination AGG buffer (with transparency) + agg::rendering_buffer rbuf_dst((unsigned char*)target.getBytes(), target.width(), target.height(), target.width() * 4); + pixfmt_pre pixf_dst(rbuf_dst); + renderer_base rb_dst(pixf_dst); + rb_dst.clear(agg::rgba(0, 0, 0, 0)); + + // create a scaling matrix + agg::trans_affine img_mtx; + img_mtx /= agg::trans_affine_scaling(image_ratio * ratio, image_ratio * ratio); + + // create a linear interpolator for our scaling matrix + typedef agg::span_interpolator_linear<> interpolator_type; + interpolator_type interpolator(img_mtx); + + // draw an anticlockwise polygon to render our image into + double scaled_width = source.width() * image_ratio; + double scaled_height = source.height() * image_ratio; + ras.reset(); + ras.move_to_d(x_off_f, y_off_f); + ras.line_to_d(x_off_f + scaled_width, y_off_f); + ras.line_to_d(x_off_f + scaled_width, y_off_f + scaled_height); + ras.line_to_d(x_off_f, y_off_f + scaled_height); + + switch(scaling_method) + { + case SCALING_NEAR: + { + typedef agg::span_image_filter_rgba_nn span_gen_type; + span_gen_type sg(img_src, interpolator); + agg::render_scanlines_aa(ras, sl, rb_dst, sa, sg); + return; + } + case SCALING_BILINEAR: + case SCALING_BILINEAR8: + filter.calculate(agg::image_filter_bilinear(), true); break; + case SCALING_BICUBIC: + filter.calculate(agg::image_filter_bicubic(), true); break; + case SCALING_SPLINE16: + filter.calculate(agg::image_filter_spline16(), true); break; + case SCALING_SPLINE36: + filter.calculate(agg::image_filter_spline36(), true); break; + case SCALING_HANNING: + filter.calculate(agg::image_filter_hanning(), true); break; + case SCALING_HAMMING: + filter.calculate(agg::image_filter_hamming(), true); break; + case SCALING_HERMITE: + filter.calculate(agg::image_filter_hermite(), true); break; + case SCALING_KAISER: + filter.calculate(agg::image_filter_kaiser(), true); break; + case SCALING_QUADRIC: + filter.calculate(agg::image_filter_quadric(), true); break; + case SCALING_CATROM: + filter.calculate(agg::image_filter_catrom(), true); break; + case SCALING_GAUSSIAN: + filter.calculate(agg::image_filter_gaussian(), true); break; + case SCALING_BESSEL: + filter.calculate(agg::image_filter_bessel(), true); break; + case SCALING_MITCHELL: + filter.calculate(agg::image_filter_mitchell(), true); break; + case SCALING_SINC: + filter.calculate(agg::image_filter_sinc(filter_radius), true); break; + case SCALING_LANCZOS: + filter.calculate(agg::image_filter_lanczos(filter_radius), true); break; + case SCALING_BLACKMAN: + filter.calculate(agg::image_filter_blackman(filter_radius), true); break; + } + typedef mapnik::span_image_resample_rgba_affine span_gen_type; + span_gen_type sg(img_src, interpolator, filter); + agg::render_scanlines_aa(ras, sl, rb_dst, sa, sg); +} + +template void scale_image_agg (image_data_32& target,const image_data_32& source, scaling_method_e scaling_method, double scale_factor, double x_off_f, double y_off_f, double filter_radius, double ratio); + +template void scale_image_bilinear_old (image_data_32& target,const image_data_32& source, double x_off_f, double y_off_f); + +template void scale_image_bilinear8 (image_data_32& target,const image_data_32& source, double x_off_f, double y_off_f); + + +} diff --git a/src/image_util.cpp b/src/image_util.cpp index 11987af97..741e07eda 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -35,7 +35,6 @@ extern "C" #include #include #include -#include // jpeg #if defined(HAVE_JPEG) #include @@ -56,20 +55,6 @@ extern "C" #include #include -// agg -#include "agg_image_accessors.h" -#include "agg_pixfmt_rgba.h" -#include "agg_rasterizer_scanline_aa.h" -#include "agg_renderer_scanline.h" -#include "agg_rendering_buffer.h" -#include "agg_scanline_u.h" -//#include "agg_scanline_p.h" -#include "agg_span_allocator.h" -#include "agg_span_image_filter_rgba.h" -#include "agg_span_interpolator_linear.h" -#include "agg_trans_affine.h" -#include "agg_image_filters.h" - namespace mapnik { @@ -352,18 +337,19 @@ void save_to_file(T const& image, std::string const& filename, rgba_palette cons #if defined(HAVE_CAIRO) // TODO - move to separate cairo_io.hpp -void save_to_cairo_file(mapnik::Map const& map, std::string const& filename) +void save_to_cairo_file(mapnik::Map const& map, std::string const& filename, double scale_factor) { boost::optional type = type_from_filename(filename); if (type) { - save_to_cairo_file(map,filename,*type); + save_to_cairo_file(map,filename,*type,scale_factor); } } void save_to_cairo_file(mapnik::Map const& map, std::string const& filename, - std::string const& type) + std::string const& type, + double scale_factor) { std::ofstream file (filename.c_str(), std::ios::out|std::ios::trunc|std::ios::binary); if (file) @@ -417,7 +403,7 @@ void save_to_cairo_file(mapnik::Map const& map, */ - mapnik::cairo_renderer ren(map, context); + mapnik::cairo_renderer ren(map, context, scale_factor); ren.apply(); if (type == "ARGB32" || type == "RGB24") @@ -476,306 +462,6 @@ template std::string save_to_string > (image_view -void scale_image_bilinear_old (Image& target,const Image& source, double x_off_f, double y_off_f) -{ - - int source_width=source.width(); - int source_height=source.height(); - - int target_width=target.width(); - int target_height=target.height(); - - if (source_width<1 || source_height<1 || - target_width<1 || target_height<1) return; - int x=0,y=0,xs=0,ys=0; - int tw2 = target_width/2; - int th2 = target_height/2; - int offs_x = rint((source_width-target_width-x_off_f*2*source_width)/2); - int offs_y = rint((source_height-target_height-y_off_f*2*source_height)/2); - unsigned yprt, yprt1, xprt, xprt1; - - //no scaling or subpixel offset - if (target_height == source_height && target_width == source_width && offs_x == 0 && offs_y == 0){ - for (y=0;y=source_height) - ys1--; - if (ys<0) - ys=ys1=0; - if (source_height/2=source_width) - xs1--; - if (xs<0) - xs=xs1=0; - - unsigned a = source(xs,ys); - unsigned b = source(xs1,ys); - unsigned c = source(xs,ys1); - unsigned d = source(xs1,ys1); - unsigned out=0; - unsigned t = 0; - - for(int i=0; i<4; i++){ - unsigned p,r,s; - // X axis - p = a&0xff; - r = b&0xff; - if (p!=r) - r = (r*xprt+p*xprt1+tw2)/target_width; - p = c&0xff; - s = d&0xff; - if (p!=s) - s = (s*xprt+p*xprt1+tw2)/target_width; - // Y axis - if (r!=s) - r = (s*yprt+r*yprt1+th2)/target_height; - // channel up - out |= r << t; - t += 8; - a >>= 8; - b >>= 8; - c >>= 8; - d >>= 8; - } - target(x,y)=out; - } - } -} - - -template -void scale_image_bilinear8 (Image& target,const Image& source, double x_off_f, double y_off_f) -{ - - int source_width=source.width(); - int source_height=source.height(); - - int target_width=target.width(); - int target_height=target.height(); - - if (source_width<1 || source_height<1 || - target_width<1 || target_height<1) return; - int x=0,y=0,xs=0,ys=0; - int tw2 = target_width/2; - int th2 = target_height/2; - int offs_x = rint((source_width-target_width-x_off_f*2*source_width)/2); - int offs_y = rint((source_height-target_height-y_off_f*2*source_height)/2); - unsigned yprt, yprt1, xprt, xprt1; - - //no scaling or subpixel offset - if (target_height == source_height && target_width == source_width && offs_x == 0 && offs_y == 0){ - for (y=0;y=source_height) - ys1--; - if (ys<0) - ys=ys1=0; - if (source_height/2=source_width) - xs1--; - if (xs<0) - xs=xs1=0; - - unsigned a = source(xs,ys); - unsigned b = source(xs1,ys); - unsigned c = source(xs,ys1); - unsigned d = source(xs1,ys1); - unsigned p,r,s; - // X axis - p = a&0xff; - r = b&0xff; - if (p!=r) - r = (r*xprt+p*xprt1+tw2)/target_width; - p = c&0xff; - s = d&0xff; - if (p!=s) - s = (s*xprt+p*xprt1+tw2)/target_width; - // Y axis - if (r!=s) - r = (s*yprt+r*yprt1+th2)/target_height; - target(x,y)=(0xff<<24) | (r<<16) | (r<<8) | r; - } - } -} - -template -void scale_image_agg (Image& target,const Image& source, scaling_method_e scaling_method, double scale_factor, double x_off_f, double y_off_f, double filter_radius, double ratio) -{ - typedef agg::pixfmt_rgba32 pixfmt; - typedef agg::pixfmt_rgba32_pre pixfmt_pre; - typedef agg::renderer_base renderer_base; - - // define some stuff we'll use soon - agg::rasterizer_scanline_aa<> ras; - agg::scanline_u8 sl; - agg::span_allocator sa; - agg::image_filter_lut filter; - - // initialize source AGG buffer - agg::rendering_buffer rbuf_src((unsigned char*)source.getBytes(), source.width(), source.height(), source.width() * 4); - pixfmt pixf_src(rbuf_src); - typedef agg::image_accessor_clone img_src_type; - img_src_type img_src(pixf_src); - - // initialise destination AGG buffer (with transparency) - agg::rendering_buffer rbuf_dst((unsigned char*)target.getBytes(), target.width(), target.height(), target.width() * 4); - pixfmt_pre pixf_dst(rbuf_dst); - renderer_base rb_dst(pixf_dst); - rb_dst.clear(agg::rgba(0, 0, 0, 0)); - - // create a scaling matrix - agg::trans_affine img_mtx; - img_mtx /= agg::trans_affine_scaling(scale_factor * ratio, scale_factor * ratio); - - // create a linear interpolator for our scaling matrix - typedef agg::span_interpolator_linear<> interpolator_type; - interpolator_type interpolator(img_mtx); - - // draw an anticlockwise polygon to render our image into - double scaled_width = source.width() * scale_factor; - double scaled_height = source.height() * scale_factor; - ras.reset(); - ras.move_to_d(x_off_f, y_off_f); - ras.line_to_d(x_off_f + scaled_width, y_off_f); - ras.line_to_d(x_off_f + scaled_width, y_off_f + scaled_height); - ras.line_to_d(x_off_f, y_off_f + scaled_height); - - switch(scaling_method) - { - case SCALING_NEAR: - { - typedef agg::span_image_filter_rgba_nn span_gen_type; - span_gen_type sg(img_src, interpolator); - agg::render_scanlines_aa(ras, sl, rb_dst, sa, sg); - return; - } - case SCALING_BILINEAR: - filter.calculate(agg::image_filter_bilinear(), true); break; - case SCALING_BICUBIC: - filter.calculate(agg::image_filter_bicubic(), true); break; - case SCALING_SPLINE16: - filter.calculate(agg::image_filter_spline16(), true); break; - case SCALING_SPLINE36: - filter.calculate(agg::image_filter_spline36(), true); break; - case SCALING_HANNING: - filter.calculate(agg::image_filter_hanning(), true); break; - case SCALING_HAMMING: - filter.calculate(agg::image_filter_hamming(), true); break; - case SCALING_HERMITE: - filter.calculate(agg::image_filter_hermite(), true); break; - case SCALING_KAISER: - filter.calculate(agg::image_filter_kaiser(), true); break; - case SCALING_QUADRIC: - filter.calculate(agg::image_filter_quadric(), true); break; - case SCALING_CATROM: - filter.calculate(agg::image_filter_catrom(), true); break; - case SCALING_GAUSSIAN: - filter.calculate(agg::image_filter_gaussian(), true); break; - case SCALING_BESSEL: - filter.calculate(agg::image_filter_bessel(), true); break; - case SCALING_MITCHELL: - filter.calculate(agg::image_filter_mitchell(), true); break; - case SCALING_SINC: - filter.calculate(agg::image_filter_sinc(filter_radius), true); break; - case SCALING_LANCZOS: - filter.calculate(agg::image_filter_lanczos(filter_radius), true); break; - case SCALING_BLACKMAN: - filter.calculate(agg::image_filter_blackman(filter_radius), true); break; - } - typedef mapnik::span_image_resample_rgba_affine span_gen_type; - span_gen_type sg(img_src, interpolator, filter); - agg::render_scanlines_aa(ras, sl, rb_dst, sa, sg); -} - - void save_to_file(image_32 const& image,std::string const& file) { save_to_file(image.data(), file); @@ -809,10 +495,4 @@ std::string save_to_string(image_32 const& image, return save_to_string(image.data(), type, palette); } -template void scale_image_agg (image_data_32& target,const image_data_32& source, scaling_method_e scaling_method, double scale_factor, double x_off_f, double y_off_f, double filter_radius, double ratio); - -template void scale_image_bilinear_old (image_data_32& target,const image_data_32& source, double x_off_f, double y_off_f); - -template void scale_image_bilinear8 (image_data_32& target,const image_data_32& source, double x_off_f, double y_off_f); - } diff --git a/src/json/feature_grammar.cpp b/src/json/feature_grammar.cpp new file mode 100644 index 000000000..59be9386e --- /dev/null +++ b/src/json/feature_grammar.cpp @@ -0,0 +1,227 @@ +/***************************************************************************** + * + * 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 +#include + +// boost +#include + +namespace mapnik { namespace json { + +template +feature_grammar::feature_grammar(mapnik::transcoder const& tr) + : feature_grammar::base_type(feature,"feature"), + put_property_(put_property(tr)) +{ + using qi::lit; + using qi::int_; + using qi::double_; +#if BOOST_VERSION > 104200 + using qi::no_skip; +#else + using qi::lexeme; +#endif + using standard_wide::char_; + using qi::_val; + using qi::_1; + using qi::_2; + using qi::_3; + using qi::_4; + using qi::_a; + using qi::_b; + using qi::_r1; + using qi::_r2; + using qi::fail; + using qi::on_error; + using qi::_pass; + using qi::eps; + using qi::raw; + + using phoenix::new_; + using phoenix::push_back; + using phoenix::construct; + + // generic json types + value = object | array | string_ + | number + ; + + pairs = key_value % lit(',') + ; + + key_value = (string_ >> lit(':') >> value) + ; + + object = lit('{') + >> *pairs + >> lit('}') + ; + array = lit('[') + >> value >> *(lit(',') >> value) + >> lit(']') + ; + + number %= strict_double + | int_ + | lit("true") [_val = true] + | lit ("false") [_val = false] + | lit("null")[_val = construct()] + ; + + unesc_char.add + ("\\\"", '\"') // quotation mark + ("\\\\", '\\') // reverse solidus + ("\\/", '/') // solidus + ("\\b", '\b') // backspace + ("\\f", '\f') // formfeed + ("\\n", '\n') // newline + ("\\r", '\r') // carrige return + ("\\t", '\t') // tab + ; + + string_ %= lit('"') >> *(unesc_char | "\\u" >> hex4 | (char_ - lit('"'))) >> lit('"') + ; + + // geojson types + + feature_type = lit("\"type\"") + >> lit(':') + >> lit("\"Feature\"") + ; + + feature = lit('{') + >> (feature_type | (lit("\"geometry\"") > lit(':') > geometry(_r1)) | properties(_r1) | key_value) % lit(',') + >> lit('}') + ; + + properties = lit("\"properties\"") + >> lit(':') >> (lit('{') >> attributes(_r1) >> lit('}')) | lit("null") + ; + + attributes = (string_ [_a = _1] >> lit(':') >> attribute_value [put_property_(_r1,_a,_1)]) % lit(',') + ; + + attribute_value %= number | string_ ; + + // Nabialek trick - FIXME: how to bind argument to dispatch rule? + // geometry = lit("\"geometry\"") + // >> lit(':') >> lit('{') + // >> lit("\"type\"") >> lit(':') >> geometry_dispatch[_a = _1] + // >> lit(',') >> lit("\"coordinates\"") >> lit(':') + // >> qi::lazy(*_a) + // >> lit('}') + // ; + // geometry_dispatch.add + // ("\"Point\"",&point_coordinates) + // ("\"LineString\"",&linestring_coordinates) + // ("\"Polygon\"",&polygon_coordinates) + // ; + ////////////////////////////////////////////////////////////////// + + geometry = (lit('{')[_a = 0 ] + >> lit("\"type\"") >> lit(':') >> geometry_dispatch[_a = _1] // <---- should be Nabialek trick! + >> lit(',') + >> (lit("\"coordinates\"") > lit(':') > coordinates(_r1,_a) + | + lit("\"geometries\"") > lit(':') + >> lit('[') >> geometry_collection(_r1) >> lit(']')) + >> lit('}')) + | lit("null") + ; + + geometry_dispatch.add + ("\"Point\"",1) + ("\"LineString\"",2) + ("\"Polygon\"",3) + ("\"MultiPoint\"",4) + ("\"MultiLineString\"",5) + ("\"MultiPolygon\"",6) + ("\"GeometryCollection\"",7) + // + ; + + coordinates = (eps(_r2 == 1) > point_coordinates(extract_geometry_(_r1))) + | (eps(_r2 == 2) > linestring_coordinates(extract_geometry_(_r1))) + | (eps(_r2 == 3) > polygon_coordinates(extract_geometry_(_r1))) + | (eps(_r2 == 4) > multipoint_coordinates(extract_geometry_(_r1))) + | (eps(_r2 == 5) > multilinestring_coordinates(extract_geometry_(_r1))) + | (eps(_r2 == 6) > multipolygon_coordinates(extract_geometry_(_r1))) + ; + + point_coordinates = eps[ _a = new_(Point) ] + > ( point(SEG_MOVETO,_a) [push_back(_r1,_a)] | eps[cleanup_(_a)][_pass = false] ) + ; + + linestring_coordinates = eps[ _a = new_(LineString)] + > -(points(_a) [push_back(_r1,_a)] + | eps[cleanup_(_a)][_pass = false]) + ; + + polygon_coordinates = eps[ _a = new_(Polygon) ] + > ((lit('[') + > -(points(_a) % lit(',')) + > lit(']')) [push_back(_r1,_a)] + | eps[cleanup_(_a)][_pass = false]) + ; + + multipoint_coordinates = lit('[') + > -(point_coordinates(_r1) % lit(',')) + > lit(']') + ; + + multilinestring_coordinates = lit('[') + > -(linestring_coordinates(_r1) % lit(',')) + > lit(']') + ; + + multipolygon_coordinates = lit('[') + > -(polygon_coordinates(_r1) % lit(',')) + > lit(']') + ; + + geometry_collection = *geometry(_r1) >> *(lit(',') >> geometry(_r1)) + ; + + // point + point = lit('[') > -((double_ > lit(',') > double_)[push_vertex_(_r1,_r2,_1,_2)]) > lit(']'); + // points + points = lit('[')[_a = SEG_MOVETO] > -(point (_a,_r1) % lit(',')[_a = SEG_LINETO]) > lit(']'); + on_error + ( + feature + , std::clog + << phoenix::val("Error! Expecting ") + << _4 // what failed? + << phoenix::val(" here: \"") + << construct(_3, _2) // iterators to error-pos, end + << phoenix::val("\"") + << std::endl + ); + +} + +template struct mapnik::json::feature_grammar; +template struct mapnik::json::feature_grammar >,mapnik::Feature>; + +}} \ No newline at end of file diff --git a/src/load_map.cpp b/src/load_map.cpp index ad6f26c82..9a1183a89 100644 --- a/src/load_map.cpp +++ b/src/load_map.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -55,6 +56,7 @@ #include #include #include +#include // boost #include @@ -115,7 +117,7 @@ private: void parse_markers_symbolizer(rule & rule, xml_node const& sym); void parse_raster_colorizer(raster_colorizer_ptr const& rc, xml_node const& node); - void parse_stroke(stroke & strk, xml_node const & sym); + bool parse_stroke(stroke & strk, xml_node const & sym); void ensure_font_face(std::string const& face_name); void find_unused_nodes(xml_node const& root); @@ -441,45 +443,45 @@ void map_parser::parse_style(Map & map, xml_node const& sty) // image filters mapnik::image_filter_grammar > filter_grammar; - + optional filters = sty.get_opt_attr("image-filters"); if (filters) { std::string filter_mode = *filters; std::string::const_iterator itr = filter_mode.begin(); std::string::const_iterator end = filter_mode.end(); - - bool result = boost::spirit::qi::phrase_parse(itr,end, - filter_grammar, - boost::spirit::qi::ascii::space, + + bool result = boost::spirit::qi::phrase_parse(itr,end, + filter_grammar, + boost::spirit::qi::ascii::space, style.image_filters()); if (!result || itr!=end) { throw config_error("failed to parse image-filters: '" + std::string(itr,end) + "'"); - } + } } - - // direct image filters (applied directly on main image buffer - // TODO : consider creating a separate XML node e.g - // - // + + // direct image filters (applied directly on main image buffer + // TODO : consider creating a separate XML node e.g + // + // optional direct_filters = sty.get_opt_attr("direct-image-filters"); if (direct_filters) { std::string filter_mode = *direct_filters; std::string::const_iterator itr = filter_mode.begin(); - std::string::const_iterator end = filter_mode.end(); - bool result = boost::spirit::qi::phrase_parse(itr,end, - filter_grammar, - boost::spirit::qi::ascii::space, + std::string::const_iterator end = filter_mode.end(); + bool result = boost::spirit::qi::phrase_parse(itr,end, + filter_grammar, + boost::spirit::qi::ascii::space, style.direct_image_filters()); if (!result || itr!=end) { throw config_error("failed to parse direct-image-filters: '" + std::string(itr,end) + "'"); - } + } } - + // rules xml_node::const_iterator ruleIter = sty.begin(); xml_node::const_iterator endRule = sty.end(); @@ -839,7 +841,7 @@ void map_parser::parse_symbolizer_base(symbolizer_base &sym, xml_node const &pt) throw config_error("failed to parse comp-op: '" + *comp_op_name + "'"); } } - + optional geometry_transform_wkt = pt.get_opt_attr("geometry-transform"); if (geometry_transform_wkt) { @@ -851,18 +853,18 @@ void map_parser::parse_symbolizer_base(symbolizer_base &sym, xml_node const &pt) if (strict_) throw config_error(ss.str()); // value_error here? else - std::clog << "### WARNING: " << ss.str() << endl; + MAPNIK_LOG_WARN(load_map) << "### WARNING: " << ss; } sym.set_transform(tl); } - + optional clip = pt.get_opt_attr("clip"); if (clip) sym.set_clip(*clip); - + // smooth value optional smooth = pt.get_opt_attr("smooth"); if (smooth) sym.set_smooth(*smooth); - + optional writer = pt.get_opt_attr("meta-writer"); if (!writer) return; optional output = pt.get_opt_attr("meta-output"); @@ -878,7 +880,7 @@ void map_parser::parse_point_symbolizer(rule & rule, xml_node const & sym) optional allow_overlap = sym.get_opt_attr("allow-overlap"); optional ignore_placement = sym.get_opt_attr("ignore-placement"); optional opacity = sym.get_opt_attr("opacity"); - + point_symbolizer symbol; if (allow_overlap) { @@ -949,13 +951,13 @@ void map_parser::parse_point_symbolizer(rule & rule, xml_node const & sym) } -void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& sym) +void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& node) { try { std::string filename(""); - optional file = sym.get_opt_attr("file"); - optional base = sym.get_opt_attr("base"); + optional file = node.get_opt_attr("file"); + optional base = node.get_opt_attr("base"); if (file && !file->empty()) { @@ -986,24 +988,45 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& sym) } } - path_expression_ptr expr(boost::make_shared()); + optional marker_type = node.get_opt_attr("marker-type"); + if (marker_type) + { + // TODO - before Mapnik 2.1 release change this from WARN TO ERROR + MAPNIK_LOG_WARN(markers_symbolizer) << "'marker-type' is deprecated and will be removed in Mapnik 3.x, use file='shape://' to specify known svg shapes"; + // back compatibility with Mapnik 2.0.0 + if (!marker_type->empty() && filename.empty()) + { + if (*marker_type == "ellipse") + { + filename = marker_cache::known_svg_prefix_ + "ellipse"; + } + else if (*marker_type == "arrow") + { + filename = marker_cache::known_svg_prefix_ + "arrow"; + } + } + } + + markers_symbolizer sym; + if (!filename.empty()) { - if (!parse_path_from_string(expr, filename, sym.get_tree().path_expr_grammar)) + path_expression_ptr expr(boost::make_shared()); + if (!parse_path_from_string(expr, filename, node.get_tree().path_expr_grammar)) { throw mapnik::config_error("Failed to parse path_expression '" + filename + "'"); } + sym.set_filename(expr); } - markers_symbolizer symbol(expr); - optional opacity = sym.get_opt_attr("opacity"); - if (opacity) symbol.set_opacity(*opacity); + optional opacity = node.get_opt_attr("opacity"); + if (opacity) sym.set_opacity(*opacity); - optional image_transform_wkt = sym.get_opt_attr("transform"); + optional image_transform_wkt = node.get_opt_attr("transform"); if (image_transform_wkt) { mapnik::transform_list_ptr tl = boost::make_shared(); - if (!mapnik::parse_transform(*tl, *image_transform_wkt, sym.get_tree().transform_expr_grammar)) + if (!mapnik::parse_transform(*tl, *image_transform_wkt, node.get_tree().transform_expr_grammar)) { std::stringstream ss; ss << "Could not parse transform from '" << *image_transform_wkt @@ -1017,52 +1040,38 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& sym) MAPNIK_LOG_WARN(load_map) << "map_parser: " << ss; } } - symbol.set_image_transform(tl); + sym.set_image_transform(tl); } - - optional c = sym.get_opt_attr("fill"); - if (c) symbol.set_fill(*c); - optional spacing = sym.get_opt_attr("spacing"); - if (spacing) symbol.set_spacing(*spacing); - optional max_error = sym.get_opt_attr("max-error"); - if (max_error) symbol.set_max_error(*max_error); - optional allow_overlap = sym.get_opt_attr("allow-overlap"); - optional ignore_placement = sym.get_opt_attr("ignore-placement"); - if (allow_overlap) symbol.set_allow_overlap(*allow_overlap); - if (ignore_placement) symbol.set_ignore_placement(*ignore_placement); - optional w = sym.get_opt_attr("width"); - optional h = sym.get_opt_attr("height"); + optional c = node.get_opt_attr("fill"); + if (c) sym.set_fill(*c); + optional spacing = node.get_opt_attr("spacing"); + if (spacing) sym.set_spacing(*spacing); + optional max_error = node.get_opt_attr("max-error"); + if (max_error) sym.set_max_error(*max_error); + optional allow_overlap = node.get_opt_attr("allow-overlap"); + optional ignore_placement = node.get_opt_attr("ignore-placement"); + if (allow_overlap) sym.set_allow_overlap(*allow_overlap); + if (ignore_placement) sym.set_ignore_placement(*ignore_placement); - if (w && h) - { - symbol.set_width(*w); - symbol.set_height(*h); - } - else if (w) - { - symbol.set_width(*w); - symbol.set_height(*w); + optional width = node.get_opt_attr("width"); + if (width) sym.set_width(*width); - } - else if (h) - { - symbol.set_width(*h); - symbol.set_height(*h); - } + optional height = node.get_opt_attr("height"); + if (height) sym.set_height(*height); stroke strk; - parse_stroke(strk,sym); - symbol.set_stroke(strk); + if (parse_stroke(strk,node)) + sym.set_stroke(strk); - marker_placement_e placement = sym.get_attr("placement", MARKER_LINE_PLACEMENT); - symbol.set_marker_placement(placement); - parse_symbolizer_base(symbol, sym); - rule.append(symbol); + marker_placement_e placement = node.get_attr("placement", MARKER_LINE_PLACEMENT); + sym.set_marker_placement(placement); + parse_symbolizer_base(sym, node); + rule.append(sym); } - catch (const config_error & ex) + catch (config_error const& ex) { - ex.append_context("in MarkersSymbolizer", sym); + ex.append_context("in MarkersSymbolizer", node); throw; } } @@ -1141,11 +1150,11 @@ void map_parser::parse_polygon_pattern_symbolizer(rule & rule, // pattern alignment pattern_alignment_e p_alignment = sym.get_attr("alignment",LOCAL_ALIGNMENT); symbol.set_alignment(p_alignment); - + // opacity optional opacity = sym.get_opt_attr("opacity"); if (opacity) symbol.set_opacity(*opacity); - + // gamma optional gamma = sym.get_opt_attr("gamma"); if (gamma) symbol.set_gamma(*gamma); @@ -1212,7 +1221,7 @@ void map_parser::parse_shield_symbolizer(rule & rule, xml_node const& sym) } shield_symbolizer shield_symbol = shield_symbolizer(placement_finder); - + optional image_transform_wkt = sym.get_opt_attr("transform"); if (image_transform_wkt) { @@ -1220,7 +1229,7 @@ void map_parser::parse_shield_symbolizer(rule & rule, xml_node const& sym) if (!mapnik::parse_transform(*tl, *image_transform_wkt, sym.get_tree().transform_expr_grammar)) { std::stringstream ss; - ss << "Could not parse transform from '" << *image_transform_wkt + ss << "Could not parse transform from '" << *image_transform_wkt << "', expected transform attribute"; if (strict_) { @@ -1233,7 +1242,7 @@ void map_parser::parse_shield_symbolizer(rule & rule, xml_node const& sym) } shield_symbol.set_image_transform(tl); } - + // shield displacement double shield_dx = sym.get_attr("shield-dx", 0.0); double shield_dy = sym.get_attr("shield-dy", 0.0); @@ -1263,8 +1272,6 @@ void map_parser::parse_shield_symbolizer(rule & rule, xml_node const& sym) shield_symbol.set_unlock_image(* unlock_image); } - parse_symbolizer_base(shield_symbol, sym); - std::string file = sym.get_attr("file"); if (file.empty()) { @@ -1289,6 +1296,7 @@ void map_parser::parse_shield_symbolizer(rule & rule, xml_node const& sym) throw mapnik::config_error("Failed to parse path_expression '" + file + "'"); } shield_symbol.set_filename(expr); + parse_symbolizer_base(shield_symbol, sym); rule.append(shield_symbol); } catch (const config_error & ex) @@ -1298,15 +1306,24 @@ void map_parser::parse_shield_symbolizer(rule & rule, xml_node const& sym) } } -void map_parser::parse_stroke(stroke & strk, xml_node const & sym) +bool map_parser::parse_stroke(stroke & strk, xml_node const & sym) { + bool result = false; // stroke color optional c = sym.get_opt_attr("stroke"); - if (c) strk.set_color(*c); + if (c) + { + strk.set_color(*c); + result = true; + } // stroke-width optional width = sym.get_opt_attr("stroke-width"); - if (width) strk.set_width(*width); + if (width && *width > 0) + { + strk.set_width(*width); + result = true; + } // stroke-opacity optional opacity = sym.get_opt_attr("stroke-opacity"); @@ -1361,10 +1378,11 @@ void map_parser::parse_stroke(stroke & strk, xml_node const & sym) "list of floats or 'none' but got '" + (*str) + "'"); } } - + // stroke-miterlimit optional miterlimit = sym.get_opt_attr("stroke-miterlimit"); if (miterlimit) strk.set_miterlimit(*miterlimit); + return result; } void map_parser::parse_line_symbolizer(rule & rule, xml_node const & sym) @@ -1374,7 +1392,7 @@ void map_parser::parse_line_symbolizer(rule & rule, xml_node const & sym) stroke strk; parse_stroke(strk,sym); line_symbolizer symbol = line_symbolizer(strk); - + // offset value optional offset = sym.get_opt_attr("offset"); if (offset) symbol.set_offset(*offset); @@ -1382,7 +1400,6 @@ void map_parser::parse_line_symbolizer(rule & rule, xml_node const & sym) line_rasterizer_e rasterizer = sym.get_attr("rasterizer", RASTERIZER_FULL); symbol.set_rasterizer(rasterizer); - // meta-writer parse_symbolizer_base(symbol, sym); rule.append(symbol); } @@ -1411,7 +1428,7 @@ void map_parser::parse_polygon_symbolizer(rule & rule, xml_node const & sym) // gamma method optional gamma_method = sym.get_opt_attr("gamma-method"); if (gamma_method) poly_sym.set_gamma_method(*gamma_method); - + parse_symbolizer_base(poly_sym, sym); rule.append(poly_sym); } @@ -1460,7 +1477,27 @@ void map_parser::parse_raster_symbolizer(rule & rule, xml_node const & sym) // scaling optional scaling = sym.get_opt_attr("scaling"); - if (scaling) raster_sym.set_scaling(*scaling); + if (scaling) + { + std::string scaling_method = *scaling; + if (scaling_method == "fast") + { + MAPNIK_LOG_ERROR(raster_symbolizer) << "'scaling' value of 'fast' is deprecated and will be removed in Mapnik 3.x, use 'near' with Mapnik >= 2.1.x"; + raster_sym.set_scaling_method(SCALING_NEAR); + } + else + { + boost::optional method = scaling_method_from_string(scaling_method); + if (method) + { + raster_sym.set_scaling_method(*method); + } + else + { + throw config_error("failed to parse 'scaling': '" + *scaling + "'"); + } + } + } // opacity optional opacity = sym.get_opt_attr("opacity"); @@ -1595,6 +1632,9 @@ void map_parser::ensure_font_face(std::string const& face_name) std::string map_parser::ensure_relative_to_xml(boost::optional opt_path) { + if (marker_cache::is_uri(*opt_path)) + return *opt_path; + if (relative_to_xml_) { boost::filesystem::path xml_path = filename_; diff --git a/src/marker_cache.cpp b/src/marker_cache.cpp index 1c9e9799c..42be35040 100644 --- a/src/marker_cache.cpp +++ b/src/marker_cache.cpp @@ -45,25 +45,73 @@ namespace mapnik { -boost::unordered_map marker_cache::cache_; +boost::unordered_map marker_cache::marker_cache_; +boost::unordered_map marker_cache::svg_cache_; +std::string marker_cache::known_svg_prefix_ = "shape://"; + +marker_cache::marker_cache() +{ + insert_svg("ellipse", + "" + "" + "" + ""); + insert_svg("arrow", + "" + "" + "" + ""); +} + +marker_cache::~marker_cache() {} void marker_cache::clear() { #ifdef MAPNIK_THREADSAFE mutex::scoped_lock lock(mutex_); #endif - return cache_.clear(); + typedef boost::unordered_map::const_iterator iterator_type; + iterator_type itr = marker_cache_.begin(); + while(itr != marker_cache_.end()) + { + if (!is_uri(itr->first)) + { + marker_cache_.erase(itr++); + } + else + { + ++itr; + } + } } -bool marker_cache::insert(std::string const& uri, marker_ptr path) +bool marker_cache::is_uri(std::string const& path) +{ + return boost::algorithm::starts_with(path,known_svg_prefix_); +} + +bool marker_cache::insert_svg(std::string const& name, std::string const& svg_string) +{ + std::string key = known_svg_prefix_ + name; + typedef boost::unordered_map::const_iterator iterator_type; + iterator_type itr = svg_cache_.find(key); + if (itr == svg_cache_.end()) + { + return svg_cache_.insert(std::make_pair(key,svg_string)).second; + } + return false; +} + +bool marker_cache::insert_marker(std::string const& uri, marker_ptr path) { #ifdef MAPNIK_THREADSAFE mutex::scoped_lock lock(mutex_); #endif - return cache_.insert(std::make_pair(uri,path)).second; + return marker_cache_.insert(std::make_pair(uri,path)).second; } -boost::optional marker_cache::find(std::string const& uri, bool update_cache) +boost::optional marker_cache::find(std::string const& uri, + bool update_cache) { boost::optional result; @@ -71,12 +119,13 @@ boost::optional marker_cache::find(std::string const& uri, bool upda { return result; } + #ifdef MAPNIK_THREADSAFE mutex::scoped_lock lock(mutex_); #endif typedef boost::unordered_map::const_iterator iterator_type; - iterator_type itr = cache_.find(uri); - if (itr != cache_.end()) + iterator_type itr = marker_cache_.find(uri); + if (itr != marker_cache_.end()) { result.reset(itr->second); return result; @@ -84,14 +133,43 @@ boost::optional marker_cache::find(std::string const& uri, bool upda try { - // we can't find marker in cache, lets try to load it from filesystem - boost::filesystem::path path(uri); - if (!exists(path)) + // if uri references a built-in marker + if (is_uri(uri)) { - MAPNIK_LOG_ERROR(marker_cache) << "Marker does not exist: " << uri; + boost::unordered_map::const_iterator mark_itr = svg_cache_.find(uri); + if (mark_itr == svg_cache_.end()) + { + MAPNIK_LOG_ERROR(marker_cache) << "Marker does not exist: " << uri; + return result; + } + std::string known_svg_string = mark_itr->second; + using namespace mapnik::svg; + path_ptr marker_path(boost::make_shared()); + vertex_stl_adapter stl_storage(marker_path->source()); + svg_path_adapter svg_path(stl_storage); + svg_converter_type svg(svg_path, marker_path->attributes()); + svg_parser p(svg); + p.parse_from_string(known_svg_string); + //svg.arrange_orientations(); + double lox,loy,hix,hiy; + svg.bounding_rect(&lox, &loy, &hix, &hiy); + marker_path->set_bounding_box(lox,loy,hix,hiy); + marker_ptr mark(boost::make_shared(marker_path)); + result.reset(mark); + if (update_cache) + { + marker_cache_.insert(std::make_pair(uri,*result)); + } } + // otherwise assume file-based else { + boost::filesystem::path path(uri); + if (!exists(path)) + { + MAPNIK_LOG_ERROR(marker_cache) << "Marker does not exist: " << uri; + return result; + } if (is_svg(uri)) { using namespace mapnik::svg; @@ -109,11 +187,12 @@ boost::optional marker_cache::find(std::string const& uri, bool upda result.reset(mark); if (update_cache) { - cache_.insert(std::make_pair(uri,*result)); + marker_cache_.insert(std::make_pair(uri,*result)); } } else { + // TODO - support reading images from string std::auto_ptr reader(mapnik::get_image_reader(uri)); if (reader.get()) { @@ -131,7 +210,7 @@ boost::optional marker_cache::find(std::string const& uri, bool upda result.reset(mark); if (update_cache) { - cache_.insert(std::make_pair(uri,*result)); + marker_cache_.insert(std::make_pair(uri,*result)); } } else diff --git a/src/markers_placement.cpp b/src/markers_placement.cpp index 94a713cf4..6ea4b0e14 100644 --- a/src/markers_placement.cpp +++ b/src/markers_placement.cpp @@ -9,6 +9,7 @@ #include "agg_conv_clip_polyline.h" #include "agg_trans_affine.h" #include "agg_conv_transform.h" +#include "agg_conv_smooth_poly1.h" // stl #include @@ -16,7 +17,7 @@ namespace mapnik { template markers_placement::markers_placement( - Locator &locator, box2d size, agg::trans_affine const& tr, Detector &detector, double spacing, double max_error, bool allow_overlap) + Locator &locator, box2d 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) { marker_width_ = (size_ * tr_).width(); @@ -239,9 +240,14 @@ typedef coord_transform path_type; typedef coord_transform clipped_path_type; typedef agg::conv_transform transformed_path_type; -template class markers_placement; -template class markers_placement, label_collision_detector4>; +template class markers_placement; template class markers_placement; +template class markers_placement; +template class markers_placement; template class markers_placement; - +template class markers_placement, label_collision_detector4>; +template class markers_placement, label_collision_detector4>; +template class markers_placement, label_collision_detector4>; +template class markers_placement, label_collision_detector4>; +template class markers_placement, label_collision_detector4>; } //ns mapnik diff --git a/src/markers_symbolizer.cpp b/src/markers_symbolizer.cpp index 278875984..03554e03c 100644 --- a/src/markers_symbolizer.cpp +++ b/src/markers_symbolizer.cpp @@ -37,41 +37,37 @@ static const char * marker_placement_strings[] = { IMPLEMENT_ENUM( marker_placement_e, marker_placement_strings ) markers_symbolizer::markers_symbolizer() - : symbolizer_with_image(path_expression_ptr(new path_expression)), + : symbolizer_with_image(parse_path("shape://ellipse")), symbolizer_base(), + width_(), + height_(), ignore_placement_(false), allow_overlap_(false), - fill_(color(0,0,255)), spacing_(100.0), max_error_(0.2), - width_(boost::make_shared(10.0)), - height_(boost::make_shared(10.0)), - stroke_(), - marker_p_(MARKER_LINE_PLACEMENT) {} + marker_p_(MARKER_POINT_PLACEMENT) {} -markers_symbolizer::markers_symbolizer(path_expression_ptr filename) +markers_symbolizer::markers_symbolizer(path_expression_ptr const& filename) : symbolizer_with_image(filename), symbolizer_base(), + width_(), + height_(), ignore_placement_(false), allow_overlap_(false), - fill_(color(0,0,255)), spacing_(100.0), max_error_(0.2), - width_(boost::make_shared(10.0)), - height_(boost::make_shared(10.0)), - stroke_(), - marker_p_(MARKER_LINE_PLACEMENT) {} + marker_p_(MARKER_POINT_PLACEMENT) {} markers_symbolizer::markers_symbolizer(markers_symbolizer const& rhs) : symbolizer_with_image(rhs), symbolizer_base(rhs), - ignore_placement_(rhs.ignore_placement_), - allow_overlap_(rhs.allow_overlap_), - fill_(rhs.fill_), - spacing_(rhs.spacing_), - max_error_(rhs.max_error_), width_(rhs.width_), height_(rhs.height_), + ignore_placement_(rhs.ignore_placement_), + allow_overlap_(rhs.allow_overlap_), + spacing_(rhs.spacing_), + max_error_(rhs.max_error_), + fill_(rhs.fill_), stroke_(rhs.stroke_), marker_p_(rhs.marker_p_) {} @@ -115,37 +111,37 @@ double markers_symbolizer::get_max_error() const return max_error_; } -void markers_symbolizer::set_fill(color fill) +void markers_symbolizer::set_fill(color const& fill) { fill_ = fill; } -color const& markers_symbolizer::get_fill() const +boost::optional markers_symbolizer::get_fill() const { return fill_; } -void markers_symbolizer::set_width(expression_ptr width) +void markers_symbolizer::set_width(expression_ptr const& width) { width_ = width; } -expression_ptr markers_symbolizer::get_width() const +expression_ptr const& markers_symbolizer::get_width() const { return width_; } -void markers_symbolizer::set_height(expression_ptr height) +void markers_symbolizer::set_height(expression_ptr const& height) { height_ = height; } -expression_ptr markers_symbolizer::get_height() const +expression_ptr const& markers_symbolizer::get_height() const { return height_; } -stroke const& markers_symbolizer::get_stroke() const +boost::optional markers_symbolizer::get_stroke() const { return stroke_; } diff --git a/src/metawriter.cpp b/src/metawriter.cpp index f55298807..e37dfa976 100644 --- a/src/metawriter.cpp +++ b/src/metawriter.cpp @@ -177,7 +177,7 @@ void metawriter_json_stream::add_box(box2d const &box, Feature const& fe } void metawriter_json_stream::add_text( - boost::ptr_vector &placements, box2d const& extents, + boost::ptr_vector const& placements, box2d const& extents, Feature const& feature, CoordTransform const& t, metawriter_properties const& properties) { @@ -195,14 +195,15 @@ void metawriter_json_stream::add_text( */ for (unsigned n = 0; n < placements.size(); n++) { - text_path ¤t_placement = placements[n]; + text_path const& current_placement = placements[n]; bool inside = false; /* Part of text is inside rendering region */ bool straight = true; char_info_ptr c; double x, y, angle; current_placement.rewind(); - for (int i = 0; i < current_placement.num_nodes(); ++i) { + for (int i = 0; i < current_placement.num_nodes(); ++i) + { int cx = current_placement.center.x; int cy = current_placement.center.y; current_placement.vertex(&c, &x, &y, &angle); diff --git a/src/metawriter_inmem.cpp b/src/metawriter_inmem.cpp index 744b910dc..7cf0645be 100644 --- a/src/metawriter_inmem.cpp +++ b/src/metawriter_inmem.cpp @@ -71,7 +71,7 @@ metawriter_inmem::add_box(box2d const& box, Feature const& feature, void metawriter_inmem::add_text( - boost::ptr_vector & /*text*/, + boost::ptr_vector const& /*text*/, box2d const& extents, Feature const& feature, CoordTransform const& /*t*/, @@ -146,4 +146,3 @@ metawriter_inmem::inst_end() const { } - diff --git a/src/placement_finder.cpp b/src/placement_finder.cpp index eefbf1b6e..f5a34b61e 100644 --- a/src/placement_finder.cpp +++ b/src/placement_finder.cpp @@ -500,9 +500,9 @@ void placement_finder::find_point_placement(double label_x, } // check the placement of any additional envelopes - if (!p.allow_overlap && !additional_boxes.empty()) + if (!p.allow_overlap && !additional_boxes_.empty()) { - BOOST_FOREACH(box2d box, additional_boxes) + BOOST_FOREACH(box2d const& box, additional_boxes_) { box2d pt(box.minx() + current_placement->center.x, box.miny() + current_placement->center.y, diff --git a/src/save_map.cpp b/src/save_map.cpp index 1072d2b94..517aaafa1 100644 --- a/src/save_map.cpp +++ b/src/save_map.cpp @@ -21,6 +21,7 @@ *****************************************************************************/ // mapnik +#include #include #include #include @@ -30,7 +31,9 @@ #include #include #include - +#include +#include +#include // boost #include #include @@ -73,7 +76,7 @@ public: { set_attr( sym_node, "placement", sym.get_point_placement() ); } - add_metawriter_attributes(sym_node, sym); + serialize_symbolizer_base(sym_node, sym); } void operator () ( line_symbolizer const& sym ) @@ -83,13 +86,13 @@ public: const stroke & strk = sym.get_stroke(); add_stroke_attributes(sym_node, strk); - add_metawriter_attributes(sym_node, sym); line_symbolizer dfl; if ( sym.get_rasterizer() != dfl.get_rasterizer() || explicit_defaults_ ) { set_attr( sym_node, "rasterizer", sym.get_rasterizer() ); } + serialize_symbolizer_base(sym_node, sym); } void operator () ( line_pattern_symbolizer const& sym ) @@ -99,7 +102,7 @@ public: ptree()))->second; add_image_attributes( sym_node, sym ); - add_metawriter_attributes(sym_node, sym); + serialize_symbolizer_base(sym_node, sym); } void operator () ( polygon_symbolizer const& sym ) @@ -124,7 +127,7 @@ public: { set_attr( sym_node, "gamma-method", sym.get_gamma_method() ); } - add_metawriter_attributes(sym_node, sym); + serialize_symbolizer_base(sym_node, sym); } void operator () ( polygon_pattern_symbolizer const& sym ) @@ -147,7 +150,7 @@ public: set_attr( sym_node, "gamma-method", sym.get_gamma_method() ); } add_image_attributes( sym_node, sym ); - add_metawriter_attributes(sym_node, sym); + serialize_symbolizer_base(sym_node, sym); } void operator () ( raster_symbolizer const& sym ) @@ -156,14 +159,9 @@ public: ptree::value_type("RasterSymbolizer", ptree()))->second; raster_symbolizer dfl; - if ( sym.get_mode() != dfl.get_mode() || explicit_defaults_ ) + if ( sym.get_scaling_method() != dfl.get_scaling_method() || explicit_defaults_ ) { - set_attr( sym_node, "mode", sym.get_mode() ); - } - - if ( sym.get_scaling() != dfl.get_scaling() || explicit_defaults_ ) - { - set_attr( sym_node, "scaling", sym.get_scaling() ); + set_attr( sym_node, "scaling", *scaling_method_to_string(sym.get_scaling_method()) ); } if ( sym.get_opacity() != dfl.get_opacity() || explicit_defaults_ ) @@ -180,7 +178,7 @@ public: serialize_raster_colorizer(sym_node, sym.get_colorizer(), explicit_defaults_); } - //Note: raster_symbolizer doesn't support metawriters + serialize_symbolizer_base(sym_node, sym); } void operator () ( shield_symbolizer const& sym ) @@ -191,7 +189,6 @@ public: add_font_attributes(sym_node, sym); add_image_attributes(sym_node, sym); - add_metawriter_attributes(sym_node, sym); // pseudo-default-construct a shield_symbolizer. It is used // to avoid printing of attributes with default values without @@ -219,7 +216,7 @@ public: { set_attr(sym_node, "shield-dy", displacement.second); } - + serialize_symbolizer_base(sym_node, sym); } void operator () ( text_symbolizer const& sym ) @@ -229,7 +226,7 @@ public: ptree()))->second; add_font_attributes( sym_node, sym); - add_metawriter_attributes(sym_node, sym); + serialize_symbolizer_base(sym_node, sym); } void operator () ( building_symbolizer const& sym ) @@ -251,7 +248,7 @@ public: set_attr( sym_node, "height", mapnik::to_expression_string(*sym.height()) ); } - add_metawriter_attributes(sym_node, sym); + serialize_symbolizer_base(sym_node, sym); } void operator () ( markers_symbolizer const& sym) @@ -306,10 +303,13 @@ public: set_attr( sym_node, "transform", tr_str ); } - const stroke & strk = sym.get_stroke(); - add_stroke_attributes(sym_node, strk); + boost::optional const& strk = sym.get_stroke(); + if (strk) + { + add_stroke_attributes(sym_node, *strk); + } - add_metawriter_attributes(sym_node, sym); + serialize_symbolizer_base(sym_node, sym); } template @@ -317,13 +317,41 @@ public: { // not-supported #ifdef MAPNIK_DEBUG - std::clog << typeid(sym).name() << " is not supported" << std::endl; + MAPNIK_LOG_WARN(save_map) << typeid(sym).name() << " is not supported"; #endif } - + private: serialize_symbolizer(); + void serialize_symbolizer_base(ptree & node, symbolizer_base const& sym) + { + symbolizer_base dfl = symbolizer_base(); + if (!sym.get_metawriter_name().empty() || explicit_defaults_) { + set_attr(node, "meta-writer", sym.get_metawriter_name()); + } + if (!sym.get_metawriter_properties_overrides().empty() || explicit_defaults_) { + set_attr(node, "meta-output", sym.get_metawriter_properties_overrides().to_string()); + } + if (sym.get_transform()) + { + std::string tr_str = sym.get_transform_string(); + set_attr( node, "geometry-transform", tr_str ); + } + if (sym.clip() != dfl.clip() || explicit_defaults_) + { + set_attr( node, "clip", sym.clip() ); + } + if (sym.smooth() != dfl.smooth() || explicit_defaults_) + { + set_attr( node, "smooth", sym.smooth() ); + } + if (sym.comp_op() != dfl.comp_op() || explicit_defaults_) + { + set_attr( node, "comp-op", *comp_op_to_string(sym.comp_op()) ); + } + } + void serialize_raster_colorizer(ptree & sym_node, raster_colorizer_ptr const& colorizer, bool explicit_defaults) @@ -348,7 +376,7 @@ private: } - void add_image_attributes(ptree & node, const symbolizer_with_image & sym) + void add_image_attributes(ptree & node, symbolizer_with_image const& sym) { if (sym.get_filename()) { @@ -438,21 +466,6 @@ private: } } - void add_metawriter_attributes(ptree & node, symbolizer_base const& sym) - { - if (!sym.get_metawriter_name().empty() || explicit_defaults_) { - set_attr(node, "meta-writer", sym.get_metawriter_name()); - } - if (!sym.get_metawriter_properties_overrides().empty() || explicit_defaults_) { - set_attr(node, "meta-output", sym.get_metawriter_properties_overrides().to_string()); - } - if (sym.get_transform()) - { - std::string tr_str = sym.get_transform_string(); - set_attr( node, "view-transform", tr_str ); - } - } - ptree & rule_; bool explicit_defaults_; }; @@ -535,6 +548,36 @@ void serialize_style( ptree & map_node, Map::const_style_iterator style_it, bool set_attr(style_node, "opacity", opacity); } + boost::optional comp_op = style.comp_op(); + if (comp_op) + { + set_attr(style_node, "comp-op", *comp_op_to_string(*comp_op)); + } + else if (explicit_defaults) + { + set_attr(style_node, "comp-op", "src-over"); + } + + if (style.image_filters().size() > 0) + { + std::string filters_str; + std::back_insert_iterator sink(filters_str); + if (generate_image_filters(sink, style.image_filters())) + { + set_attr(style_node, "image-filters", filters_str); + } + } + + if (style.direct_image_filters().size() > 0) + { + std::string filters_str; + std::back_insert_iterator sink(filters_str); + if (generate_image_filters(sink, style.direct_image_filters())) + { + set_attr(style_node, "direct-image-filters", filters_str); + } + } + rules::const_iterator it = style.get_rules().begin(); rules::const_iterator end = style.get_rules().end(); for (; it != end; ++it) diff --git a/src/shield_symbolizer.cpp b/src/shield_symbolizer.cpp index 006ccca83..17238953b 100644 --- a/src/shield_symbolizer.cpp +++ b/src/shield_symbolizer.cpp @@ -88,4 +88,3 @@ position const& shield_symbolizer::get_shield_displacement() const } } - diff --git a/src/svg/process_symbolizers.cpp b/src/svg/process_symbolizers.cpp index 1619b6caa..2a1bcbad1 100644 --- a/src/svg/process_symbolizers.cpp +++ b/src/svg/process_symbolizers.cpp @@ -46,7 +46,7 @@ bool svg_renderer::process(rule::symbolizers const& syms, for(unsigned i=0; i 1) + if(geom.size() > 1) { path_type path(t_, geom, prj_trans); generator_.generate_path(path, path_attributes_); diff --git a/src/svg_parser.cpp b/src/svg_parser.cpp index eb8dcb5dc..2cd3241dd 100644 --- a/src/svg_parser.cpp +++ b/src/svg_parser.cpp @@ -135,29 +135,52 @@ svg_parser::~svg_parser() {} void svg_parser::parse(std::string const& filename) { xmlTextReaderPtr reader = xmlNewTextReaderFilename(filename.c_str()); - if (reader != 0) + if (reader == NULL) { - int ret = xmlTextReaderRead(reader); - try { - while (ret == 1) - { - process_node(reader); - ret = xmlTextReaderRead(reader); - } - } - catch (std::exception const& ex) - { - xmlFreeTextReader(reader); - throw; - } - xmlFreeTextReader(reader); - if (ret != 0) - { - MAPNIK_LOG_ERROR(svg_parser) << "Failed to parse " << filename; - } - } else { - MAPNIK_LOG_ERROR(svg_parser) << "Unable to open " << filename; + MAPNIK_LOG_ERROR(svg_parser) << "Unable to open '" << filename << "'"; } + else if (!parse_reader(reader)) + { + MAPNIK_LOG_ERROR(svg_parser) << "Unable to parse '" << filename << "'"; + } +} + +void svg_parser::parse_from_string(std::string const& svg) +{ + xmlTextReaderPtr reader = xmlReaderForMemory(svg.c_str(),svg.size(),NULL,NULL, + (XML_PARSE_NOBLANKS | XML_PARSE_NOCDATA | XML_PARSE_NOERROR | XML_PARSE_NOWARNING)); + if (reader == NULL) + { + MAPNIK_LOG_ERROR(svg_parser) << "Unable to parse '" << svg << "'"; + } + else if (!parse_reader(reader)) + { + MAPNIK_LOG_ERROR(svg_parser) << "Unable to parse '" << svg << "'"; + } +} + +bool svg_parser::parse_reader(xmlTextReaderPtr reader) +{ + int ret = xmlTextReaderRead(reader); + try { + while (ret == 1) + { + process_node(reader); + ret = xmlTextReaderRead(reader); + } + } + catch (std::exception const& ex) + { + xmlFreeTextReader(reader); + throw; + } + xmlFreeTextReader(reader); + if (ret != 0) + { + // parsing failure + return false; + } + return true; } void svg_parser::process_node(xmlTextReaderPtr reader) @@ -384,7 +407,8 @@ void svg_parser::parse_attr(const xmlChar * name, const xmlChar * value ) else if(xmlStrEqual(name, BAD_CAST "opacity")) { double opacity = parse_double((const char*)value); - path_.opacity(opacity); + path_.stroke_opacity(opacity); + path_.fill_opacity(opacity); } else if (xmlStrEqual(name, BAD_CAST "visibility")) { diff --git a/src/symbolizer_helpers.cpp b/src/symbolizer_helpers.cpp index 3312ac4c8..1cf014bb9 100644 --- a/src/symbolizer_helpers.cpp +++ b/src/symbolizer_helpers.cpp @@ -34,6 +34,8 @@ bool text_symbolizer_helper::next() if (!placement_valid_) return false; if (point_placement_) return next_point_placement(); + else if (sym_.clip()) + return next_line_placement_clipped(); else return next_line_placement(); } @@ -52,11 +54,54 @@ bool text_symbolizer_helper::next_line_placement() continue; //Reexecute size check } + typedef coord_transform path_type; + path_type path(t_, **geo_itr_, prj_trans_); + + finder_->clear_placements(); + if (points_on_line_) { + finder_->find_point_placements(path); + } else { + finder_->find_line_placements(path); + } + if (!finder_->get_results().empty()) + { + //Found a placement + if (points_on_line_) + { + finder_->update_detector(); + } + geo_itr_ = geometries_to_process_.erase(geo_itr_); + if (writer_.first) writer_.first->add_text( + finder_->get_results(), finder_->get_extents(), + feature_, t_, writer_.second); + return true; + } + //No placement for this geometry. Keep it in geometries_to_process_ for next try. + geo_itr_++; + } + return false; +} + +template +bool text_symbolizer_helper::next_line_placement_clipped() +{ + while (!geometries_to_process_.empty()) + { + if (geo_itr_ == geometries_to_process_.end()) + { + //Just processed the last geometry. Try next placement. + if (!next_placement()) return false; //No more placements + //Start again from begin of list + geo_itr_ = geometries_to_process_.begin(); + continue; //Reexecute size check + } + typedef agg::conv_clip_polyline clipped_geometry_type; typedef coord_transform path_type; clipped_geometry_type clipped(**geo_itr_); clipped.clip_box(query_extent_.minx(),query_extent_.miny(),query_extent_.maxx(),query_extent_.maxy()); path_type path(t_, clipped, prj_trans_); + finder_->clear_placements(); if (points_on_line_) { finder_->find_point_placements(path); @@ -134,7 +179,7 @@ void text_symbolizer_helper::initialize_geometries() geometry_type const& geom = feature_.get_geometry(i); // don't bother with empty geometries - if (geom.num_points() == 0) continue; + if (geom.size() == 0) continue; eGeomType type = geom.type(); if (type == Polygon) { @@ -187,7 +232,7 @@ void text_symbolizer_helper::initialize_points() if (how_placed == VERTEX_PLACEMENT) { geom.rewind(0); - for(unsigned i = 0; i < geom.num_points(); i++) + for(unsigned i = 0; i < geom.size(); i++) { geom.vertex(&label_x, &label_y); prj_trans_.backward(label_x, label_y, z); @@ -199,11 +244,11 @@ void text_symbolizer_helper::initialize_points() { if (how_placed == POINT_PLACEMENT) { - geom.label_position(&label_x, &label_y); + label::centroid(geom, label_x, label_y); } else if (how_placed == INTERIOR_PLACEMENT) { - geom.label_interior_position(&label_x, &label_y); + label::interior_position(geom, label_x, label_y); } else { @@ -247,7 +292,7 @@ bool text_symbolizer_helper::next_placement() } template -placements_type &text_symbolizer_helper::placements() const +placements_type const& text_symbolizer_helper::placements() const { return finder_->get_results(); } @@ -335,14 +380,17 @@ template bool shield_symbolizer_helper::next_line_placement() { position const& pos = placement_->properties.displacement; - finder_->additional_boxes.clear(); + finder_->additional_boxes().clear(); //Markers are automatically centered - finder_->additional_boxes.push_back( + finder_->additional_boxes().push_back( box2d(-0.5 * marker_ext_.width() - pos.first, -0.5 * marker_ext_.height() - pos.second, 0.5 * marker_ext_.width() - pos.first, 0.5 * marker_ext_.height() - pos.second)); - return text_symbolizer_helper::next_line_placement(); + if ( sym_.clip()) + return text_symbolizer_helper::next_line_placement_clipped(); + else + return text_symbolizer_helper::next_line_placement(); } diff --git a/src/transform_expression_grammar.cpp b/src/transform_expression_grammar.cpp new file mode 100644 index 000000000..026c6c13e --- /dev/null +++ b/src/transform_expression_grammar.cpp @@ -0,0 +1,91 @@ +/***************************************************************************** + * + * 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 + * + *****************************************************************************/ + +#include + +namespace mapnik { + +namespace qi = boost::spirit::qi; + +template +transform_expression_grammar::transform_expression_grammar(expression_grammar const& g) + : transform_expression_grammar::base_type(start) +{ + using boost::phoenix::construct; + using qi::_a; using qi::_1; using qi::_4; + using qi::_b; using qi::_2; using qi::_5; + using qi::_c; using qi::_3; using qi::_6; + using qi::_val; + using qi::char_; + using qi::lit; + using qi::no_case; + using qi::no_skip; + + start = transform_ % no_skip[char_(", ")] ; + + transform_ = matrix | translate | scale | rotate | skewX | skewY ; + + matrix = no_case[lit("matrix")] + >> (lit('(') + >> expr >> -lit(',') + >> expr >> -lit(',') + >> expr >> -lit(',') + >> expr >> -lit(',') + >> expr >> -lit(',') + >> expr >> lit(')')) + [ _val = construct(_1,_2,_3,_4,_5,_6) ]; + + translate = no_case[lit("translate")] + >> (lit('(') + >> expr >> -lit(',') + >> -expr >> lit(')')) + [ _val = construct(_1,_2) ]; + + scale = no_case[lit("scale")] + >> (lit('(') + >> expr >> -lit(',') + >> -expr >> lit(')')) + [ _val = construct(_1,_2) ]; + + rotate = no_case[lit("rotate")] + >> lit('(') + >> expr[_a = _1] >> -lit(',') + >> -(expr [_b = _1] >> -lit(',') >> expr[_c = _1]) + >> lit(')') + [ _val = construct(_a,_b,_c) ]; + + skewX = no_case[lit("skewX")] + >> lit('(') + >> expr [ _val = construct(_1) ] + >> lit(')'); + + skewY = no_case[lit("skewY")] + >> lit('(') + >> expr [ _val = construct(_1) ] + >> lit(')'); + + expr = g.expr.alias(); +} + +template struct mapnik::transform_expression_grammar; + +} \ No newline at end of file diff --git a/src/warp.cpp b/src/warp.cpp index 1033e062a..ee0dc6a05 100644 --- a/src/warp.cpp +++ b/src/warp.cpp @@ -46,162 +46,149 @@ namespace mapnik { -void reproject_raster(raster &target, raster const& source, +void reproject_and_scale_raster(raster & target, raster const& source, proj_transform const& prj_trans, double offset_x, double offset_y, unsigned mesh_size, double filter_radius, - double scale_factor, - std::string scaling_method_name) + scaling_method_e scaling_method) { - if (prj_trans.equal()) { + CoordTransform ts(source.data_.width(), source.data_.height(), + source.ext_); + CoordTransform tt(target.data_.width(), target.data_.height(), + target.ext_, offset_x, offset_y); + unsigned i, j; + unsigned mesh_nx = ceil(source.data_.width()/double(mesh_size)+1); + unsigned mesh_ny = ceil(source.data_.height()/double(mesh_size)+1); - if (scaling_method_name == "bilinear8"){ - scale_image_bilinear8(target.data_,source.data_, - offset_x, offset_y); - } else { - scaling_method_e scaling_method = get_scaling_method_by_name(scaling_method_name); - scale_image_agg(target.data_,source.data_, (scaling_method_e)scaling_method, scale_factor, offset_x, offset_y, filter_radius); + ImageData xs(mesh_nx, mesh_ny); + ImageData ys(mesh_nx, mesh_ny); + + // Precalculate reprojected mesh + for(j=0; j xs(mesh_nx, mesh_ny); - ImageData ys(mesh_nx, mesh_ny); + // Initialize AGG objects + typedef agg::pixfmt_rgba32 pixfmt; + typedef pixfmt::color_type color_type; + typedef agg::renderer_base renderer_base; + typedef agg::pixfmt_rgba32_pre pixfmt_pre; + typedef agg::renderer_base renderer_base_pre; - // Precalculate reprojected mesh - for(j=0; j rasterizer; + agg::scanline_u8 scanline; + agg::rendering_buffer buf((unsigned char*)target.data_.getData(), + target.data_.width(), + target.data_.height(), + target.data_.width()*4); + pixfmt_pre pixf_pre(buf); + renderer_base_pre rb_pre(pixf_pre); + rasterizer.clip_box(0, 0, target.data_.width(), target.data_.height()); + agg::rendering_buffer buf_tile( + (unsigned char*)source.data_.getData(), + source.data_.width(), + source.data_.height(), + source.data_.width() * 4); - // Initialize AGG objects - typedef agg::pixfmt_rgba32 pixfmt; - typedef pixfmt::color_type color_type; - typedef agg::renderer_base renderer_base; - typedef agg::pixfmt_rgba32_pre pixfmt_pre; - typedef agg::renderer_base renderer_base_pre; + pixfmt pixf_tile(buf_tile); - agg::rasterizer_scanline_aa<> rasterizer; - agg::scanline_u8 scanline; - agg::rendering_buffer buf((unsigned char*)target.data_.getData(), - target.data_.width(), - target.data_.height(), - target.data_.width()*4); - pixfmt_pre pixf_pre(buf); - renderer_base_pre rb_pre(pixf_pre); - rasterizer.clip_box(0, 0, target.data_.width(), target.data_.height()); - agg::rendering_buffer buf_tile( - (unsigned char*)source.data_.getData(), - source.data_.width(), - source.data_.height(), - source.data_.width() * 4); + typedef agg::image_accessor_clone img_accessor_type; + img_accessor_type ia(pixf_tile); - pixfmt pixf_tile(buf_tile); + agg::span_allocator sa; - typedef agg::image_accessor_clone img_accessor_type; - img_accessor_type ia(pixf_tile); + // Initialize filter + agg::image_filter_lut filter; + switch(scaling_method) + { + case SCALING_NEAR: break; + case SCALING_BILINEAR8: // TODO - impl this or remove? + case SCALING_BILINEAR: + filter.calculate(agg::image_filter_bilinear(), true); break; + case SCALING_BICUBIC: + filter.calculate(agg::image_filter_bicubic(), true); break; + case SCALING_SPLINE16: + filter.calculate(agg::image_filter_spline16(), true); break; + case SCALING_SPLINE36: + filter.calculate(agg::image_filter_spline36(), true); break; + case SCALING_HANNING: + filter.calculate(agg::image_filter_hanning(), true); break; + case SCALING_HAMMING: + filter.calculate(agg::image_filter_hamming(), true); break; + case SCALING_HERMITE: + filter.calculate(agg::image_filter_hermite(), true); break; + case SCALING_KAISER: + filter.calculate(agg::image_filter_kaiser(), true); break; + case SCALING_QUADRIC: + filter.calculate(agg::image_filter_quadric(), true); break; + case SCALING_CATROM: + filter.calculate(agg::image_filter_catrom(), true); break; + case SCALING_GAUSSIAN: + filter.calculate(agg::image_filter_gaussian(), true); break; + case SCALING_BESSEL: + filter.calculate(agg::image_filter_bessel(), true); break; + case SCALING_MITCHELL: + filter.calculate(agg::image_filter_mitchell(), true); break; + case SCALING_SINC: + filter.calculate(agg::image_filter_sinc(filter_radius), true); break; + case SCALING_LANCZOS: + filter.calculate(agg::image_filter_lanczos(filter_radius), true); break; + case SCALING_BLACKMAN: + filter.calculate(agg::image_filter_blackman(filter_radius), true); break; + } - agg::span_allocator sa; + // Project mesh cells into target interpolating raster inside each one + for(j=0; j + interpolator_type; + interpolator_type interpolator(tr); - unsigned x0 = i * mesh_size; - unsigned y0 = j * mesh_size; - unsigned x1 = (i+1) * mesh_size; - unsigned y1 = (j+1) * mesh_size; - - agg::trans_affine tr(polygon, x0, y0, x1, y1); - if (tr.is_valid()) - { - typedef agg::span_interpolator_linear - interpolator_type; - interpolator_type interpolator(tr); - - if (scaling_method == SCALING_NEAR) { - typedef agg::span_image_filter_rgba_nn - - span_gen_type; - span_gen_type sg(ia, interpolator); - agg::render_scanlines_aa(rasterizer, scanline, rb_pre, - sa, sg); - } else { - typedef mapnik::span_image_resample_rgba_affine - span_gen_type; - span_gen_type sg(ia, interpolator, filter); - agg::render_scanlines_aa(rasterizer, scanline, rb_pre, - sa, sg); - } + if (scaling_method == SCALING_NEAR) { + typedef agg::span_image_filter_rgba_nn + + span_gen_type; + span_gen_type sg(ia, interpolator); + agg::render_scanlines_aa(rasterizer, scanline, rb_pre, + sa, sg); + } else { + typedef mapnik::span_image_resample_rgba_affine + span_gen_type; + span_gen_type sg(ia, interpolator, filter); + agg::render_scanlines_aa(rasterizer, scanline, rb_pre, + sa, sg); } - } + } } } diff --git a/src/wkb.cpp b/src/wkb.cpp index cfc07530c..a26122a88 100644 --- a/src/wkb.cpp +++ b/src/wkb.cpp @@ -76,7 +76,7 @@ public: // try to determine WKB format automatically if (format_ == wkbAuto) { - if (size >= 44 + if (size_ >= 44 && (unsigned char)(wkb_[0]) == (unsigned char)(0x00) && (unsigned char)(wkb_[38]) == (unsigned char)(0x7C)) { @@ -113,9 +113,6 @@ public: { int type = read_integer(); -#ifdef MAPNIK_LOG - MAPNIK_LOG_DEBUG(wkb_reader) << "wkb_reader: Read=" << wkb_geometry_type_string(type) << "," << type; -#endif switch (type) { case wkbPoint: @@ -246,9 +243,9 @@ private: void read_point(boost::ptr_vector & paths) { - geometry_type* pt = new geometry_type(Point); double x = read_double(); double y = read_double(); + std::auto_ptr pt(new geometry_type(Point)); pt->move_to(x, y); paths.push_back(pt); } @@ -265,9 +262,9 @@ private: void read_point_xyz(boost::ptr_vector & paths) { - geometry_type* pt = new geometry_type(Point); double x = read_double(); double y = read_double(); + std::auto_ptr pt(new geometry_type(Point)); pos_ += 8; // double z = read_double(); pt->move_to(x, y); paths.push_back(pt); @@ -285,16 +282,19 @@ private: void read_linestring(boost::ptr_vector & paths) { - geometry_type* line = new geometry_type(LineString); int num_points = read_integer(); - CoordinateArray ar(num_points); - read_coords(ar); - line->move_to(ar[0].x, ar[0].y); - for (int i = 1; i < num_points; ++i) + if (num_points > 0) { - line->line_to(ar[i].x, ar[i].y); + CoordinateArray ar(num_points); + read_coords(ar); + std::auto_ptr line(new geometry_type(LineString)); + line->move_to(ar[0].x, ar[0].y); + for (int i = 1; i < num_points; ++i) + { + line->line_to(ar[i].x, ar[i].y); + } + paths.push_back(line); } - paths.push_back(line); } void read_multilinestring(boost::ptr_vector & paths) @@ -309,16 +309,19 @@ private: void read_linestring_xyz(boost::ptr_vector & paths) { - geometry_type* line = new geometry_type(LineString); int num_points = read_integer(); - CoordinateArray ar(num_points); - read_coords_xyz(ar); - line->move_to(ar[0].x, ar[0].y); - for (int i = 1; i < num_points; ++i) + if (num_points > 0) { - line->line_to(ar[i].x, ar[i].y); + CoordinateArray ar(num_points); + read_coords_xyz(ar); + std::auto_ptr line(new geometry_type(LineString)); + line->move_to(ar[0].x, ar[0].y); + for (int i = 1; i < num_points; ++i) + { + line->line_to(ar[i].x, ar[i].y); + } + paths.push_back(line); } - paths.push_back(line); } void read_multilinestring_xyz(boost::ptr_vector & paths) @@ -334,22 +337,27 @@ private: void read_polygon(boost::ptr_vector & paths) { - geometry_type* poly = new geometry_type(Polygon); int num_rings = read_integer(); - unsigned capacity = 0; - for (int i = 0; i < num_rings; ++i) + if (num_rings > 0) { - int num_points = read_integer(); - capacity += num_points; - CoordinateArray ar(num_points); - read_coords(ar); - poly->move_to(ar[0].x, ar[0].y); - for (int j = 1; j < num_points; ++j) + std::auto_ptr poly(new geometry_type(Polygon)); + for (int i = 0; i < num_rings; ++i) { - poly->line_to(ar[j].x, ar[j].y); + int num_points = read_integer(); + if (num_points > 0) + { + CoordinateArray ar(num_points); + read_coords(ar); + poly->move_to(ar[0].x, ar[0].y); + for (int j = 1; j < num_points; ++j) + { + poly->line_to(ar[j].x, ar[j].y); + } + } } + if (poly->size() > 2) // ignore if polygon has less than 3 vertices + paths.push_back(poly); } - paths.push_back(poly); } void read_multipolygon(boost::ptr_vector & paths) @@ -364,22 +372,27 @@ private: void read_polygon_xyz(boost::ptr_vector & paths) { - geometry_type* poly = new geometry_type(Polygon); int num_rings = read_integer(); - unsigned capacity = 0; - for (int i = 0; i < num_rings; ++i) + if (num_rings > 0) { - int num_points = read_integer(); - capacity += num_points; - CoordinateArray ar(num_points); - read_coords_xyz(ar); - poly->move_to(ar[0].x, ar[0].y); - for (int j = 1; j < num_points; ++j) + std::auto_ptr poly(new geometry_type(Polygon)); + for (int i = 0; i < num_rings; ++i) { - poly->line_to(ar[j].x, ar[j].y); + int num_points = read_integer(); + if (num_points > 0) + { + CoordinateArray ar(num_points); + read_coords_xyz(ar); + poly->move_to(ar[0].x, ar[0].y); + for (int j = 1; j < num_points; ++j) + { + poly->line_to(ar[j].x, ar[j].y); + } + } } + if (poly->size() > 2) // ignore if polygon has less than 3 vertices + paths.push_back(poly); } - paths.push_back(poly); } void read_multipolygon_xyz(boost::ptr_vector & paths) @@ -402,42 +415,45 @@ private: } } -#ifdef MAPNIK_LOG std::string wkb_geometry_type_string(int type) { std::stringstream s; switch (type) { - case wkbPoint: s << "wkbPoint"; break; - case wkbLineString: s << "wkbLineString"; break; - case wkbPolygon: s << "wkbPolygon"; break; - case wkbMultiPoint: s << "wkbMultiPoint"; break; - case wkbMultiLineString: s << "wkbMultiLineString"; break; - case wkbMultiPolygon: s << "wkbMultiPolygon"; break; - case wkbGeometryCollection: s << "wkbGeometryCollection"; break; - case wkbPointZ: s << "wkbPointZ"; break; - case wkbLineStringZ: s << "wkbLineStringZ"; break; - case wkbPolygonZ: s << "wkbPolygonZ"; break; - case wkbMultiPointZ: s << "wkbMultiPointZ"; break; - case wkbMultiLineStringZ: s << "wkbMultiLineStringZ"; break; - case wkbMultiPolygonZ: s << "wkbMultiPolygonZ"; break; - case wkbGeometryCollectionZ: s << "wkbGeometryCollectionZ"; break; - default: s << "wkbUknown"; break; + case wkbPoint: s << "Point"; break; + case wkbLineString: s << "LineString"; break; + case wkbPolygon: s << "Polygon"; break; + case wkbMultiPoint: s << "MultiPoint"; break; + case wkbMultiLineString: s << "MultiLineString"; break; + case wkbMultiPolygon: s << "MultiPolygon"; break; + case wkbGeometryCollection: s << "GeometryCollection"; break; + case wkbPointZ: s << "PointZ"; break; + case wkbLineStringZ: s << "LineStringZ"; break; + case wkbPolygonZ: s << "PolygonZ"; break; + case wkbMultiPointZ: s << "MultiPointZ"; break; + case wkbMultiLineStringZ: s << "MultiLineStringZ"; break; + case wkbMultiPolygonZ: s << "MultiPolygonZ"; break; + case wkbGeometryCollectionZ: s << "GeometryCollectionZ"; break; + default: s << "wkbUknown(" << type << ")"; break; } return s.str(); } -#endif + }; -void geometry_utils::from_wkb (boost::ptr_vector& paths, +bool geometry_utils::from_wkb(boost::ptr_vector& paths, const char* wkb, unsigned size, wkbFormat format) { + unsigned geom_count = paths.size(); wkb_reader reader(wkb, size, format); - return reader.read(paths); + reader.read(paths); + if (paths.size() > geom_count) + return true; + return false; } } diff --git a/src/wkb_generator.cpp b/src/wkb_generator.cpp new file mode 100644 index 000000000..68decfc9e --- /dev/null +++ b/src/wkb_generator.cpp @@ -0,0 +1,141 @@ +/***************************************************************************** + * + * 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 + * + *****************************************************************************/ + +#include +#include +#include + +namespace mapnik { namespace util { + +boost::tuple multi_geometry_type::operator() (geometry_container const& geom) const +{ + unsigned type = 0u; + bool collection = false; + + geometry_container::const_iterator itr = geom.begin(); + geometry_container::const_iterator end = geom.end(); + + for ( ; itr != end; ++itr) + { + if (type != 0 && itr->type() != type) + { + collection = true; + break; + } + type = itr->type(); + } + return boost::tuple(type, collection); +} + +template +wkt_generator::wkt_generator(bool single) + : wkt_generator::base_type(wkt) +{ + using boost::spirit::karma::uint_; + using boost::spirit::karma::_val; + using boost::spirit::karma::_1; + using boost::spirit::karma::lit; + using boost::spirit::karma::_a; + using boost::spirit::karma::_r1; + using boost::spirit::karma::eps; + using boost::spirit::karma::string; + + wkt = point | linestring | polygon + ; + + point = &uint_(mapnik::Point)[_1 = _type(_val)] + << string[ phoenix::if_ (single) [_1 = "Point("] + .else_[_1 = "("]] + << point_coord [_1 = _first(_val)] << lit(')') + ; + + linestring = &uint_(mapnik::LineString)[_1 = _type(_val)] + << string[ phoenix::if_ (single) [_1 = "LineString("] + .else_[_1 = "("]] + << coords + << lit(')') + ; + + polygon = &uint_(mapnik::Polygon)[_1 = _type(_val)] + << string[ phoenix::if_ (single) [_1 = "Polygon("] + .else_[_1 = "("]] + << coords2 + << lit("))") + ; + + point_coord = &uint_ << coord_type << lit(' ') << coord_type + ; + + polygon_coord %= ( &uint_(mapnik::SEG_MOVETO) << eps[_r1 += 1] + << string[ if_ (_r1 > 1) [_1 = "),("] + .else_[_1 = "("] ] | &uint_ << ",") + << coord_type + << lit(' ') + << coord_type + ; + + coords2 %= *polygon_coord(_a) + ; + + coords = point_coord % lit(',') + ; +} + +template +wkt_multi_generator::wkt_multi_generator() + : wkt_multi_generator::base_type(wkt) +{ + using boost::spirit::karma::lit; + using boost::spirit::karma::eps; + using boost::spirit::karma::_val; + using boost::spirit::karma::_1; + using boost::spirit::karma::_a; + + geometry_types.add + (mapnik::Point,"Point") + (mapnik::LineString,"LineString") + (mapnik::Polygon,"Polygon") + ; + + wkt = eps(phoenix::at_c<1>(_a))[_a = _multi_type(_val)] + << lit("GeometryCollection(") << geometry << lit(")") + | eps(is_multi(_val)) << lit("Multi") << geometry_types[_1 = phoenix::at_c<0>(_a)] + << "(" << multi_geometry << ")" + | geometry + ; + + geometry = -(single_geometry % lit(',')) + ; + + single_geometry = geometry_types[_1 = _type(_val)] << path + ; + + multi_geometry = -(path % lit(',')) + ; + +} + +template struct mapnik::util::wkt_generator >; +template struct mapnik::util::wkt_multi_generator >; + + +}} \ No newline at end of file diff --git a/tests/cpp_tests/build.py b/tests/cpp_tests/build.py index 3750717fd..69add55d4 100644 --- a/tests/cpp_tests/build.py +++ b/tests/cpp_tests/build.py @@ -8,8 +8,9 @@ test_env = env.Clone() headers = env['CPPPATH'] -libraries = copy(env['LIBMAPNIK_LIBS']) +libraries = copy(env['LIBMAPNIK_LIBS']) libraries.append('mapnik') +libraries.append('sqlite3') test_env.Append(CXXFLAGS='-g') diff --git a/tests/cpp_tests/exceptions_test.cpp b/tests/cpp_tests/exceptions_test.cpp new file mode 100644 index 000000000..e3d0e6eb2 --- /dev/null +++ b/tests/cpp_tests/exceptions_test.cpp @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" { +#include +} + +int main( int, char*[] ) +{ + try { + mapnik::projection srs("foo"); + // to avoid unused variable warning + srs.params(); + BOOST_TEST(false); + } catch (...) { + BOOST_TEST(true); + } + + mapnik::Map map(256,256); + mapnik::rule r; + r.set_filter(mapnik::parse_expression("[foo]='bar'")); + mapnik::feature_type_style style; + style.add_rule(r); + map.insert_style("style",style); + + std::string csv_plugin("./plugins/input/csv.input"); + if (boost::filesystem::exists(csv_plugin)) { + try { + mapnik::datasource_cache::instance()->register_datasource(csv_plugin); + mapnik::parameters p; + p["type"]="csv"; + p["inline"]="x,y\n0,0"; + mapnik::datasource_ptr ds = mapnik::datasource_cache::instance()->create(p); + //mapnik::datasource_ptr ds = boost::make_shared(); + //mapnik::context_ptr ctx = boost::make_shared(); + //mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx, 1)); + //mapnik::memory_datasource *mem_ds = dynamic_cast(ds.get()); + //mem_ds->push(feature); + mapnik::layer l("layer"); + l.set_datasource(ds); + l.add_style("style"); + mapnik::Map m = map; + m.addLayer(l); + m.zoom_all(); + mapnik::image_32 im(m.width(),m.height()); + mapnik::agg_renderer ren(m,im); + //std::clog << mapnik::save_map_to_string(m) << "\n"; + BOOST_TEST(true); + // should throw here + ren.apply(); + BOOST_TEST(false); + } catch (...) { + BOOST_TEST(true); + } + } + + std::string shape_plugin("./plugins/input/shape.input"); + if (boost::filesystem::exists(shape_plugin)) { + try { + mapnik::datasource_cache::instance()->register_datasource(shape_plugin); + mapnik::parameters p2; + p2["type"]="shape"; + p2["file"]="foo"; + mapnik::datasource_cache::instance()->create(p2); + BOOST_TEST(false); + } catch (...) { + BOOST_TEST(true); + } + } + + /* + // not working, oddly segfaults valgrind + try { + sqlite3_initialize(); + // http://stackoverflow.com/questions/11107703/sqlite3-sigsegvs-with-valgrind + sqlite3_config(SQLITE_CONFIG_HEAP, malloc (1024*1024), 1024*1024, 64); + mapnik::datasource_cache::instance()->register_datasource("./plugins/input/sqlite.input"); + mapnik::parameters p; + p["type"]="sqlite"; + p["file"]="tests/data/sqlite/world.sqlite"; + p["table"]="world_merc"; + mapnik::datasource_cache::instance()->create(p); + sqlite3_shutdown(); + BOOST_TEST(true); + } catch (...) { + BOOST_TEST(false); + } + */ + + if (!::boost::detail::test_errors()) { + std::clog << "C++ exceptions: \x1b[1;32m✓ \x1b[0m\n"; +#if BOOST_VERSION >= 104600 + ::boost::detail::report_errors_remind().called_report_errors_function = true; +#endif + } else { + return ::boost::report_errors(); + } +} diff --git a/tests/data/good_maps/markers_symbolizer_points_file.xml b/tests/data/good_maps/markers_symbolizer_points_file.xml index 7814761ce..304adc572 100644 --- a/tests/data/good_maps/markers_symbolizer_points_file.xml +++ b/tests/data/good_maps/markers_symbolizer_points_file.xml @@ -3,7 +3,7 @@ diff --git a/tests/python_tests/geometry_io_test.py b/tests/python_tests/geometry_io_test.py index b2bce104c..1eeef4db6 100644 --- a/tests/python_tests/geometry_io_test.py +++ b/tests/python_tests/geometry_io_test.py @@ -5,6 +5,7 @@ import os,sys from utilities import execution_path from utilities import Todo import mapnik +from binascii import unhexlify def setup(): # All of the paths used are relative, if we run the tests @@ -27,6 +28,43 @@ wkts = [ [2,"MULTIPOLYGON(((-178.32319 71.518365,-178.321586 71.518439,-178.259635 71.510688,-178.304862 71.513129,-178.32319 71.518365)),((-178.32319 71.518365,-178.341544 71.517524,-178.32244 71.505439,-178.215323 71.478034,-178.193473 71.47663,-178.147757 71.485175,-178.124442 71.481879,-178.005729 71.448615,-178.017203 71.441413,-178.054191 71.428778,-178.047049 71.425727,-178.033439 71.417792,-178.026236 71.415107,-178.030082 71.413459,-178.039908 71.40766,-177.970878 71.39643,-177.779837 71.333197,-177.718375 71.305243,-177.706412 71.3039,-177.68212 71.304877,-177.670279 71.301825,-177.655387 71.293158,-177.587577 71.285956,-177.548575 71.294867,-177.531119 71.296332,-177.51409 71.293402,-177.498649 71.284735,-177.506217 71.268622,-177.486991 71.258734,-177.459708 71.249884,-177.443412 71.237006,-177.445914 71.222663,-177.457755 71.209357,-177.507804 71.173774,-177.581168 71.147589,-177.637626 71.117011,-177.684134 71.110968,-177.751883 71.092963,-177.819266 71.084662,-177.877677 71.052558,-177.930472 71.041449,-178.206595 71.038398,-178.310111 71.013617,-178.875907 70.981024,-178.980277 70.95069,-179.342093 70.908026,-179.336234 70.911078,-179.322257 70.921698,-179.364493 70.930243,-179.457511 70.915534,-179.501212 70.919684,-179.666007 70.965461,-179.853385 70.979438,-179.888785 70.993598,-179.907523 70.996772,-179.999989 70.992011,-179.999989 71.024848,-179.999989 71.058661,-179.999989 71.126166,-179.999989 71.187018,-179.999989 71.224189,-179.999989 71.27497,-179.999989 71.312079,-179.999989 71.356024,-179.999989 71.410041,-179.999989 71.487799,-179.999989 71.536689,-179.862845 71.538642,-179.912223 71.555854,-179.900748 71.558478,-179.798819 71.569098,-179.757438 71.583197,-179.735953 71.586432,-179.715445 71.583258,-179.697501 71.577338,-179.678702 71.573676,-179.610831 71.585211,-179.372062 71.569098,-179.326774 71.555487,-179.306815 71.557563,-179.287162 71.562934,-179.24285 71.569098,-179.204642 71.583197,-179.074576 71.600043,-178.395438 71.539008,-178.32319 71.518365)))"] ] +wkbs = [ + [ 0, "Point EMPTY", '010400000000000000'], + [ 0, "MULTIPOINT EMPTY", '010400000000000000'], + [ 0, "LINESTRING EMPTY", '010200000000000000'], + [ 0, "MULTILINESTRING EMPTY", '010500000000000000'], + [ 0, "Polygon EMPTY", '010300000000000000'], + [ 0, "MULTIPOLYGON EMPTY", '010600000000000000'], + [ 0, "TRIANGLE EMPTY", '011100000000000000'], + + [ 0, "CircularString EMPTY", '010800000000000000'], + [ 0, "CurvePolygon EMPTY", '010A00000000000000'], + [ 0, "CompoundCurve EMPTY", '010900000000000000'], + [ 0, "MultiCurve EMPTY", '010B00000000000000'], + + [ 0, "MultiSurface EMPTY", '010C00000000000000'], + [ 0, "PolyhedralSurface EMPTY", '010F00000000000000'], + [ 0, "TIM EMPTY", '011000000000000000'], + [ 0, "GEOMETRYCOLLECTION EMPTY", '010700000000000000'], + [ 2, "GEOMETRYCOLLECTION(MULTILINESTRING((10 10,20 20,10 40),(40 40,30 30,40 20,30 10)),LINESTRING EMPTY)", '010700000002000000010500000002000000010200000003000000000000000000244000000000000024400000000000003440000000000000344000000000000024400000000000004440010200000004000000000000000000444000000000000044400000000000003e400000000000003e40000000000000444000000000000034400000000000003e400000000000002440010200000000000000' + ], + [ 0, "GEOMETRYCOLLECTION(LINESTRING EMPTY,LINESTRING EMPTY)", '010700000000000000'], + [ 0, "GEOMETRYCOLLECTION(POINT EMPTY,POINT EMPTY)", '010700000000000000'], + [ 1, "GEOMETRYCOLLECTION(POINT EMPTY,POINT(0 0))", '010700000002000000010400000000000000010100000000000000000000000000000000000000'], + [ 1, "GEOMETRYCOLLECTION(POINT EMPTY,MULTIPOINT(0 0))", '010700000002000000010400000000000000010400000001000000010100000000000000000000000000000000000000'], + [ 0, "LINESTRING EMPTY", '010200000000000000' ], + [ 1, "Point(0 0)", '010100000000000000000000000000000000000000' ], +] + +def test_wkb_parsing(): + for wkb in wkbs: + path = mapnik.Path() + success = path.add_wkb(unhexlify(wkb[2])) + if wkb[0] > 0: + eq_(success,True) + else: + eq_(success,False) + eq_(wkb[0],len(path)) def compare_wkb_from_wkt(wkt,num=None): diff --git a/tests/python_tests/object_test.py b/tests/python_tests/object_test.py index 44517286f..7806ada66 100644 --- a/tests/python_tests/object_test.py +++ b/tests/python_tests/object_test.py @@ -127,15 +127,14 @@ def test_markersymbolizer_init(): p = mapnik.MarkersSymbolizer() eq_(p.allow_overlap, False) eq_(p.opacity,1) - eq_(p.filename,'') - eq_(p.marker_type,mapnik.marker_type.ARROW) - eq_(p.placement,mapnik.marker_placement.LINE_PLACEMENT) - eq_(p.fill,mapnik.Color(0,0,255)) + eq_(p.filename,'shape://ellipse') + eq_(p.placement,mapnik.marker_placement.POINT_PLACEMENT) + eq_(p.fill,None) eq_(p.ignore_placement,False) eq_(p.spacing,100) eq_(p.max_error,0.2) - eq_(str(p.width),'10.0') - eq_(str(p.height),'10.0') + eq_(p.width,None) + eq_(p.height,None) p.width = mapnik.Expression('12') p.height = mapnik.Expression('12') diff --git a/tests/python_tests/query_test.py b/tests/python_tests/query_test.py new file mode 100644 index 000000000..ec636da09 --- /dev/null +++ b/tests/python_tests/query_test.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import os, mapnik + +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_query_init(): + bbox = (-180, -90, 180, 90) + query = mapnik.Query(mapnik.Box2d(*bbox)) + r = query.resolution + assert_almost_equal(r[0], 1.0, places=7) + assert_almost_equal(r[1], 1.0, places=7) + +# Converting *from* tuples *to* resolutions is not yet supported +@raises(TypeError) +def test_query_resolution(): + bbox = (-180, -90, 180, 90) + init_res = (4.5, 6.7) + query = mapnik.Query(mapnik.Box2d(*bbox), init_res) + r = query.resolution + assert_almost_equal(r[0], init_res[0], places=7) + assert_almost_equal(r[1], init_res[1], places=7) + +if __name__ == "__main__": + setup() + [eval(run)() for run in dir() if 'test_' in run] diff --git a/tests/python_tests/raster_symbolizer_test.py b/tests/python_tests/raster_symbolizer_test.py index 2962bab5e..ba3e492cf 100644 --- a/tests/python_tests/raster_symbolizer_test.py +++ b/tests/python_tests/raster_symbolizer_test.py @@ -116,9 +116,7 @@ def test_raster_with_alpha_blends_correctly_with_background(): style = mapnik.Style() rule = mapnik.Rule() symbolizer = mapnik.RasterSymbolizer() - #XXX: This fixes it, see http://trac.mapnik.org/ticket/759#comment:3 - # (and remove comment when this test passes) - #symbolizer.scaling="bilinear_old" + symbolizer.scaling = mapnik.scaling_method.BILINEAR rule.symbols.append(symbolizer) style.rules.append(rule) diff --git a/tests/python_tests/render_grid_test.py b/tests/python_tests/render_grid_test.py index 3b77ccf3d..f2ce75b3c 100644 --- a/tests/python_tests/render_grid_test.py +++ b/tests/python_tests/render_grid_test.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- from nose.tools import * - +from utilities import execution_path import os, mapnik try: @@ -10,11 +10,24 @@ try: except ImportError: import simplejson as json -grid_correct = {"keys": ["", "North West", "North East", "South West", "South East"], "data": {"South East": {"Name": "South East"}, "North East": {"Name": "North East"}, "North West": {"Name": "North West"}, "South West": {"Name": "South West"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !!! ### ", " !!!!! ##### ", " !!!!! ##### ", " !!! ### ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$$$ %%%% ", " $$$$$ %%%%% ", " $$$$$ %%%%% ", " $$$ %%% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "]} +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('.')) +# first pass impl where resolution is passed as render +# time rather than encoding time, likely will be deprecated soon +grid_correct_old = {"keys": ["", "North West", "North East", "South West", "South East"], "data": {"South East": {"Name": "South East"}, "North East": {"Name": "North East"}, "North West": {"Name": "North West"}, "South West": {"Name": "South West"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !!! ### ", " !!!!! ##### ", " !!!!! ##### ", " !!! ### ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$$$ %%%% ", " $$$$$ %%%%% ", " $$$$$ %%%%% ", " $$$ %%% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "]} +# now using svg rendering +grid_correct_old2 = {"data": {"North East": {"Name": "North East"}, "North West": {"Name": "North West"}, "South East": {"Name": "South East"}, "South West": {"Name": "South West"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !!! ### ", " !!! ### ", " !!! ### ", " !!! ### ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$$ %%% ", " $$$ %%% ", " $$$ %%% ", " $ % ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "], "keys": ["", "North West", "North East", "South West", "South East"]} + +# previous rendering using agg ellipse directly grid_correct_new = {"keys": ["", "North West", "North East", "South West", "South East"], "data": {"South East": {"Name": "South East"}, "North East": {"Name": "North East"}, "North West": {"Name": "North West"}, "South West": {"Name": "South West"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !! ## ", " !!! ### ", " !! ## ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$$ %% ", " $$$ %%% ", " $$ %% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "]} +# newer rendering using svg +grid_correct_new2 = {"data": {"North East": {"Name": "North East"}, "North West": {"Name": "North West"}, "South East": {"Name": "South East"}, "South West": {"Name": "South West"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !! ## ", " !!! ## ", " !! ## ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$ %% ", " $$ %% ", " $ % ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "], "keys": ["", "North West", "North East", "South West", "South East"]} + def resolve(grid,row,col): """ Resolve the attributes for a given pixel in a grid. """ @@ -31,7 +44,7 @@ def resolve(grid,row,col): return grid['data'].get(key) -def create_grid_map(width,height): +def create_grid_map(width,height,marker=True): ds = mapnik.MemoryDatasource() context = mapnik.Context() context.push('Name') @@ -56,9 +69,12 @@ def create_grid_map(width,height): ds.add_feature(f) s = mapnik.Style() r = mapnik.Rule() - symb = mapnik.MarkersSymbolizer() - symb.width = mapnik.Expression('10') - symb.height = mapnik.Expression('10') + if marker: + symb = mapnik.MarkersSymbolizer() + symb.width = mapnik.Expression('10') + symb.height = mapnik.Expression('10') + else: + symb = mapnik.PointSymbolizer(mapnik.PathExpression('../data/images/dummy.png')) symb.allow_overlap = True r.symbols.append(symb) @@ -71,15 +87,37 @@ def create_grid_map(width,height): m.layers.append(lyr) return m +def show_grids(name,g1,g2): + g1_file = '/tmp/mapnik-%s-actual.json' % name + open(g1_file,'w').write(json.dumps(g1,sort_keys=True)) + g2_file = '/tmp/mapnik-%s-expected.json' % name + open(g2_file,'w').write(json.dumps(g2,sort_keys=True)) + val = 'JSON does not match ->\n' + if g1['grid'] != g2['grid']: + val += ' X grid does not match\n' + else: + val += ' ✓ grid matches\n' + if g1['data'].keys() != g2['data'].keys(): + val += ' X data does not match\n' + else: + val += ' ✓ data matches\n' + if g1['keys'] != g2['keys']: + val += ' X keys do not\n' + else: + val += ' ✓ keys match\n' + val += '\n\t%s\n\t%s' % (g1_file,g2_file) + return val + def test_render_grid(): """ test old method """ width,height = 256,256 m = create_grid_map(width,height) + #print mapnik.save_map_to_string(m) ul_lonlat = mapnik.Coord(142.30,-38.20) lr_lonlat = mapnik.Coord(143.40,-38.80) m.zoom_to_box(mapnik.Box2d(ul_lonlat,lr_lonlat)) grid = mapnik.render_grid(m,0,key='Name',resolution=4,fields=['Name']) - eq_(grid,grid_correct) + eq_(grid,grid_correct_old2,show_grids('old',grid,grid_correct_old2)) eq_(resolve(grid,0,0),None) # check every pixel of the nw symbol @@ -90,23 +128,6 @@ def test_render_grid(): eq_(resolve(grid,23,10),expected) eq_(resolve(grid,23,11),expected) - # core - eq_(resolve(grid,24,8),expected) - eq_(resolve(grid,24,9),expected) - eq_(resolve(grid,24,10),expected) - eq_(resolve(grid,24,11),expected) - eq_(resolve(grid,24,12),expected) - eq_(resolve(grid,25,8),expected) - eq_(resolve(grid,25,9),expected) - eq_(resolve(grid,25,10),expected) - eq_(resolve(grid,25,11),expected) - eq_(resolve(grid,25,12),expected) - - # bottom row - eq_(resolve(grid,26,9),expected) - eq_(resolve(grid,26,10),expected) - eq_(resolve(grid,26,11),expected) - def test_render_grid2(): """ test old against new""" width,height = 256,256 @@ -119,16 +140,7 @@ def test_render_grid2(): grid = mapnik.Grid(m.width,m.height,key='Name') mapnik.render_layer(m,grid,layer=0,fields=['Name']) utf1 = grid.encode('utf',resolution=4) - eq_(utf1,grid_correct_new) - - # old method - to be removed - utf2 = mapnik.render_grid(m,0,key='Name',resolution=4,fields=['Name']) - eq_(utf2,grid_correct) - - # for complex polygons these will not be true - eq_(len(utf2['grid']),len(utf1['grid'])) - eq_(len(utf2['keys']),len(utf1['keys'])) - eq_(len(utf2['data']),len(utf1['data'])) + eq_(utf1,grid_correct_new2,show_grids('new',utf1,grid_correct_new2)) # check a full view is the same as a full image grid_view = grid.view(0,0,width,height) @@ -152,6 +164,8 @@ def test_render_grid2(): grid_feat_id = {'keys': ['', '3', '4', '2', '1'], 'data': {'1': {'Name': 'South East'}, '3': {'Name': u'North West'}, '2': {'Name': 'South West'}, '4': {'Name': 'North East'}}, 'grid': [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' !! ## ', ' !!! ### ', ' !! ## ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' $$$ %% ', ' $$$ %%% ', ' $$ %% ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']} +grid_feat_id2 = {"data": {"1": {"Name": "South East"}, "2": {"Name": "South West"}, "3": {"Name": "North West"}, "4": {"Name": "North East"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !! ## ", " !!! ## ", " !! ## ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$ %% ", " $$ %% ", " $ % ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "], "keys": ["", "3", "4", "2", "1"]} + def test_render_grid3(): """ test using feature id""" width,height = 256,256 @@ -163,10 +177,7 @@ def test_render_grid3(): grid = mapnik.Grid(m.width,m.height,key='__id__') mapnik.render_layer(m,grid,layer=0,fields=['__id__','Name']) utf1 = grid.encode('utf',resolution=4) - eq_(utf1['keys'],grid_feat_id['keys']) - eq_(utf1['grid'],grid_feat_id['grid']) - eq_(utf1['data'],grid_feat_id['data']) - eq_(utf1,grid_feat_id) + eq_(utf1,grid_feat_id2,show_grids('id',utf1,grid_feat_id2)) # check a full view is the same as a full image grid_view = grid.view(0,0,width,height) # for kicks check at full res too @@ -240,5 +251,54 @@ def test_id_zero(): utf1 = grid.encode('utf',resolution=4) eq_(utf1['keys'],['0']) +line_expected = {"keys": ["", "1"], "data": {"1": {"Name": "1"}}, "grid": [" !", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", "!! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! "]} + +def test_line_rendering(): + 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('LINESTRING (30 10, 10 30, 40 40)') + ds.add_feature(f) + s = mapnik.Style() + r = mapnik.Rule() + symb = mapnik.LineSymbolizer() + 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() + #mapnik.render_to_file(m,'test.png') + grid = mapnik.Grid(m.width,m.height,key='__id__') + mapnik.render_layer(m,grid,layer=0,fields=['__id__','Name']) + utf1 = grid.encode() + eq_(utf1,line_expected,show_grids('line',utf1,line_expected)) + #open('test.json','w').write(json.dumps(grid.encode())) + +point_expected = {"keys": ["", "3", "4", "2", "1"], "data": {"1": {"Name": "South East"}, "3": {"Name": "North West"}, "2": {"Name": "South West"}, "4": {"Name": "North East"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !!!! #### ", " !!!! #### ", " !!!! #### ", " !!!! #### ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$$$ %%%% ", " $$$$ %%%% ", " $$$$ %%%% ", " $$$$ %%%% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "]} + +def test_point_symbolizer_grid(): + width,height = 256,256 + m = create_grid_map(width,height,marker=False) + ul_lonlat = mapnik.Coord(142.30,-38.20) + lr_lonlat = mapnik.Coord(143.40,-38.80) + m.zoom_to_box(mapnik.Box2d(ul_lonlat,lr_lonlat)) + #mapnik.render_to_file(m,'test.png') + #print mapnik.save_map_to_string(m) + grid = mapnik.Grid(m.width,m.height) + mapnik.render_layer(m,grid,layer=0,fields=['Name']) + utf1 = grid.encode() + #open('test.json','w').write(json.dumps(grid.encode())) + eq_(utf1,point_expected,show_grids('point-sym',utf1,point_expected)) + + if __name__ == "__main__": + setup() [eval(run)() for run in dir() if 'test_' in run] diff --git a/tests/python_tests/render_test.py b/tests/python_tests/render_test.py index c0808a1a0..19e547f26 100644 --- a/tests/python_tests/render_test.py +++ b/tests/python_tests/render_test.py @@ -95,100 +95,6 @@ def test_render_from_serialization(): if not 'Could not create datasource' in str(e): raise RuntimeError(e) -grid_correct = {"keys": ["", "North West", "North East", "South West", "South East"], "data": {"South East": {"Name": "South East"}, "North East": {"Name": "North East"}, "North West": {"Name": "North West"}, "South West": {"Name": "South West"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !!! ### ", " !!!!! ##### ", " !!!!! ##### ", " !!! ### ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$$$ %%%% ", " $$$$$ %%%%% ", " $$$$$ %%%%% ", " $$$ %%% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "]} - - -def resolve(grid,x,y): - """ Resolve the attributes for a given pixel in a grid. - - js version: - https://github.com/mapbox/mbtiles-spec/blob/master/1.1/utfgrid.md - spec: - https://github.com/mapbox/wax/blob/master/control/lib/gridutil.js - - """ - utf_val = grid['grid'][x][y] - #http://docs.python.org/library/functions.html#ord - codepoint = ord(utf_val) - if (codepoint >= 93): - codepoint-=1 - if (codepoint >= 35): - codepoint-=1 - codepoint -= 32 - key = grid['keys'][codepoint] - return grid['data'].get(key) - - -def test_render_grid(): - ds = mapnik.MemoryDatasource() - context = mapnik.Context() - context.push('Name') - f = mapnik.Feature(context,1) - f['Name'] = 'South East' - f.add_geometries_from_wkt('POINT (143.10 -38.60)') - ds.add_feature(f) - - f = mapnik.Feature(context,2) - f['Name'] = 'South West' - f.add_geometries_from_wkt('POINT (142.48 -38.60)') - ds.add_feature(f) - - f = mapnik.Feature(context,3) - f['Name'] = 'North West' - f.add_geometries_from_wkt('POINT (142.48 -38.38)') - ds.add_feature(f) - - f = mapnik.Feature(context,4) - f['Name'] = 'North East' - f.add_geometries_from_wkt('POINT (143.10 -38.38)') - ds.add_feature(f) - - s = mapnik.Style() - r = mapnik.Rule() - symb = mapnik.MarkersSymbolizer() - symb.width = mapnik.Expression('10') - symb.height = mapnik.Expression('10') - symb.allow_overlap = True - r.symbols.append(symb) - s.rules.append(r) - lyr = mapnik.Layer('Places') - lyr.datasource = ds - lyr.styles.append('places_labels') - m = mapnik.Map(256,256) - m.append_style('places_labels',s) - m.layers.append(lyr) - ul_lonlat = mapnik.Coord(142.30,-38.20) - lr_lonlat = mapnik.Coord(143.40,-38.80) - m.zoom_to_box(mapnik.Box2d(ul_lonlat,lr_lonlat)) - grid = mapnik.render_grid(m,0,key='Name',resolution=4,fields=['Name']) - eq_(grid,grid_correct) - eq_(resolve(grid,0,0),None) - - # check every pixel of the nw symbol - expected = {"Name": "North West"} - - # top row - eq_(resolve(grid,23,9),expected) - eq_(resolve(grid,23,10),expected) - eq_(resolve(grid,23,11),expected) - - # core - eq_(resolve(grid,24,8),expected) - eq_(resolve(grid,24,9),expected) - eq_(resolve(grid,24,10),expected) - eq_(resolve(grid,24,11),expected) - eq_(resolve(grid,24,12),expected) - eq_(resolve(grid,25,8),expected) - eq_(resolve(grid,25,9),expected) - eq_(resolve(grid,25,10),expected) - eq_(resolve(grid,25,11),expected) - eq_(resolve(grid,25,12),expected) - - # bottom row - eq_(resolve(grid,26,9),expected) - eq_(resolve(grid,26,10),expected) - eq_(resolve(grid,26,11),expected) - def test_render_points(): if not mapnik.has_cairo(): return diff --git a/tests/visual_tests/compare.py b/tests/visual_tests/compare.py index 4e57127c0..98edde22a 100644 --- a/tests/visual_tests/compare.py +++ b/tests/visual_tests/compare.py @@ -1,8 +1,7 @@ # -*- coding: utf-8 -*- -#import math, operator -import Image import sys +import mapnik COMPUTE_THRESHOLD = 16 @@ -11,37 +10,43 @@ passed = 0 # returns true if pixels are not identical def compare_pixels(pixel1, pixel2): - r_diff = abs(pixel1[0] - pixel2[0]) - g_diff = abs(pixel1[1] - pixel2[1]) - b_diff = abs(pixel1[2] - pixel2[2]) - if(r_diff > COMPUTE_THRESHOLD or g_diff > COMPUTE_THRESHOLD or b_diff > COMPUTE_THRESHOLD): + if pixel1 == pixel2: + return False + # will only work on little endian + r_diff = abs((pixel1 & 0xff) - (pixel2 & 0xff)) + g_diff = abs(((pixel1 >> 8) & 0xff) - ((pixel2 >> 8) & 0xff)) + b_diff = abs(((pixel1 >> 16) & 0xff)- ((pixel2 >> 16) & 0xff)) + a_diff = abs(((pixel1 >> 24) & 0xff) - ((pixel2 >> 24) & 0xff)) + if(r_diff > COMPUTE_THRESHOLD or + g_diff > COMPUTE_THRESHOLD or + b_diff > COMPUTE_THRESHOLD or + a_diff > COMPUTE_THRESHOLD): return True else: return False -# compare tow images and return number of different pixels -def compare(fn1, fn2): +# compare two images and return number of different pixels +def compare(actual, expected): global errors global passed - im1 = Image.open(fn1) + im1 = mapnik.Image.open(actual) try: - im2 = Image.open(fn2) + im2 = mapnik.Image.open(expected) except IOError: - errors.append((None, fn1, fn2)) + errors.append((None, actual, expected)) return -1 diff = 0 - pixels = im1.size[0] * im1.size[1] - delta_pixels = im2.size[0] * im2.size[1] - pixels + pixels = im1.width() * im1.height() + delta_pixels = (im2.width() * im2.height()) - pixels if delta_pixels != 0: - errors.append((delta_pixels, fn1, fn2)) + errors.append((delta_pixels, actual, expected)) return delta_pixels - im1 = im1.getdata() - im2 = im2.getdata() - for i in range(3, pixels - 1, 3): - if(compare_pixels(im1[i], im2[i])): - diff = diff + 1 + for x in range(0,im1.width(),2): + for y in range(0,im1.height(),2): + if compare_pixels(im1.get_pixel(x,y),im2.get_pixel(x,y)): + diff += 1 if diff != 0: - errors.append((diff, fn1, fn2)) + errors.append((diff, actual, expected)) passed += 1 return diff diff --git a/utils/pgsql2sqlite/pgsql2sqlite.hpp b/utils/pgsql2sqlite/pgsql2sqlite.hpp index faa3f3e40..2d8583caa 100644 --- a/utils/pgsql2sqlite/pgsql2sqlite.hpp +++ b/utils/pgsql2sqlite/pgsql2sqlite.hpp @@ -281,8 +281,8 @@ void pgsql2sqlite(Connection conn, if (oid == geometry_oid) { mapnik::Feature feat(ctx,pkid); - geometry_utils::from_wkb(feat.paths(),buf,size,wkbGeneric); - if (feat.num_geometries() > 0) + if (geometry_utils::from_wkb(feat.paths(),buf,size,wkbGeneric) + && feat.num_geometries() > 0) { geometry_type const& geom=feat.get_geometry(0); box2d bbox = geom.envelope(); diff --git a/utils/svg2png/svg2png.cpp b/utils/svg2png/svg2png.cpp index 63aa5725d..2c9113b08 100644 --- a/utils/svg2png/svg2png.cpp +++ b/utils/svg2png/svg2png.cpp @@ -55,7 +55,7 @@ int main (int argc,char** argv) bool verbose = false; bool auto_open = false; - bool error = false; + int return_value = 0; std::vector svg_files; mapnik::logger logger; logger.set_severity(mapnik::logger::error); @@ -131,14 +131,14 @@ int main (int argc,char** argv) if (!marker_ptr) { std::clog << "svg2png error: could not open: '" << svg_name << "'\n"; - error = true; + return_value = -1; continue; } mapnik::marker marker = **marker_ptr; if (!marker.is_vector()) { std::clog << "svg2png error: '" << svg_name << "' is not a valid vector!\n"; - error = true; + return_value = -1; continue; } @@ -149,7 +149,6 @@ int main (int argc,char** argv) agg::scanline_u8 sl; double opacity = 1; - double scale_factor_ = .95; int w = marker.width(); int h = marker.height(); if (verbose) @@ -165,8 +164,6 @@ int main (int argc,char** argv) mapnik::coord c = bbox.center(); // center the svg marker on '0,0' agg::trans_affine mtx = agg::trans_affine_translation(-c.x,-c.y); - // apply symbol transformation to get to map space - mtx *= agg::trans_affine_scaling(scale_factor_); // render the marker at the center of the marker box mtx.translate(0.5 * w, 0.5 * h); @@ -182,14 +179,18 @@ int main (int argc,char** argv) boost::algorithm::ireplace_last(svg_name,".svg",".png"); mapnik::save_to_file(im.data(),svg_name,"png"); -#ifdef DARWIN if (auto_open) { std::ostringstream s; +#ifdef DARWIN s << "open " << svg_name; - system(s.str().c_str()); - } +#else + s << "xdg-open " << svg_name; #endif + int ret = system(s.str().c_str()); + if (ret != 0) + return_value = ret; + } std::clog << "rendered to: " << svg_name << "\n"; } } @@ -204,7 +205,5 @@ int main (int argc,char** argv) // to make sure valgrind output is clean // http://xmlsoft.org/xmlmem.html xmlCleanupParser(); - if (error) - return -1; - return 0; + return return_value; } diff --git a/workspace/mapnik.pro b/workspace/mapnik.pro index ce6f36356..32b1d2333 100644 --- a/workspace/mapnik.pro +++ b/workspace/mapnik.pro @@ -69,7 +69,6 @@ HEADERS += \ ../include/mapnik/agg_pattern_source.hpp \ ../include/mapnik/agg_rasterizer.hpp \ ../include/mapnik/agg_renderer.hpp \ - ../include/mapnik/arrow.hpp \ ../include/mapnik/attribute.hpp \ ../include/mapnik/attribute_collector.hpp \ ../include/mapnik/attribute_descriptor.hpp \