[mapnik] 01/05: Imported Upstream version 3.0.11+ds

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Sat Apr 2 01:09:16 UTC 2016


This is an automated email from the git hooks/post-receive script.

sebastic pushed a commit to branch master
in repository mapnik.

commit d34dadb098fac6b41dffd57cec44c558137fdf78
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Sat Apr 2 01:36:47 2016 +0200

    Imported Upstream version 3.0.11+ds
---
 .travis.yml                                        |  60 +-
 CHANGELOG.md                                       |  11 +
 Makefile                                           |  15 +-
 SConstruct                                         |  16 +-
 appveyor.yml                                       |  14 +-
 benchmark/bench_framework.hpp                      | 117 ++-
 benchmark/compare_images.hpp                       |  15 +-
 benchmark/run                                      |  13 +-
 benchmark/test_getline.cpp                         |   6 +-
 bootstrap.sh                                       |  10 +-
 circle.yml                                         |  49 ++
 include/mapnik/agg_helpers.hpp                     |   4 +-
 include/mapnik/agg_pattern_source.hpp              |   4 +-
 include/mapnik/agg_rasterizer.hpp                  |   5 +-
 include/mapnik/agg_render_marker.hpp               |   4 +-
 include/mapnik/box2d.hpp                           |  18 +-
 include/mapnik/cairo/cairo_context.hpp             |  12 +-
 include/mapnik/color.hpp                           |   4 +-
 include/mapnik/coord.hpp                           |   4 +-
 include/mapnik/css_color_grammar.hpp               | 244 +-----
 include/mapnik/css_color_grammar_impl.hpp          | 230 +++++
 include/mapnik/csv/csv_grammar.hpp                 |  44 +-
 .../csv_grammar_impl.hpp}                          |  62 +-
 .../csv_types.hpp}                                 |  14 +-
 include/mapnik/expression_grammar.hpp              |  75 +-
 include/mapnik/expression_grammar_impl.hpp         |  71 +-
 include/mapnik/expression_node.hpp                 |   2 +
 include/mapnik/feature_kv_iterator.hpp             |   4 +-
 include/mapnik/feature_type_style.hpp              |   4 +-
 include/mapnik/global.hpp                          |  16 +-
 include/mapnik/gradient.hpp                        |   4 +-
 include/mapnik/grid/grid_rasterizer.hpp            |   4 +
 include/mapnik/grid/grid_render_marker.hpp         |   5 +-
 include/mapnik/grid/grid_renderer_base.hpp         |   6 +-
 include/mapnik/grid/grid_rendering_buffer.hpp      |   4 +
 include/mapnik/hextree.hpp                         |  26 +-
 include/mapnik/image_compositing.hpp               |   4 +-
 include/mapnik/image_filter.hpp                    |   5 +-
 include/mapnik/image_filter_grammar.hpp            |   9 +-
 include/mapnik/image_filter_grammar_impl.hpp       |   3 +
 include/mapnik/image_options.hpp                   |   5 +
 include/mapnik/image_reader.hpp                    |   6 +-
 include/mapnik/image_scaling.hpp                   |   5 +-
 include/mapnik/image_scaling_traits.hpp            |   4 +-
 include/mapnik/json/error_handler.hpp              |   9 +-
 .../mapnik/json/extract_bounding_box_grammar.hpp   |  62 +-
 .../json/extract_bounding_box_grammar_impl.hpp     |  50 +-
 include/mapnik/json/feature_grammar.hpp            |   9 +-
 include/mapnik/json/geometry_generator_grammar.hpp |   2 +-
 .../json/geometry_generator_grammar_impl.hpp       |   1 +
 include/mapnik/json/geometry_grammar.hpp           |   4 +-
 include/mapnik/json/geometry_grammar_impl.hpp      |   6 +-
 include/mapnik/json/geometry_parser.hpp            |  18 +-
 include/mapnik/json/geometry_util.hpp              |   1 +
 .../{agg_rasterizer.hpp => json/positions.hpp}     |  20 +-
 include/mapnik/json/positions_grammar.hpp          |  12 +-
 include/mapnik/json/positions_grammar_impl.hpp     |   2 +-
 .../mapnik/json/properties_generator_grammar.hpp   |  13 +-
 include/mapnik/json/symbolizer_grammar.hpp         | 216 -----
 include/mapnik/json/topojson_grammar.hpp           |   8 +-
 include/mapnik/json/topojson_grammar_impl.hpp      | 115 ++-
 include/mapnik/json/topojson_utils.hpp             | 368 +++++++-
 include/mapnik/json/topology.hpp                   |  73 --
 include/mapnik/label_collision_detector.hpp        |   4 +-
 include/mapnik/map.hpp                             |   4 +-
 include/mapnik/mapped_memory_cache.hpp             |   5 +
 include/mapnik/marker.hpp                          |   4 +-
 include/mapnik/marker_helpers.hpp                  |  96 +--
 include/mapnik/markers_placement.hpp               | 118 ++-
 include/mapnik/markers_placements/basic.hpp        | 104 +++
 include/mapnik/markers_placements/interior.hpp     |  24 +-
 include/mapnik/markers_placements/line.hpp         |  30 +-
 include/mapnik/markers_placements/point.hpp        | 123 +--
 .../mapnik/markers_placements/vertext_first.hpp    |  24 +-
 include/mapnik/markers_placements/vertext_last.hpp |  21 +-
 include/mapnik/params.hpp                          |   5 +-
 include/mapnik/path_expression_grammar_impl.hpp    |   5 +-
 include/mapnik/png_io.hpp                          |  28 +-
 include/mapnik/projection.hpp                      |   4 +-
 include/mapnik/ptree_helpers.hpp                   |   4 +-
 include/mapnik/quad_tree.hpp                       |  80 +-
 include/mapnik/raster.hpp                          |   5 +-
 include/mapnik/raster_colorizer.hpp                |  11 +-
 .../renderer_common/process_raster_symbolizer.hpp  |   4 +-
 include/mapnik/simplify.hpp                        |   4 +-
 include/mapnik/simplify_converter.hpp              |   2 +-
 include/mapnik/span_image_filter.hpp               |  45 +-
 ...id_rendering_buffer.hpp => stringify_macro.hpp} |  19 +-
 include/mapnik/svg/geometry_svg_generator.hpp      |   6 +-
 include/mapnik/svg/output/svg_output_grammars.hpp  |  45 -
 .../mapnik/svg/output/svg_output_grammars_impl.hpp |  45 +
 include/mapnik/svg/svg_converter.hpp               |   4 +-
 include/mapnik/svg/svg_path_adapter.hpp            |   4 +-
 include/mapnik/svg/svg_path_attributes.hpp         |  12 +-
 include/mapnik/svg/svg_path_commands.hpp           | 223 ++---
 include/mapnik/svg/svg_path_grammar.hpp            | 135 +--
 include/mapnik/svg/svg_path_grammar_impl.hpp       | 112 +++
 include/mapnik/svg/svg_path_parser.hpp             |  28 +-
 include/mapnik/svg/svg_points_grammar.hpp          |  50 +-
 ...nts_grammar.hpp => svg_points_grammar_impl.hpp} |  65 +-
 include/mapnik/svg/svg_renderer_agg.hpp            |   4 +-
 include/mapnik/svg/svg_transform_grammar.hpp       | 247 +-----
 include/mapnik/svg/svg_transform_grammar_impl.hpp  | 172 ++++
 include/mapnik/symbolizer.hpp                      |   4 +-
 include/mapnik/text/face.hpp                       |   6 +-
 include/mapnik/text/font_feature_settings.hpp      |   8 +-
 include/mapnik/text/formatting/layout.hpp          |   3 +
 include/mapnik/text/glyph_positions.hpp            |   4 +-
 include/mapnik/text/harfbuzz_shaper.hpp            |   6 +-
 include/mapnik/text/icu_shaper.hpp                 |   5 +-
 include/mapnik/text/itemizer.hpp                   |   4 +-
 include/mapnik/text/properties_util.hpp            |   7 +-
 include/mapnik/text/renderer.hpp                   |   7 +-
 include/mapnik/text/scrptrun.hpp                   |   3 +
 include/mapnik/text/symbolizer_helpers.hpp         |   2 +-
 include/mapnik/text/text_properties.hpp            |   4 +-
 include/mapnik/tiff_io.hpp                         |   6 +
 include/mapnik/transform_expression.hpp            |   6 +-
 include/mapnik/transform_processor.hpp             |   5 +-
 include/mapnik/unicode.hpp                         |   4 +
 include/mapnik/util/const_rendering_buffer.hpp     |   3 +
 include/mapnik/util/file_io.hpp                    |   7 +-
 include/mapnik/util/geometry_to_ds_type.hpp        |   7 +-
 include/mapnik/util/geometry_to_geojson.hpp        |  11 +-
 include/mapnik/util/path_iterator.hpp              |   5 +-
 include/mapnik/util/spatial_index.hpp              |  41 +-
 include/mapnik/util/variant.hpp                    |   6 +-
 include/mapnik/value.hpp                           | 920 +-------------------
 include/mapnik/value_hash.hpp                      |   4 +-
 include/mapnik/value_types.hpp                     |   5 +-
 include/mapnik/version.hpp                         |   9 +-
 include/mapnik/vertex_adapters.hpp                 | 185 +---
 include/mapnik/vertex_cache.hpp                    |   4 +-
 include/mapnik/vertex_converters.hpp               |   6 +-
 include/mapnik/warning_ignore.hpp                  |  23 +-
 .../{warning_ignore.hpp => warning_ignore_agg.hpp} |  13 +-
 include/mapnik/well_known_srs.hpp                  |   7 +-
 include/mapnik/wkb.hpp                             |   8 +-
 include/mapnik/wkt/wkt_generator_grammar.hpp       |   1 -
 include/mapnik/wkt/wkt_generator_grammar_impl.hpp  |   8 +-
 include/mapnik/wkt/wkt_grammar.hpp                 |   3 +-
 include/mapnik/wkt/wkt_grammar_impl.hpp            |   6 +-
 include/mapnik/xml_node.hpp                        |   4 +-
 mason_latest.sh                                    |  37 +-
 plugins/input/csv/build.py                         |   1 +
 plugins/input/csv/csv_datasource.cpp               | 348 ++------
 plugins/input/csv/csv_datasource.hpp               |  23 +-
 plugins/input/csv/csv_featureset.cpp               |   6 +-
 plugins/input/csv/csv_featureset.hpp               |   5 +-
 plugins/input/csv/csv_getline.hpp                  |  72 ++
 plugins/input/csv/csv_index_featureset.cpp         |   6 +-
 plugins/input/csv/csv_index_featureset.hpp         |   4 +-
 plugins/input/csv/csv_inline_featureset.cpp        |   6 +-
 plugins/input/csv/csv_inline_featureset.hpp        |   5 +-
 plugins/input/csv/csv_utils.cpp                    | 507 +++++++++++
 plugins/input/csv/csv_utils.hpp                    | 321 +------
 plugins/input/gdal/gdal_datasource.cpp             |  41 +-
 plugins/input/gdal/gdal_datasource.hpp             |   3 +-
 plugins/input/gdal/gdal_featureset.cpp             |   7 +-
 plugins/input/gdal/gdal_featureset.hpp             |   5 +-
 plugins/input/geojson/geojson_datasource.cpp       |  14 +-
 plugins/input/geojson/geojson_index_featureset.cpp |   1 -
 .../geojson/geojson_memory_index_featureset.cpp    |   1 -
 plugins/input/pgraster/pgraster_wkb_reader.cpp     |  15 +-
 plugins/input/postgis/postgis_datasource.cpp       | 113 ++-
 plugins/input/postgis/postgis_datasource.hpp       |   7 +
 plugins/input/postgis/postgis_featureset.cpp       |  16 +-
 plugins/input/postgis/postgis_featureset.hpp       |   4 +-
 plugins/input/topojson/topojson_datasource.cpp     |   2 +-
 plugins/input/topojson/topojson_featureset.cpp     | 335 +-------
 scripts/build-appveyor.bat                         |   6 +-
 scripts/travis-common.sh                           |  41 +-
 src/agg/agg_renderer.cpp                           |   9 +-
 src/agg/process_building_symbolizer.cpp            |   5 +-
 src/agg/process_debug_symbolizer.cpp               |   4 +-
 src/agg/process_dot_symbolizer.cpp                 |   4 +-
 src/agg/process_group_symbolizer.cpp               |   4 +-
 src/agg/process_line_pattern_symbolizer.cpp        |   6 +-
 src/agg/process_line_symbolizer.cpp                |   5 +-
 src/agg/process_markers_symbolizer.cpp             |   4 +-
 src/agg/process_point_symbolizer.cpp               |   4 +-
 src/agg/process_polygon_pattern_symbolizer.cpp     |   5 +-
 src/agg/process_polygon_symbolizer.cpp             |   5 +-
 src/agg/process_raster_symbolizer.cpp              |   4 +-
 src/box2d.cpp                                      |  50 +-
 src/build.py                                       |   7 +
 src/cairo/process_polygon_pattern_symbolizer.cpp   |   3 +-
 src/debug.cpp                                      |  10 +-
 src/feature_kv_iterator.cpp                        |   4 +
 src/font_engine_freetype.cpp                       |  18 +-
 src/fs.cpp                                         |   5 +-
 src/grid/grid_renderer.cpp                         |   8 +-
 src/grid/process_building_symbolizer.cpp           |   4 +-
 src/grid/process_group_symbolizer.cpp              |   4 +-
 src/grid/process_line_pattern_symbolizer.cpp       |   5 +-
 src/grid/process_line_symbolizer.cpp               |   5 +-
 src/grid/process_markers_symbolizer.cpp            |   4 +-
 src/grid/process_point_symbolizer.cpp              |   4 +-
 src/grid/process_polygon_pattern_symbolizer.cpp    |  11 +-
 src/grid/process_polygon_symbolizer.cpp            |   4 +-
 src/grid/process_shield_symbolizer.cpp             |   5 +-
 src/image_compositing.cpp                          |   5 +-
 src/image_scaling.cpp                              |   5 +-
 src/image_util.cpp                                 |   5 +-
 .../json/mapnik_geometry_to_geojson.cpp            |   9 +-
 .../json/mapnik_json_geometry_parser.cpp           |  12 +-
 .../json/mapnik_json_positions_grammar.cpp         |  16 +-
 src/load_map.cpp                                   |   8 +-
 src/map.cpp                                        |   2 +-
 src/marker_cache.cpp                               |   4 +-
 src/marker_helpers.cpp                             | 141 ++++
 src/palette.cpp                                    |  10 +-
 src/plugin.cpp                                     |   2 +
 src/rapidxml_loader.cpp                            |   6 +-
 src/raster_colorizer.cpp                           |   2 +-
 src/renderer_common/render_markers_symbolizer.cpp  | 232 +++---
 src/renderer_common/render_pattern.cpp             |   3 +
 src/svg/svg_parser.cpp                             |   6 +-
 src/svg/svg_path_parser.cpp                        |  43 +-
 src/svg/svg_points_parser.cpp                      |  33 +-
 src/svg/svg_transform_parser.cpp                   |  37 +-
 src/text/face.cpp                                  |   9 +-
 src/text/font_library.cpp                          |   5 +
 src/text/formatting/format.cpp                     |   4 +-
 src/text/formatting/layout.cpp                     |   4 +-
 src/text/formatting/list.cpp                       |   4 +-
 src/text/formatting/text.cpp                       |   4 +-
 src/text/placements/list.cpp                       |   4 +-
 src/text/scrptrun.cpp                              |   3 +
 src/text/text_layout.cpp                           |   5 +-
 src/text/text_properties.cpp                       |   4 +-
 src/twkb.cpp                                       | 387 +++++++++
 src/unicode.cpp                                    |  12 +-
 src/value.cpp                                      | 928 +++++++++++++++++++++
 src/vertex_adapters.cpp                            | 213 +++++
 src/warp.cpp                                       |   4 +-
 src/well_known_srs.cpp                             |   4 +-
 src/wkb.cpp                                        |  22 +-
 test/build.py                                      |   2 +
 test/cleanup.hpp                                   |   5 +
 test/run                                           |  32 +-
 test/unit/color/css_color.cpp                      |   1 +
 test/unit/core/box2d_test.cpp                      |   1 +
 test/unit/core/comparison_test.cpp                 |   1 +
 test/unit/core/conversions_test.cpp                |   1 +
 test/unit/core/exceptions_test.cpp                 |   1 +
 test/unit/core/expressions_test.cpp                |   8 +
 test/unit/core/params_test.cpp                     |   1 +
 test/unit/core/value_test.cpp                      |   1 +
 test/unit/data/well-known-geometries.test          |  13 +
 test/unit/datasource/csv.cpp                       |  37 +-
 test/unit/datasource/ds_test_util.hpp              |  25 +
 test/unit/datasource/geojson.cpp                   |  19 -
 test/unit/datasource/topojson.cpp                  |  75 ++
 test/unit/font/fontset_runtime_test.cpp            |   1 +
 test/unit/geometry/centroid.cpp                    |   1 +
 test/unit/geometry/geometry.cpp                    |   6 +-
 test/unit/geometry/geometry_envelope_test.cpp      |   1 +
 test/unit/geometry/geometry_equal.hpp              |   6 +
 test/unit/geometry/geometry_hit_test.cpp           |   1 +
 test/unit/geometry/geometry_is_simple.cpp          |   1 +
 test/unit/geometry/geometry_is_valid.cpp           |   1 +
 test/unit/geometry/geometry_reprojection.cpp       |   1 +
 test/unit/geometry/geometry_strategy_test.cpp      |   1 +
 test/unit/geometry/has_empty.cpp                   |   1 +
 test/unit/geometry/is_empty.cpp                    |   1 +
 test/unit/geometry/remove_empty.cpp                |   1 +
 test/unit/imaging/image.cpp                        |   1 +
 test/unit/imaging/image_apply_opacity.cpp          |   1 +
 test/unit/imaging/image_filter.cpp                 |   1 +
 test/unit/imaging/image_io_test.cpp                |  33 +-
 test/unit/imaging/image_is_solid.cpp               |   1 +
 test/unit/imaging/image_painted_test.cpp           |   1 +
 test/unit/imaging/image_premultiply.cpp            |   1 +
 test/unit/imaging/image_set_pixel.cpp              |   1 +
 test/unit/imaging/image_view.cpp                   |   1 +
 test/unit/numerics/enumeration.cpp                 |   1 +
 test/unit/numerics/safe_cast.cpp                   |   1 +
 test/unit/pixel/agg_blend_src_over_test.cpp        |   1 +
 test/unit/pixel/palette.cpp                        |   1 +
 test/unit/projection/proj_transform.cpp            |   1 +
 .../unit/serialization/parse_hex.hpp               |  26 +-
 test/unit/serialization/wkb_formats_test.cpp       |   5 -
 test/unit/serialization/wkb_test.cpp               | 113 +++
 test/unit/serialization/xml_parser_trim.cpp        |   1 +
 test/unit/svg/svg_parser_test.cpp                  |   4 +-
 test/unit/svg/svg_path_parser_test.cpp             |   2 +-
 test/unit/svg/util.hpp                             |   2 +-
 test/unit/symbolizer/symbolizer_test.cpp           |   1 +
 test/unit/text/shaping.cpp                         |   1 +
 test/unit/vertex_adapter/clipping_test.cpp         |   1 +
 test/unit/vertex_adapter/line_offset_test.cpp      |   1 +
 test/unit/vertex_adapter/offset_converter.cpp      |   1 +
 .../vertex_adapter/simplify_converters_test.cpp    |   1 +
 test/unit/vertex_adapter/vertex_adapter.cpp        |   1 +
 utils/mapnik-config/build.py                       |   5 -
 utils/mapnik-index/build.py                        |   5 +-
 utils/mapnik-index/mapnik-index.cpp                |  10 +-
 utils/mapnik-index/process_csv_file.cpp            | 191 +----
 utils/mapnik-index/process_csv_file.hpp            |   2 +-
 utils/mapnik-index/process_geojson_file.cpp        |  36 +-
 utils/mapnik-index/process_geojson_file.hpp        |   2 +-
 utils/pgsql2sqlite/main.cpp                        |   7 +-
 utils/pgsql2sqlite/sqlite.hpp                      |   5 +-
 utils/shapeindex/build.py                          |   4 +-
 utils/shapeindex/shapeindex.cpp                    |  15 +-
 utils/svg2png/svg2png.cpp                          |   4 +
 307 files changed, 5830 insertions(+), 4788 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index bce7b05..13cf1f2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,23 +1,20 @@
 language: c
 
-sudo: false
-
 git:
   depth: 10
   submodules: false
 
 env:
   global:
+   - CCACHE_TEMPDIR=/tmp/.ccache-temp
+   - CCACHE_COMPRESS=1
+   - HEAVY_JOBS="2"
+   - PREFIX=/tmp/mapnik
    - secure: "N3a5nzzsgpuu45k8qWdYsHNxrSnqeAGLTOYpfYoAH7B94vuf7pa7XV1tQjXbxrnx2D6ryTdtUtyRKwy7zXbwXxGt4DpczWEo8f6DUd6+obAp3kdnXABg2Sj4oA7KMs0F0CmoADy0jdUZD5YyOJHu64LCIIgzEQ9q49PFMNbU3IE="
    - secure: "iQYPNpMtejcgYeUkWZGIWz1msIco5qydJrhZTSCQOYahAQerdT7q5WZEpEo3G6IWOGgO1eo7GFuY8DvqQjw1+jC9b9mhkRNdo3LhGTKS9Gsbl5Q27k0rjlaFZmmQHrfPlQJwhfAIp+KLugHtQw5bCoLh+95E3j0F0DayF1tuJ3s="
+   - secure: "F6ivqDNMBQQnrDGA9+7IX+GDswuIqQQd7YPJdQqa2Ked9jddAQDeJClb05ig3JlwfOlYLGZOd43ZX0pKuMtI2Gbkwz211agGP9S3YunwlRg8iWtJlO5kYFUdKCmJNhjg4icfkGELCgwXn+zuEWFSLpkPcjqAFKFlQrIJeAJJgKM="
 addons:
   postgresql: "9.4"
-  apt:
-    sources:
-     - ubuntu-toolchain-r-test
-     - llvm-toolchain-precise-3.5
-    packages:
-     - clang-3.5
 
 cache:
   directories:
@@ -26,35 +23,31 @@ cache:
 matrix:
   include:
     - os: linux
-      compiler: clang
-      env: JOBS=8 CXX="ccache clang++-3.5 -Qunused-arguments" CC="clang-3.5" MASON_PUBLISH=true BENCH=True
+      sudo: false
+      compiler: ": clang"
+      env: JOBS=8 MASON_PUBLISH=true CXX="ccache clang++-3.5 -Qunused-arguments" CC="clang-3.5" TRIGGER=true
       addons:
         apt:
           sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.5' ]
           packages: [ 'clang-3.5' ]
-    # OOM killer knocking out build on render_markers_symbolizer.cpp
-    #
-    #- os: linux
-    #  compiler: gcc
-    #  env: JOBS=6 CXX="ccache g++-4.9" CC="gcc-4.9"
-    #  addons:
-    #    apt:
-    #      sources: [ 'ubuntu-toolchain-r-test' ]
-    #      packages: [ 'gcc-4.9', 'g++-4.9', 'libstdc++-4.9-dev', 'libstdc++6' ]
+    - os: linux
+      sudo: false
+      compiler: ": clang-coverage"
+      env: JOBS=8 COVERAGE=true LLVM_VERSION="3.5" CXX="ccache clang++-3.5 -Qunused-arguments" CC="clang-3.5"
+      addons:
+        apt:
+          sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.5' ]
+          packages: [ 'clang-3.5', 'llvm-3.5-dev' ]
     - os: osx
       compiler: clang
       # https://docs.travis-ci.com/user/languages/objective-c/#Supported-OS-X-iOS-SDK-versions
-      osx_image: xcode7.2 # upgrades clang from 6 -> 7
-      env: JOBS=8 MASON_PUBLISH=true HEAVY_JOBS=3
-    - os: osx
-      compiler: clang
-      osx_image: xcode7.2 # upgrades clang from 6 -> 7
-      env: JOBS=8 COVERAGE=true HEAVY_JOBS=3
+      osx_image: xcode7.3 # upgrades clang from 6 -> 7
+      env: JOBS=4 MASON_PUBLISH=true
 
 before_install:
  - source scripts/travis-common.sh
  - export PYTHONUSERBASE=$(pwd)/mason_packages/.link
- - export PATH=${PYTHONUSERBASE}/bin:${PATH}
+ - export PATH=${PREFIX}/bin:$(pwd)/mason_packages/.link/bin:${PYTHONUSERBASE}/bin:${PATH}
  - export COVERAGE=${COVERAGE:-false}
  - export MASON_PUBLISH=${MASON_PUBLISH:-false}
  - export BENCH=${BENCH:-false}
@@ -63,11 +56,14 @@ before_install:
  - git_submodule_update --init --depth=10
 
 install:
+ - if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then export CCACHE_READONLY=1; fi
  - on 'linux' export PYTHONPATH=${PYTHONUSERBASE}/lib/python2.7/site-packages
  - on 'osx' export PYTHONPATH=${PYTHONUSERBASE}/lib/python/site-packages
- - on 'osx' brew rm postgis --force
- - on 'osx' brew install postgis --force
- - on 'osx' pg_ctl -w start -l postgres.log --pgdata /usr/local/var/postgres
+ - on 'osx' export DATA_PATH=$(brew --prefix)/var/postgres
+ - on 'osx' rm -rf ${DATA_PATH}
+ - on 'osx' initdb ${DATA_PATH} -E utf8
+ - on 'osx' pg_ctl -w start -l postgres.log --pgdata ${DATA_PATH};
+ - on 'osx' cat postgres.log;
  - on 'osx' createuser -s postgres
  - psql -c 'create database template_postgis;' -U postgres
  - psql -c 'create extension postgis;' -d template_postgis -U postgres
@@ -75,6 +71,9 @@ install:
 
 before_script:
  - source bootstrap.sh
+ - ccache --version
+ - ccache -p || true
+ - ccache --show-stats || true
  - commit_message_parse
 
 script:
@@ -86,8 +85,9 @@ script:
  - enabled ${BENCH} make bench
 
 after_success:
+ - enabled ${TRIGGER} trigger_downstream
  - if enabled ${MASON_PUBLISH}; then
+     source ./.mason/mason.sh &&
      ./mason_latest.sh build &&
-     ./mason_latest.sh link &&
      ./mason_latest.sh publish;
    fi
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f7c6078..762cee9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,17 @@ Developers: Please commit along with changes.
 
 For a complete change history, see the git log.
 
+## 3.0.11
+
+Released:
+
+(Packaged from 8d9dc27)
+
+#### Summary
+
+ - Raster scaling: fixed crash and clipping negative pixel values of floating point rasters (https://github.com/mapnik/mapnik/pull/3349)
+ - Restored support for unquoted strings in expressions (https://github.com/mapnik/mapnik/pull/3390)
+ 
 ## 3.0.10
 
 Released: February 25, 2016
diff --git a/Makefile b/Makefile
index 777303d..fd3a2ad 100755
--- a/Makefile
+++ b/Makefile
@@ -24,7 +24,8 @@ release:
 	git clone --depth 1 --branch v$${MAPNIK_VERSION} git at github.com:mapnik/mapnik.git $${TARBALL_NAME} && \
 	cd $${TARBALL_NAME} && \
 	git checkout "tags/v$${MAPNIK_VERSION}" && \
-	git submodule update --depth 1 --init && \
+	git submodule update --depth 100 --init && \
+	rm -rf deps/mapbox/variant/.git && \
 	rm -rf test/data/.git && \
 	rm -rf test/data/.gitignore && \
 	rm -rf test/data-visual/.git && \
@@ -53,6 +54,16 @@ src/json/libmapnik-json.a:
 		src/expression_grammar.os \
 		src/transform_expression_grammar.os \
 		src/image_filter_grammar.os \
+		src/marker_helpers.os \
+		src/svg/svg_transform_parser.os \
+		src/agg/process_line_symbolizer.os \
+		plugins/input/geojson/geojson_datasource.os \
+		utils/mapnik-index/process_geojson_file.o \
+		src/svg/svg_path_parser.os \
+		src/svg/svg_parser.os \
+		src/svg/svg_points_parser.os \
+		src/svg/svg_transform_parser.os \
+
 
 mapnik: src/json/libmapnik-json.a
 	# then install the rest with -j$(JOBS)
@@ -70,6 +81,8 @@ clean:
 	@find ./src/ -name "*.so" -exec rm {} \;
 	@find ./ -name "*.o" -exec rm {} \;
 	@find ./src/ -name "*.a" -exec rm {} \;
+	@find ./ -name "*.gcda" -exec rm {} \;
+	@find ./ -name "*.gcno" -exec rm {} \;
 
 distclean:
 	if test -e "config.py"; then mv "config.py" "config.py.backup"; fi
diff --git a/SConstruct b/SConstruct
index 2b851e4..dacc950 100644
--- a/SConstruct
+++ b/SConstruct
@@ -293,6 +293,7 @@ opts.AddVariables(
     EnumVariable('OPTIMIZATION','Set compiler optimization level','3', ['0','1','2','3','4','s']),
     # Note: setting DEBUG=True will override any custom OPTIMIZATION level
     BoolVariable('DEBUG', 'Compile a debug version of Mapnik', 'False'),
+    BoolVariable('COVERAGE', 'Compile a libmapnik and plugins with --coverage', 'False'),
     BoolVariable('DEBUG_UNDEFINED', 'Compile a version of Mapnik using clang/llvm undefined behavior asserts', 'False'),
     BoolVariable('DEBUG_SANITIZE', 'Compile a version of Mapnik using clang/llvm address sanitation', 'False'),
     ListVariable('INPUT_PLUGINS','Input drivers to include',DEFAULT_PLUGINS,PLUGINS.keys()),
@@ -303,6 +304,7 @@ opts.AddVariables(
     ('CONFIG', "The path to the python file in which to save user configuration options. Currently : '%s'" % SCONS_LOCAL_CONFIG,SCONS_LOCAL_CONFIG),
     BoolVariable('USE_CONFIG', "Use SCons user '%s' file (will also write variables after successful configuration)", 'True'),
     BoolVariable('NO_ATEXIT', 'Will prevent Singletons from being deleted atexit of main thread', 'False'),
+    BoolVariable('NO_DLCLOSE', 'Will prevent plugins from being unloaded', 'False'),
     # http://www.scons.org/wiki/GoFastButton
     # http://stackoverflow.com/questions/1318863/how-to-optimize-an-scons-script
     BoolVariable('FAST', "Make SCons faster at the cost of less precise dependency tracking", 'False'),
@@ -317,7 +319,6 @@ opts.AddVariables(
     ('PATH_REMOVE', 'A path prefix to exclude from all known command and compile paths (create multiple excludes separated by :)', ''),
     ('PATH_REPLACE', 'Two path prefixes (divided with a :) to search/replace from all known command and compile paths', ''),
     ('MAPNIK_NAME', 'Name of library', 'mapnik'),
-    BoolVariable('MAPNIK_BUNDLED_SHARE_DIRECTORY', 'For portable packaging: instruct mapnik-config to report relative paths to bundled GDAL_DATA, PROJ_LIB, and ICU_DATA','False'),
 
     # Boost variables
     # default is '/usr/include', see FindBoost method below
@@ -1139,6 +1140,9 @@ if not preconfigured:
     else:
         mode = 'release mode'
 
+    if env['COVERAGE']:
+        mode += ' (with coverage)'
+
     env['PLATFORM'] = platform.uname()[0]
     color_print(4,"Configuring on %s in *%s*..." % (env['PLATFORM'],mode))
 
@@ -1727,6 +1731,9 @@ if not preconfigured:
         if env['NO_ATEXIT']:
             env.Append(CPPDEFINES = '-DMAPNIK_NO_ATEXIT')
 
+        if env['NO_DLCLOSE'] or env['COVERAGE']:
+            env.Append(CPPDEFINES = '-DMAPNIK_NO_DLCLOSE')
+
         # Mac OSX (Darwin) special settings
         if env['PLATFORM'] == 'Darwin':
             pthread = ''
@@ -1786,10 +1793,11 @@ if not preconfigured:
 
         # Common flags for g++/clang++ CXX compiler.
         # TODO: clean up code more to make -Wextra -Wsign-compare -Wsign-conversion -Wconversion viable
+        # -Wfloat-equal -Wold-style-cast -Wexit-time-destructors -Wglobal-constructors -Wreserved-id-macro -Wheader-hygiene -Wmissing-noreturn
         common_cxx_flags = '-fvisibility=hidden -fvisibility-inlines-hidden -Wall %s %s -ftemplate-depth-300 -Wsign-compare -Wshadow ' % (env['WARNING_CXXFLAGS'], pthread)
 
         if 'clang++' in env['CXX']:
-            common_cxx_flags += ' -Wno-unsequenced '
+            common_cxx_flags += ' -Wno-unsequenced -Wtautological-compare -Wheader-hygiene '
 
         if env['DEBUG']:
             env.Append(CXXFLAGS = common_cxx_flags + '-O0')
@@ -1891,6 +1899,10 @@ if not HELP_REQUESTED:
 
     plugin_base = env.Clone()
 
+    if env['COVERAGE']:
+        plugin_base.Append(LINKFLAGS='--coverage')
+        plugin_base.Append(CXXFLAGS='--coverage')
+
     Export('plugin_base')
 
     if env['FAST']:
diff --git a/appveyor.yml b/appveyor.yml
index ea7af41..f236021 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -12,9 +12,20 @@ os: Visual Studio 2015
 # limit clone to latest 5 commits
 clone_depth: 5
 
+services:
+  - postgresql94 #if changing this, also change PATH below
+
 install:
+  - SET PGUSER=postgres
+  - SET PGPASSWORD=Password12!
+  - SET PATH=C:\Program Files\PostgreSQL\9.4\bin\;%PATH%
+
+build_script:
   - scripts\build-appveyor.bat
 
+after_build:
+  - 7z a mapnik-visual-images.zip C:\tmp\mapnik-visual-images
+
 artifacts:
   - path: mapnik-gyp\msbuild-summary.txt
     name: msbuild-summary.txt
@@ -22,7 +33,8 @@ artifacts:
     name: msbuild-errors.txt
   - path: mapnik-gyp\msbuild-warnings.txt
     name: msbuild-warnings.txt
+  - path: mapnik-visual-images.zip
+    name: mapnik-visual-images.zip
 
-build: off
 test: off
 deploy: off
diff --git a/benchmark/bench_framework.hpp b/benchmark/bench_framework.hpp
index 34c63a8..a3de4fd 100644
--- a/benchmark/bench_framework.hpp
+++ b/benchmark/bench_framework.hpp
@@ -1,5 +1,5 @@
-#ifndef __MAPNIK_BENCH_FRAMEWORK_HPP__
-#define __MAPNIK_BENCH_FRAMEWORK_HPP__
+#ifndef MAPNIK_BENCH_FRAMEWORK_HPP
+#define MAPNIK_BENCH_FRAMEWORK_HPP
 
 // mapnik
 #include <mapnik/debug.hpp>
@@ -10,6 +10,7 @@
 
 // stl
 #include <chrono>
+#include <cmath> // log10, round
 #include <cstdio> // snprintf
 #include <iostream>
 #include <set>
@@ -19,6 +20,12 @@
 
 namespace benchmark {
 
+template <typename T>
+using milliseconds = std::chrono::duration<T, std::milli>;
+
+template <typename T>
+using seconds = std::chrono::duration<T>;
+
 class test_case
 {
 protected:
@@ -45,7 +52,6 @@ public:
     }
     virtual bool validate() const = 0;
     virtual bool operator()() const = 0;
-    virtual ~test_case() {}
 };
 
 // gathers --long-option values in 'params';
@@ -92,7 +98,7 @@ inline int parse_args(int argc, char** argv, mapnik::parameters & params)
 
 inline void handle_common_args(mapnik::parameters const& params)
 {
-    if (auto severity = params.get<std::string>("log-severity")) {
+    if (auto severity = params.get<std::string>("log")) {
         if (*severity == "debug")
             mapnik::logger::set_severity(mapnik::logger::debug);
         else if (*severity == "warn")
@@ -102,7 +108,7 @@ inline void handle_common_args(mapnik::parameters const& params)
         else if (*severity == "none")
             mapnik::logger::set_severity(mapnik::logger::none);
         else
-            std::clog << "ignoring option --log-severity='" << *severity
+            std::clog << "ignoring option --log='" << *severity
                       << "' (allowed values are: debug, warn, error, none)\n";
     }
 }
@@ -134,6 +140,29 @@ inline int handle_args(int argc, char** argv, mapnik::parameters & params)
         }                                               \
     }                                                   \
 
+struct big_number_fmt
+{
+    int w;
+    double v;
+    const char* u;
+
+    big_number_fmt(int width, double value, int base = 1000)
+        : w(width), v(value), u("")
+    {
+        static const char* suffixes = "\0\0k\0M\0G\0T\0P\0E\0Z\0Y\0\0";
+        u = suffixes;
+
+        while (v > 1 && std::log10(std::round(v)) >= width && u[2])
+        {
+            v /= base;
+            u += 2;
+        }
+
+        // adjust width for proper alignment without suffix
+        w += (u == suffixes);
+    }
+};
+
 template <typename T>
 int run(T const& test_runner, std::string const& name)
 {
@@ -156,21 +185,43 @@ int run(T const& test_runner, std::string const& name)
         auto opt_min_duration = test_runner.params().template get<double>("min-duration", 0.0);
         std::chrono::duration<double> min_seconds(*opt_min_duration);
         auto min_duration = std::chrono::duration_cast<decltype(elapsed)>(min_seconds);
-        std::size_t loops = 0;
+        auto num_iters = test_runner.iterations();
+        auto num_threads = test_runner.threads();
+        auto total_iters = 0;
 
-        if (test_runner.threads() > 0)
+        if (num_threads > 0)
         {
-            using thread_group = std::vector<std::unique_ptr<std::thread> >;
-            using value_type = thread_group::value_type;
-            thread_group tg;
-            for (std::size_t i=0;i<test_runner.threads();++i)
+            std::mutex mtx_ready;
+            std::unique_lock<std::mutex> lock_ready(mtx_ready);
+
+            auto stub = [&](T const& test_copy)
             {
-                tg.emplace_back(new std::thread(test_runner));
+                // workers will wait on this mutex until the main thread
+                // constructs all of them and starts measuring time
+                std::unique_lock<std::mutex> my_lock(mtx_ready);
+                my_lock.unlock();
+                test_copy();
+            };
+
+            std::vector<std::thread> tg;
+            tg.reserve(num_threads);
+            for (auto i = num_threads; i-- > 0; )
+            {
+                tg.emplace_back(stub, test_runner);
             }
             start = std::chrono::high_resolution_clock::now();
-            std::for_each(tg.begin(), tg.end(), [](value_type & t) {if (t->joinable()) t->join();});
+            lock_ready.unlock();
+            // wait for all workers to finish
+            for (auto & t : tg)
+            {
+                if (t.joinable())
+                    t.join();
+            }
             elapsed = std::chrono::high_resolution_clock::now() - start;
-            loops = 1;
+            // this is actually per-thread count, not total, but I think
+            // reporting average 'iters/thread/second' is more useful
+            // than 'iters/second' multiplied by the number of threads
+            total_iters += num_iters;
         }
         else
         {
@@ -178,39 +229,25 @@ int run(T const& test_runner, std::string const& name)
             do {
                 test_runner();
                 elapsed = std::chrono::high_resolution_clock::now() - start;
-                ++loops;
+                total_iters += num_iters;
             } while (elapsed < min_duration);
         }
 
-        double iters = loops * test_runner.iterations();
-        double dur_total = std::chrono::duration<double, std::milli>(elapsed).count();
-        double dur_avg = dur_total / iters;
-        char iters_unit = ' ';
         char msg[200];
-
-        if (iters >= 1e7) iters *= 1e-6, iters_unit = 'M';
-        else if (iters >= 1e4) iters *= 1e-3, iters_unit = 'k';
+        double dur_total = milliseconds<double>(elapsed).count();
+        auto elapsed_nonzero = std::max(elapsed, decltype(elapsed){1});
+        big_number_fmt itersf(4, total_iters);
+        big_number_fmt ips(5, total_iters / seconds<double>(elapsed_nonzero).count());
 
         std::snprintf(msg, sizeof(msg),
-                "%-43s %3zu threads %4.0f%c iters %6.0f milliseconds",
+                "%-43s %3zu threads %*.0f%s iters %6.0f milliseconds %*.0f%s i/s\n",
                 name.c_str(),
-                test_runner.threads(),
-                iters, iters_unit,
-                dur_total);
+                num_threads,
+                itersf.w, itersf.v, itersf.u,
+                dur_total,
+                ips.w, ips.v, ips.u
+                );
         std::clog << msg;
-
-        // log average time per iteration, currently only for non-threaded runs
-        if (test_runner.threads() == 0)
-        {
-            char unit = 'm';
-            if (dur_avg < 1e-5) dur_avg *= 1e+9, unit = 'p';
-            else if (dur_avg < 1e-2) dur_avg *= 1e+6, unit = 'n';
-            else if (dur_avg < 1e+1) dur_avg *= 1e+3, unit = 'u';
-            std::snprintf(msg, sizeof(msg), " %4.0f%cs/iter", dur_avg, unit);
-            std::clog << msg;
-        }
-
-        std::clog << "\n";
         return 0;
     }
     catch (std::exception const& ex)
@@ -250,4 +287,4 @@ protected:
 
 }
 
-#endif // __MAPNIK_BENCH_FRAMEWORK_HPP__
+#endif // MAPNIK_BENCH_FRAMEWORK_HPP
diff --git a/benchmark/compare_images.hpp b/benchmark/compare_images.hpp
index fb0e4ac..ff90e01 100644
--- a/benchmark/compare_images.hpp
+++ b/benchmark/compare_images.hpp
@@ -1,11 +1,10 @@
-#ifndef __MAPNIK_COMPARE_IMAGES_HPP__
-#define __MAPNIK_COMPARE_IMAGES_HPP__
+#ifndef MAPNIK_COMPARE_IMAGES_HPP
+#define MAPNIK_COMPARE_IMAGES_HPP
 
 #include <mapnik/image.hpp>
 #include <mapnik/image_util.hpp>
 #include <mapnik/image_reader.hpp>
 
-using namespace mapnik;
 
 namespace benchmark {
 
@@ -23,15 +22,15 @@ namespace benchmark {
             throw mapnik::image_reader_exception("Failed to load: " + src_fn);
         }
 
-        const image_any desc_any = reader1->read(0,0,reader1->width(), reader1->height());
-        const image_any src_any = reader2->read(0,0,reader2->width(), reader2->height());
+        const mapnik::image_any desc_any = reader1->read(0,0,reader1->width(), reader1->height());
+        const mapnik::image_any src_any = reader2->read(0,0,reader2->width(), reader2->height());
 
-        image_rgba8 const& dest = util::get<image_rgba8>(desc_any);
-        image_rgba8 const& src = util::get<image_rgba8>(src_any);
+        mapnik::image_rgba8 const& dest = mapnik::util::get<mapnik::image_rgba8>(desc_any);
+        mapnik::image_rgba8 const& src = mapnik::util::get<mapnik::image_rgba8>(src_any);
 
         return compare(dest, src, 0, true) == 0;
     }
 
 }
 
-#endif // __MAPNIK_COMPARE_IMAGES_HPP__
+#endif // MAPNIK_COMPARE_IMAGES_HPP
diff --git a/benchmark/run b/benchmark/run
index 00285b2..6a8fdd9 100755
--- a/benchmark/run
+++ b/benchmark/run
@@ -6,8 +6,14 @@ source ./localize.sh
 
 BASE=./benchmark/out
 function run {
-    ${BASE}/$1 --threads 0 --iterations $3;
-    ${BASE}/$1 --threads $2 --iterations $(expr $3 / $2);
+    local runner="$BASE/$1 --log=none"
+    local threads="$2"
+    local iters="$3"
+    shift 3
+    $runner --threads 0 --iterations $iters "$@"
+    if test $threads -gt 0; then
+        $runner --threads $threads --iterations $((iters/threads)) "$@"
+    fi
 }
 run test_getline 30 10000000
 #run test_array_allocation 20 100000
@@ -23,6 +29,8 @@ run test_face_ptr_creation 10 1000
 run test_font_registration 10 100
 run test_offset_converter 10 1000
 
+# commented since this is really slow on travis
+: '
 ./benchmark/out/test_rendering \
   --name "text rendering" \
   --map benchmark/data/roads.xml \
@@ -31,6 +39,7 @@ run test_offset_converter 10 1000
   --height 600 \
   --iterations 20 \
   --threads 10
+'
 
 ./benchmark/out/test_rendering \
   --name "gdal tiff rendering" \
diff --git a/benchmark/test_getline.cpp b/benchmark/test_getline.cpp
index 1791b06..ed21c04 100644
--- a/benchmark/test_getline.cpp
+++ b/benchmark/test_getline.cpp
@@ -1,7 +1,7 @@
 #include "bench_framework.hpp"
-#include <cstring>
-#include <cstdlib>
-#include "../plugins/input/csv/csv_utils.hpp"
+#include "../plugins/input/csv/csv_getline.hpp"
+
+
 
 class test : public benchmark::test_case
 {
diff --git a/bootstrap.sh b/bootstrap.sh
old mode 100644
new mode 100755
index f565d01..3a64709
--- a/bootstrap.sh
+++ b/bootstrap.sh
@@ -10,12 +10,15 @@ todo
 - shrink icu data
 '
 
+MASON_VERSION="694d08c"
+
 function setup_mason() {
     if [[ ! -d ./.mason ]]; then
-        git clone --depth 1 https://github.com/mapbox/mason.git ./.mason
+        git clone https://github.com/mapbox/mason.git ./.mason
+        (cd ./.mason && git checkout ${MASON_VERSION})
     else
         echo "Updating to latest mason"
-        (cd ./.mason && git pull)
+        (cd ./.mason && git fetch && git checkout ${MASON_VERSION})
     fi
     export MASON_DIR=$(pwd)/.mason
     export PATH=$(pwd)/.mason:$PATH
@@ -28,7 +31,7 @@ function install() {
     if [[ ! -d ./mason_packages/${MASON_PLATFORM_ID}/${1}/${2} ]]; then
         mason install $1 $2
         mason link $1 $2
-        if [[ $3 ]]; then
+        if [[ ${3:-false} != false ]]; then
             LA_FILE=$(${MASON_DIR:-~/.mason}/mason prefix $1 $2)/lib/$3.la
             if [[ -f ${LA_FILE} ]]; then
                perl -i -p -e 's:\Q$ENV{HOME}/build/mapbox/mason\E:$ENV{PWD}:g' ${LA_FILE}
@@ -42,6 +45,7 @@ function install() {
 ICU_VERSION="55.1"
 
 function install_mason_deps() {
+    install ccache 3.2.4 &
     install jpeg_turbo 1.4.0 libjpeg &
     install libpng 1.6.20 libpng &
     install libtiff 4.0.4beta libtiff &
diff --git a/circle.yml b/circle.yml
new file mode 100644
index 0000000..e7c12d7
--- /dev/null
+++ b/circle.yml
@@ -0,0 +1,49 @@
+machine:
+  xcode:
+    version: 7.3
+  environment:
+    XCODE_SCHEME: "no"
+    XCODE_WORKSPACE: "no"
+    JOBS: 8
+    CCACHE_TEMPDIR: /tmp/.ccache-temp
+    CCACHE_COMPRESS: 1
+    LLVM_VERSION: 3.7
+  pre:
+    - echo "here"
+  post:
+    - echo "there"
+
+checkout:
+  post:
+    - git submodule update --init
+
+dependencies:
+  cache_directories:
+    - "~/.ccache"
+    - "~/.apt-cache"
+    - "mason_packages"
+  pre:
+    # https://discuss.circleci.com/t/add-ability-to-cache-apt-get-programs/598/3
+    - sudo rm -rf /var/cache/apt/archives && sudo ln -s ~/.apt-cache /var/cache/apt/archives && mkdir -p ~/.apt-cache/partial
+    - sudo wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key | sudo apt-key add -
+    - sudo add-apt-repository -y "deb http://llvm.org/apt/precise/ llvm-toolchain-precise-${LLVM_VERSION} main"
+    - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
+    - sudo apt-get update -y
+  override:
+    - sudo apt-get install clang-${LLVM_VERSION} -y
+  post:
+    - which clang-${LLVM_VERSION}
+    - which clang++-${LLVM_VERSION}
+
+database:
+  pre:
+    - ./bootstrap.sh
+    - ./configure CC="clang-${LLVM_VERSION}" CXX="$(pwd)/mason_packages/.link/bin/ccache clang++-${LLVM_VERSION} -Qunused-arguments"
+    - make
+  override:
+    - psql -c 'create database template_postgis;'
+    - psql -c 'create extension postgis;' -d template_postgis
+
+test:
+  override:
+    - make test
diff --git a/include/mapnik/agg_helpers.hpp b/include/mapnik/agg_helpers.hpp
index 139405c..ff87ce0 100644
--- a/include/mapnik/agg_helpers.hpp
+++ b/include/mapnik/agg_helpers.hpp
@@ -26,8 +26,10 @@
 // mapnik
 #include <mapnik/symbolizer_enumerations.hpp>
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_gamma_functions.h"
+#pragma GCC diagnostic pop
 
 namespace mapnik {
 
diff --git a/include/mapnik/agg_pattern_source.hpp b/include/mapnik/agg_pattern_source.hpp
index a000020..42dd7f3 100644
--- a/include/mapnik/agg_pattern_source.hpp
+++ b/include/mapnik/agg_pattern_source.hpp
@@ -27,8 +27,10 @@
 #include <mapnik/image.hpp>
 #include <mapnik/util/noncopyable.hpp>
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_color_rgba.h"
+#pragma GCC diagnostic pop
 
 namespace mapnik
 {
diff --git a/include/mapnik/agg_rasterizer.hpp b/include/mapnik/agg_rasterizer.hpp
index 51cf4cd..66da59f 100644
--- a/include/mapnik/agg_rasterizer.hpp
+++ b/include/mapnik/agg_rasterizer.hpp
@@ -26,8 +26,11 @@
 // mapnik
 #include <mapnik/util/noncopyable.hpp>
 
-// agg
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_rasterizer_scanline_aa.h"
+#pragma GCC diagnostic pop
 
 namespace mapnik {
 
diff --git a/include/mapnik/agg_render_marker.hpp b/include/mapnik/agg_render_marker.hpp
index 65e531c..283807a 100644
--- a/include/mapnik/agg_render_marker.hpp
+++ b/include/mapnik/agg_render_marker.hpp
@@ -30,7 +30,8 @@
 #include <mapnik/safe_cast.hpp>
 #include <mapnik/util/const_rendering_buffer.hpp>
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_color_rgba.h"
 #include "agg_renderer_base.h"
 #include "agg_renderer_scanline.h"
@@ -43,6 +44,7 @@
 #include "agg_pixfmt_rgba.h"
 #include "agg_span_image_filter_rgba.h"
 #include "agg_span_interpolator_linear.h"
+#pragma GCC diagnostic pop
 
 namespace mapnik {
 
diff --git a/include/mapnik/box2d.hpp b/include/mapnik/box2d.hpp
index 4471c28..a790c1d 100644
--- a/include/mapnik/box2d.hpp
+++ b/include/mapnik/box2d.hpp
@@ -27,8 +27,10 @@
 #include <mapnik/config.hpp>
 #include <mapnik/coord.hpp>
 
-// boost
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/operators.hpp>
+#pragma GCC diagnostic pop
 
 // agg
 // forward declare so that apps using mapnik do not need agg headers
@@ -48,7 +50,8 @@ template <typename T> class MAPNIK_DECL box2d
                                                               boost::multipliable2<box2d<T>, T > > > >
 {
 public:
-    using box2d_type = box2d<T>;
+    using value_type = T;
+    using box2d_type = box2d<value_type>;
 private:
     T minx_;
     T miny_;
@@ -63,12 +66,22 @@ private:
         swap(lhs.maxy_, rhs.maxy_);
     }
 public:
+
     box2d();
     box2d(T minx,T miny,T maxx,T maxy);
     box2d(coord<T,2> const& c0, coord<T,2> const& c1);
     box2d(box2d_type const& rhs);
     box2d(box2d_type const& rhs, agg::trans_affine const& tr);
+    // move
     box2d(box2d_type&& rhs);
+    // converting ctor
+    template <typename T1>
+    explicit box2d(box2d<T1> other)
+        : minx_(static_cast<value_type>(other.minx())),
+        miny_(static_cast<value_type>(other.miny())),
+        maxx_(static_cast<value_type>(other.maxx())),
+        maxy_(static_cast<value_type>(other.maxy()))
+        {}
     box2d_type& operator=(box2d_type other);
     T minx() const;
     T miny() const;
@@ -97,6 +110,7 @@ public:
     void re_center(T cx,T cy);
     void re_center(coord<T,2> const& c);
     void init(T x0,T y0,T x1,T y1);
+    void init(T x, T y);
     void clip(box2d_type const& other);
     void pad(T padding);
     bool from_string(std::string const& str);
diff --git a/include/mapnik/cairo/cairo_context.hpp b/include/mapnik/cairo/cairo_context.hpp
index 3f065db..9733efb 100644
--- a/include/mapnik/cairo/cairo_context.hpp
+++ b/include/mapnik/cairo/cairo_context.hpp
@@ -38,18 +38,20 @@
 #include <mapnik/symbolizer_base.hpp>
 #include <mapnik/symbolizer_enumerations.hpp>
 
-// stl
-#include <memory>
-
-// cairo
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <cairo.h>
+#pragma GCC diagnostic pop
 
 // stl
+#include <memory>
 #include <map>
 #include <stdexcept>
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_basics.h"
+#pragma GCC diagnostic pop
 
 namespace mapnik {
 
diff --git a/include/mapnik/color.hpp b/include/mapnik/color.hpp
index 690803a..434a9cf 100644
--- a/include/mapnik/color.hpp
+++ b/include/mapnik/color.hpp
@@ -27,8 +27,10 @@
 #include <mapnik/config.hpp>
 #include <mapnik/global.hpp>
 
-//boost
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/operators.hpp>
+#pragma GCC diagnostic pop
 
 // stl
 #include <sstream>
diff --git a/include/mapnik/coord.hpp b/include/mapnik/coord.hpp
index fcdfa90..f8ea3f1 100644
--- a/include/mapnik/coord.hpp
+++ b/include/mapnik/coord.hpp
@@ -23,8 +23,10 @@
 #ifndef MAPNIK_COORD_HPP
 #define MAPNIK_COORD_HPP
 
-// boost
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/operators.hpp>
+#pragma GCC diagnostic pop
 
 namespace mapnik {
 template <typename T,int dim>
diff --git a/include/mapnik/css_color_grammar.hpp b/include/mapnik/css_color_grammar.hpp
index 21e6391..8fbdeaa 100644
--- a/include/mapnik/css_color_grammar.hpp
+++ b/include/mapnik/css_color_grammar.hpp
@@ -32,261 +32,25 @@
 #pragma GCC diagnostic push
 #include <mapnik/warning_ignore.hpp>
 #include <boost/spirit/include/qi.hpp>
-#include <boost/spirit/include/qi_action.hpp>
-#include <boost/spirit/include/qi_lexeme.hpp>
-#include <boost/spirit/include/phoenix_core.hpp>
-#include <boost/spirit/include/phoenix_operator.hpp>
-#include <boost/spirit/include/phoenix_fusion.hpp>
-#include <boost/spirit/include/phoenix_function.hpp>
-#include <boost/fusion/include/adapt_adt.hpp>
 #pragma GCC diagnostic pop
 
 // stl
 #include <string>
 
-BOOST_FUSION_ADAPT_ADT(
-    mapnik::color,
-    (unsigned, unsigned, obj.red(), obj.set_red(mapnik::safe_cast<uint8_t>(val)))
-    (unsigned, unsigned, obj.green(), obj.set_green(mapnik::safe_cast<uint8_t>(val)))
-    (unsigned, unsigned, obj.blue(), obj.set_blue(mapnik::safe_cast<uint8_t>(val)))
-    (unsigned, unsigned, obj.alpha(), obj.set_alpha(mapnik::safe_cast<uint8_t>(val)))
-    )
-
 namespace mapnik
 {
 
 namespace qi = boost::spirit::qi;
 namespace ascii = boost::spirit::ascii;
-namespace phoenix = boost::phoenix;
 
 using ascii_space_type = boost::spirit::ascii::space_type;
 
-struct named_colors_ : qi::symbols<char,color>
-{
-    named_colors_()
-    {
-        add
-            ("aliceblue", color(240, 248, 255))
-            ("antiquewhite", color(250, 235, 215))
-            ("aqua", color(0, 255, 255))
-            ("aquamarine", color(127, 255, 212))
-            ("azure", color(240, 255, 255))
-            ("beige", color(245, 245, 220))
-            ("bisque", color(255, 228, 196))
-            ("black", color(0, 0, 0))
-            ("blanchedalmond", color(255,235,205))
-            ("blue", color(0, 0, 255))
-            ("blueviolet", color(138, 43, 226))
-            ("brown", color(165, 42, 42))
-            ("burlywood", color(222, 184, 135))
-            ("cadetblue", color(95, 158, 160))
-            ("chartreuse", color(127, 255, 0))
-            ("chocolate", color(210, 105, 30))
-            ("coral", color(255, 127, 80))
-            ("cornflowerblue", color(100, 149, 237))
-            ("cornsilk", color(255, 248, 220))
-            ("crimson", color(220, 20, 60))
-            ("cyan", color(0, 255, 255))
-            ("darkblue", color(0, 0, 139))
-            ("darkcyan", color(0, 139, 139))
-            ("darkgoldenrod", color(184, 134, 11))
-            ("darkgray", color(169, 169, 169))
-            ("darkgreen", color(0, 100, 0))
-            ("darkgrey", color(169, 169, 169))
-            ("darkkhaki", color(189, 183, 107))
-            ("darkmagenta", color(139, 0, 139))
-            ("darkolivegreen", color(85, 107, 47))
-            ("darkorange", color(255, 140, 0))
-            ("darkorchid", color(153, 50, 204))
-            ("darkred", color(139, 0, 0))
-            ("darksalmon", color(233, 150, 122))
-            ("darkseagreen", color(143, 188, 143))
-            ("darkslateblue", color(72, 61, 139))
-            ("darkslategrey", color(47, 79, 79))
-            ("darkturquoise", color(0, 206, 209))
-            ("darkviolet", color(148, 0, 211))
-            ("deeppink", color(255, 20, 147))
-            ("deepskyblue", color(0, 191, 255))
-            ("dimgray", color(105, 105, 105))
-            ("dimgrey", color(105, 105, 105))
-            ("dodgerblue", color(30, 144, 255))
-            ("firebrick", color(178, 34, 34))
-            ("floralwhite", color(255, 250, 240))
-            ("forestgreen", color(34, 139, 34))
-            ("fuchsia", color(255, 0, 255))
-            ("gainsboro", color(220, 220, 220))
-            ("ghostwhite", color(248, 248, 255))
-            ("gold", color(255, 215, 0))
-            ("goldenrod", color(218, 165, 32))
-            ("gray", color(128, 128, 128))
-            ("grey", color(128, 128, 128))
-            ("green", color(0, 128, 0))
-            ("greenyellow", color(173, 255, 47))
-            ("honeydew", color(240, 255, 240))
-            ("hotpink", color(255, 105, 180))
-            ("indianred", color(205, 92, 92))
-            ("indigo", color(75, 0, 130))
-            ("ivory", color(255, 255, 240))
-            ("khaki", color(240, 230, 140))
-            ("lavender", color(230, 230, 250))
-            ("lavenderblush", color(255, 240, 245))
-            ("lawngreen", color(124, 252, 0))
-            ("lemonchiffon", color(255, 250, 205))
-            ("lightblue", color(173, 216, 230))
-            ("lightcoral", color(240, 128, 128))
-            ("lightcyan", color(224, 255, 255))
-            ("lightgoldenrodyellow", color(250, 250, 210))
-            ("lightgray", color(211, 211, 211))
-            ("lightgreen", color(144, 238, 144))
-            ("lightgrey", color(211, 211, 211))
-            ("lightpink", color(255, 182, 193))
-            ("lightsalmon", color(255, 160, 122))
-            ("lightseagreen", color(32, 178, 170))
-            ("lightskyblue", color(135, 206, 250))
-            ("lightslategray", color(119, 136, 153))
-            ("lightslategrey", color(119, 136, 153))
-            ("lightsteelblue", color(176, 196, 222))
-            ("lightyellow", color(255, 255, 224))
-            ("lime", color(0, 255, 0))
-            ("limegreen", color(50, 205, 50))
-            ("linen", color(250, 240, 230))
-            ("magenta", color(255, 0, 255))
-            ("maroon", color(128, 0, 0))
-            ("mediumaquamarine", color(102, 205, 170))
-            ("mediumblue", color(0, 0, 205))
-            ("mediumorchid", color(186, 85, 211))
-            ("mediumpurple", color(147, 112, 219))
-            ("mediumseagreen", color(60, 179, 113))
-            ("mediumslateblue", color(123, 104, 238))
-            ("mediumspringgreen", color(0, 250, 154))
-            ("mediumturquoise", color(72, 209, 204))
-            ("mediumvioletred", color(199, 21, 133))
-            ("midnightblue", color(25, 25, 112))
-            ("mintcream", color(245, 255, 250))
-            ("mistyrose", color(255, 228, 225))
-            ("moccasin", color(255, 228, 181))
-            ("navajowhite", color(255, 222, 173))
-            ("navy", color(0, 0, 128))
-            ("oldlace", color(253, 245, 230))
-            ("olive", color(128, 128, 0))
-            ("olivedrab", color(107, 142, 35))
-            ("orange", color(255, 165, 0))
-            ("orangered", color(255, 69, 0))
-            ("orchid", color(218, 112, 214))
-            ("palegoldenrod", color(238, 232, 170))
-            ("palegreen", color(152, 251, 152))
-            ("paleturquoise", color(175, 238, 238))
-            ("palevioletred", color(219, 112, 147))
-            ("papayawhip", color(255, 239, 213))
-            ("peachpuff", color(255, 218, 185))
-            ("peru", color(205, 133, 63))
-            ("pink", color(255, 192, 203))
-            ("plum", color(221, 160, 221))
-            ("powderblue", color(176, 224, 230))
-            ("purple", color(128, 0, 128))
-            ("red", color(255, 0, 0))
-            ("rosybrown", color(188, 143, 143))
-            ("royalblue", color(65, 105, 225))
-            ("saddlebrown", color(139, 69, 19))
-            ("salmon", color(250, 128, 114))
-            ("sandybrown", color(244, 164, 96))
-            ("seagreen", color(46, 139, 87))
-            ("seashell", color(255, 245, 238))
-            ("sienna", color(160, 82, 45))
-            ("silver", color(192, 192, 192))
-            ("skyblue", color(135, 206, 235))
-            ("slateblue", color(106, 90, 205))
-            ("slategray", color(112, 128, 144))
-            ("slategrey", color(112, 128, 144))
-            ("snow", color(255, 250, 250))
-            ("springgreen", color(0, 255, 127))
-            ("steelblue", color(70, 130, 180))
-            ("tan", color(210, 180, 140))
-            ("teal", color(0, 128, 128))
-            ("thistle", color(216, 191, 216))
-            ("tomato", color(255, 99, 71))
-            ("turquoise", color(64, 224, 208))
-            ("violet", color(238, 130, 238))
-            ("wheat", color(245, 222, 179))
-            ("white", color(255, 255, 255))
-            ("whitesmoke", color(245, 245, 245))
-            ("yellow", color(255, 255, 0))
-            ("yellowgreen", color(154, 205, 50))
-            ("transparent", color(0, 0, 0, 0))
-            ;
-    }
-} ;
-
-struct percent_conv_impl
-{
-    template <typename T>
-    struct result
-    {
-        using type = unsigned;
-    };
-
-    unsigned operator() (double val) const
-    {
-        return safe_cast<uint8_t>(std::lround((255.0 * val)/100.0));
-    }
-};
-
-struct alpha_conv_impl
-{
-    template <typename T>
-    struct result
-    {
-        using type = unsigned;
-    };
-
-    unsigned operator() (double val) const
-    {
-        return safe_cast<uint8_t>(std::lround((255.0 * val)));
-    }
-};
-
-struct hsl_conv_impl
-{
-    template<typename T>
-    struct result
-    {
-        using type = void;
-    };
-
-    template <typename T0,typename T1, typename T2, typename T3>
-    void operator() (T0 & c, T1 h, T2 s, T3 l) const
-    {
-        double m1,m2;
-        // normalize values
-        h /= 360.0;
-        s /= 100.0;
-        l /= 100.0;
-
-        if (l <= 0.5)
-        {
-            m2 = l * (s + 1.0);
-        }
-        else
-        {
-            m2 = l + s - l*s;
-        }
-        m1 = l * 2 - m2;
-
-        double r = hue_to_rgb(m1, m2, h + 1.0/3.0);
-        double g = hue_to_rgb(m1, m2, h);
-        double b = hue_to_rgb(m1, m2, h - 1.0/3.0);
-
-        c.set_red(safe_cast<uint8_t>(std::lround(255.0 * r)));
-        c.set_green(safe_cast<uint8_t>(std::lround(255.0 * g)));
-        c.set_blue(safe_cast<uint8_t>(std::lround(255.0 * b)));
-    }
-};
-
-
 template <typename Iterator>
 struct css_color_grammar : qi::grammar<Iterator, color(), ascii_space_type>
 {
+    // ctor
     css_color_grammar();
+    // rules
     qi::uint_parser< unsigned, 16, 2, 2 > hex2 ;
     qi::uint_parser< unsigned, 16, 1, 1 > hex1 ;
     qi::uint_parser< unsigned, 10, 1, 3 > dec3 ;
@@ -296,10 +60,6 @@ struct css_color_grammar : qi::grammar<Iterator, color(), ascii_space_type>
     qi::rule<Iterator, color(), ascii_space_type> hex_color;
     qi::rule<Iterator, color(), ascii_space_type> hex_color_small;
     qi::rule<Iterator, color(), ascii_space_type> css_color;
-    named_colors_ named;
-    phoenix::function<percent_conv_impl> percent_converter;
-    phoenix::function<alpha_conv_impl>   alpha_converter;
-    phoenix::function<hsl_conv_impl>  hsl_converter;
 };
 
 }
diff --git a/include/mapnik/css_color_grammar_impl.hpp b/include/mapnik/css_color_grammar_impl.hpp
index c978194..22fa744 100644
--- a/include/mapnik/css_color_grammar_impl.hpp
+++ b/include/mapnik/css_color_grammar_impl.hpp
@@ -22,10 +22,234 @@
 
 // NOTE: This is an implementation header file and is only meant to be included
 //    from implementation files. It therefore doesn't have an include guard.
+// mapnik
 #include <mapnik/css_color_grammar.hpp>
+// boost
+#pragma GCC diagnostic push
+#include <boost/fusion/include/adapt_adt.hpp>
+#include <boost/spirit/include/phoenix_core.hpp>
+#include <boost/spirit/include/phoenix_operator.hpp>
+#include <boost/spirit/include/phoenix_fusion.hpp>
+#pragma GCC diagnostic pop
+
+
+BOOST_FUSION_ADAPT_ADT(
+    mapnik::color,
+    (unsigned, unsigned, obj.red(), obj.set_red(mapnik::safe_cast<uint8_t>(val)))
+    (unsigned, unsigned, obj.green(), obj.set_green(mapnik::safe_cast<uint8_t>(val)))
+    (unsigned, unsigned, obj.blue(), obj.set_blue(mapnik::safe_cast<uint8_t>(val)))
+    (unsigned, unsigned, obj.alpha(), obj.set_alpha(mapnik::safe_cast<uint8_t>(val)))
+    )
 
 namespace mapnik
 {
+namespace phoenix = boost::phoenix;
+
+struct percent_conv_impl
+{
+    using result_type = unsigned;
+    unsigned operator() (double val) const
+    {
+        return safe_cast<uint8_t>(std::lround((255.0 * val)/100.0));
+    }
+};
+
+struct alpha_conv_impl
+{
+    using result_type = unsigned;
+    unsigned operator() (double val) const
+    {
+        return safe_cast<uint8_t>(std::lround((255.0 * val)));
+    }
+};
+
+struct hsl_conv_impl
+{
+    using result_type = void;
+    template <typename T0,typename T1, typename T2, typename T3>
+    void operator() (T0 & c, T1 h, T2 s, T3 l) const
+    {
+        double m1,m2;
+        // normalize values
+        h /= 360.0;
+        s /= 100.0;
+        l /= 100.0;
+
+        if (l <= 0.5)
+        {
+            m2 = l * (s + 1.0);
+        }
+        else
+        {
+            m2 = l + s - l*s;
+        }
+        m1 = l * 2 - m2;
+
+        double r = hue_to_rgb(m1, m2, h + 1.0/3.0);
+        double g = hue_to_rgb(m1, m2, h);
+        double b = hue_to_rgb(m1, m2, h - 1.0/3.0);
+
+        c.set_red(safe_cast<uint8_t>(std::lround(255.0 * r)));
+        c.set_green(safe_cast<uint8_t>(std::lround(255.0 * g)));
+        c.set_blue(safe_cast<uint8_t>(std::lround(255.0 * b)));
+    }
+};
+
+struct named_colors : qi::symbols<char,color>
+{
+    named_colors()
+    {
+        add
+            ("aliceblue", color(240, 248, 255))
+            ("antiquewhite", color(250, 235, 215))
+            ("aqua", color(0, 255, 255))
+            ("aquamarine", color(127, 255, 212))
+            ("azure", color(240, 255, 255))
+            ("beige", color(245, 245, 220))
+            ("bisque", color(255, 228, 196))
+            ("black", color(0, 0, 0))
+            ("blanchedalmond", color(255,235,205))
+            ("blue", color(0, 0, 255))
+            ("blueviolet", color(138, 43, 226))
+            ("brown", color(165, 42, 42))
+            ("burlywood", color(222, 184, 135))
+            ("cadetblue", color(95, 158, 160))
+            ("chartreuse", color(127, 255, 0))
+            ("chocolate", color(210, 105, 30))
+            ("coral", color(255, 127, 80))
+            ("cornflowerblue", color(100, 149, 237))
+            ("cornsilk", color(255, 248, 220))
+            ("crimson", color(220, 20, 60))
+            ("cyan", color(0, 255, 255))
+            ("darkblue", color(0, 0, 139))
+            ("darkcyan", color(0, 139, 139))
+            ("darkgoldenrod", color(184, 134, 11))
+            ("darkgray", color(169, 169, 169))
+            ("darkgreen", color(0, 100, 0))
+            ("darkgrey", color(169, 169, 169))
+            ("darkkhaki", color(189, 183, 107))
+            ("darkmagenta", color(139, 0, 139))
+            ("darkolivegreen", color(85, 107, 47))
+            ("darkorange", color(255, 140, 0))
+            ("darkorchid", color(153, 50, 204))
+            ("darkred", color(139, 0, 0))
+            ("darksalmon", color(233, 150, 122))
+            ("darkseagreen", color(143, 188, 143))
+            ("darkslateblue", color(72, 61, 139))
+            ("darkslategrey", color(47, 79, 79))
+            ("darkturquoise", color(0, 206, 209))
+            ("darkviolet", color(148, 0, 211))
+            ("deeppink", color(255, 20, 147))
+            ("deepskyblue", color(0, 191, 255))
+            ("dimgray", color(105, 105, 105))
+            ("dimgrey", color(105, 105, 105))
+            ("dodgerblue", color(30, 144, 255))
+            ("firebrick", color(178, 34, 34))
+            ("floralwhite", color(255, 250, 240))
+            ("forestgreen", color(34, 139, 34))
+            ("fuchsia", color(255, 0, 255))
+            ("gainsboro", color(220, 220, 220))
+            ("ghostwhite", color(248, 248, 255))
+            ("gold", color(255, 215, 0))
+            ("goldenrod", color(218, 165, 32))
+            ("gray", color(128, 128, 128))
+            ("grey", color(128, 128, 128))
+            ("green", color(0, 128, 0))
+            ("greenyellow", color(173, 255, 47))
+            ("honeydew", color(240, 255, 240))
+            ("hotpink", color(255, 105, 180))
+            ("indianred", color(205, 92, 92))
+            ("indigo", color(75, 0, 130))
+            ("ivory", color(255, 255, 240))
+            ("khaki", color(240, 230, 140))
+            ("lavender", color(230, 230, 250))
+            ("lavenderblush", color(255, 240, 245))
+            ("lawngreen", color(124, 252, 0))
+            ("lemonchiffon", color(255, 250, 205))
+            ("lightblue", color(173, 216, 230))
+            ("lightcoral", color(240, 128, 128))
+            ("lightcyan", color(224, 255, 255))
+            ("lightgoldenrodyellow", color(250, 250, 210))
+            ("lightgray", color(211, 211, 211))
+            ("lightgreen", color(144, 238, 144))
+            ("lightgrey", color(211, 211, 211))
+            ("lightpink", color(255, 182, 193))
+            ("lightsalmon", color(255, 160, 122))
+            ("lightseagreen", color(32, 178, 170))
+            ("lightskyblue", color(135, 206, 250))
+            ("lightslategray", color(119, 136, 153))
+            ("lightslategrey", color(119, 136, 153))
+            ("lightsteelblue", color(176, 196, 222))
+            ("lightyellow", color(255, 255, 224))
+            ("lime", color(0, 255, 0))
+            ("limegreen", color(50, 205, 50))
+            ("linen", color(250, 240, 230))
+            ("magenta", color(255, 0, 255))
+            ("maroon", color(128, 0, 0))
+            ("mediumaquamarine", color(102, 205, 170))
+            ("mediumblue", color(0, 0, 205))
+            ("mediumorchid", color(186, 85, 211))
+            ("mediumpurple", color(147, 112, 219))
+            ("mediumseagreen", color(60, 179, 113))
+            ("mediumslateblue", color(123, 104, 238))
+            ("mediumspringgreen", color(0, 250, 154))
+            ("mediumturquoise", color(72, 209, 204))
+            ("mediumvioletred", color(199, 21, 133))
+            ("midnightblue", color(25, 25, 112))
+            ("mintcream", color(245, 255, 250))
+            ("mistyrose", color(255, 228, 225))
+            ("moccasin", color(255, 228, 181))
+            ("navajowhite", color(255, 222, 173))
+            ("navy", color(0, 0, 128))
+            ("oldlace", color(253, 245, 230))
+            ("olive", color(128, 128, 0))
+            ("olivedrab", color(107, 142, 35))
+            ("orange", color(255, 165, 0))
+            ("orangered", color(255, 69, 0))
+            ("orchid", color(218, 112, 214))
+            ("palegoldenrod", color(238, 232, 170))
+            ("palegreen", color(152, 251, 152))
+            ("paleturquoise", color(175, 238, 238))
+            ("palevioletred", color(219, 112, 147))
+            ("papayawhip", color(255, 239, 213))
+            ("peachpuff", color(255, 218, 185))
+            ("peru", color(205, 133, 63))
+            ("pink", color(255, 192, 203))
+            ("plum", color(221, 160, 221))
+            ("powderblue", color(176, 224, 230))
+            ("purple", color(128, 0, 128))
+            ("red", color(255, 0, 0))
+            ("rosybrown", color(188, 143, 143))
+            ("royalblue", color(65, 105, 225))
+            ("saddlebrown", color(139, 69, 19))
+            ("salmon", color(250, 128, 114))
+            ("sandybrown", color(244, 164, 96))
+            ("seagreen", color(46, 139, 87))
+            ("seashell", color(255, 245, 238))
+            ("sienna", color(160, 82, 45))
+            ("silver", color(192, 192, 192))
+            ("skyblue", color(135, 206, 235))
+            ("slateblue", color(106, 90, 205))
+            ("slategray", color(112, 128, 144))
+            ("slategrey", color(112, 128, 144))
+            ("snow", color(255, 250, 250))
+            ("springgreen", color(0, 255, 127))
+            ("steelblue", color(70, 130, 180))
+            ("tan", color(210, 180, 140))
+            ("teal", color(0, 128, 128))
+            ("thistle", color(216, 191, 216))
+            ("tomato", color(255, 99, 71))
+            ("turquoise", color(64, 224, 208))
+            ("violet", color(238, 130, 238))
+            ("wheat", color(245, 222, 179))
+            ("white", color(255, 255, 255))
+            ("whitesmoke", color(245, 245, 245))
+            ("yellow", color(255, 255, 0))
+            ("yellowgreen", color(154, 205, 50))
+            ("transparent", color(0, 0, 0, 0))
+            ;
+    }
+};
 
 template <typename Iterator>
 css_color_grammar<Iterator>::css_color_grammar()
@@ -42,6 +266,12 @@ css_color_grammar<Iterator>::css_color_grammar()
     qi::lexeme_type lexeme;
     ascii::no_case_type no_case;
     using phoenix::at_c;
+    // symbols
+    named_colors named;
+    // functions
+    phoenix::function<percent_conv_impl> percent_converter;
+    phoenix::function<alpha_conv_impl>   alpha_converter;
+    phoenix::function<hsl_conv_impl>  hsl_converter;
 
     css_color %= rgba_color
         | rgba_percent_color
diff --git a/include/mapnik/csv/csv_grammar.hpp b/include/mapnik/csv/csv_grammar.hpp
index 6edecad..240f11c 100644
--- a/include/mapnik/csv/csv_grammar.hpp
+++ b/include/mapnik/csv/csv_grammar.hpp
@@ -20,20 +20,15 @@
  *
  *****************************************************************************/
 
-#ifndef MAPNIK_CVS_GRAMMAR_HPP
-#define MAPNIK_CVS_GRAMMAR_HPP
-
-//#define BOOST_SPIRIT_DEBUG
+#ifndef MAPNIK_CSV_GRAMMAR_HPP
+#define MAPNIK_CSV_GRAMMAR_HPP
 
+#include <mapnik/csv/csv_types.hpp>
 #include <boost/spirit/include/qi.hpp>
-#include <boost/spirit/include/phoenix.hpp>
 
 namespace mapnik {
 
 namespace qi = boost::spirit::qi;
-using csv_value  = std::string;
-using csv_line = std::vector<csv_value>;
-using csv_data = std::vector<csv_line>;
 
 struct csv_white_space_skipper : qi::primitive_parser<csv_white_space_skipper>
 {
@@ -70,36 +65,7 @@ struct csv_white_space_skipper : qi::primitive_parser<csv_white_space_skipper>
 template <typename Iterator, typename Skipper = csv_white_space_skipper>
 struct csv_line_grammar : qi::grammar<Iterator, csv_line(char, char), Skipper>
 {
-    csv_line_grammar()
-        : csv_line_grammar::base_type(line)
-    {
-        qi::_r1_type _r1;
-        qi::_r2_type _r2;
-        qi::lit_type lit;
-        qi::char_type char_;
-        unesc_char.add
-            ("\\a", '\a')
-            ("\\b", '\b')
-            ("\\f", '\f')
-            ("\\n", '\n')
-            ("\\r", '\r')
-            ("\\t", '\t')
-            ("\\v", '\v')
-            ("\\\\",'\\')
-            ("\\\'", '\'')
-            ("\\\"", '\"')
-            ("\"\"", '\"') // double quote
-            ;
-        line = -lit("\n\r") >> column(_r1, _r2) % lit(_r1)
-            ;
-        column = quoted(_r2) | *(char_ - lit(_r1))
-            ;
-        quoted = lit(_r1) > text(_r1) > lit(_r1) // support unmatched quotes or not (??)
-            ;
-        text = *(unesc_char | (char_ - lit(_r1)))
-            ;
-        BOOST_SPIRIT_DEBUG_NODES((line)(column)(quoted));
-    }
+    csv_line_grammar();
 private:
     qi::rule<Iterator, csv_line(char, char),  Skipper> line;
     qi::rule<Iterator, csv_value(char, char)> column; // no-skip
@@ -110,4 +76,4 @@ private:
 
 }
 
-#endif // MAPNIK_CVS_GRAMMAR_HPP
+#endif // MAPNIK_CSV_GRAMMAR_HPP
diff --git a/include/mapnik/path_expression_grammar_impl.hpp b/include/mapnik/csv/csv_grammar_impl.hpp
similarity index 50%
copy from include/mapnik/path_expression_grammar_impl.hpp
copy to include/mapnik/csv/csv_grammar_impl.hpp
index bc2fcfb..5608354 100644
--- a/include/mapnik/path_expression_grammar_impl.hpp
+++ b/include/mapnik/csv/csv_grammar_impl.hpp
@@ -2,7 +2,7 @@
  *
  * This file is part of Mapnik (c++ mapping toolkit)
  *
- * Copyright (C) 2015 Artem Pavlenko
+ * Copyright (C) 2016 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,40 +20,42 @@
  *
  *****************************************************************************/
 
-// mapnik
-#include <mapnik/path_expression_grammar.hpp>
-#include <mapnik/attribute.hpp>
+#include <mapnik/csv/csv_grammar.hpp>
 
-// boost
-#include <boost/spirit/include/phoenix_core.hpp>
-#include <boost/spirit/include/phoenix_object.hpp>
-#include <boost/spirit/include/phoenix_stl.hpp>
+namespace mapnik {
 
-namespace mapnik
-{
+namespace qi = boost::spirit::qi;
 
-template <typename Iterator>
-path_expression_grammar<Iterator>::path_expression_grammar()
-    : path_expression_grammar::base_type(expr)
+template <typename Iterator, typename Skipper>
+csv_line_grammar<Iterator, Skipper>::csv_line_grammar()
+    : csv_line_grammar::base_type(line)
 {
-    standard_wide::char_type char_;
-    qi::_1_type _1;
-    qi::_val_type _val;
+    qi::_r1_type _r1;
+    qi::_r2_type _r2;
     qi::lit_type lit;
-    qi::lexeme_type lexeme;
-    using phoenix::push_back;
-    using boost::phoenix::construct;
-
-    expr =
-        * (
-            str [ push_back(_val, _1)]
-            |
-            ( '[' >> attr [ push_back(_val, construct<mapnik::attribute>( _1 )) ] >> ']')
-            )
+    qi::char_type char_;
+    unesc_char.add
+        ("\\a", '\a')
+        ("\\b", '\b')
+        ("\\f", '\f')
+        ("\\n", '\n')
+        ("\\r", '\r')
+        ("\\t", '\t')
+        ("\\v", '\v')
+        ("\\\\",'\\')
+        ("\\\'", '\'')
+        ("\\\"", '\"')
+        ("\"\"", '\"') // double quote
         ;
-
-    attr %= +(char_ - ']');
-    str  %= lexeme[+(char_ -'[')];
+    line = -lit("\r") > -lit("\n") > column(_r1, _r2) % lit(_r1)
+        ;
+    column = quoted(_r2) | *(char_ - lit(_r1))
+        ;
+    quoted = lit(_r1) > text(_r1) > lit(_r1) // support unmatched quotes or not (??)
+        ;
+    text = *(unesc_char | (char_ - lit(_r1)))
+        ;
+    BOOST_SPIRIT_DEBUG_NODES((line)(column)(quoted));
 }
 
-}
+} // namespace mapnik
diff --git a/include/mapnik/grid/grid_rendering_buffer.hpp b/include/mapnik/csv/csv_types.hpp
similarity index 79%
copy from include/mapnik/grid/grid_rendering_buffer.hpp
copy to include/mapnik/csv/csv_types.hpp
index 4282e3b..5359c3d 100644
--- a/include/mapnik/grid/grid_rendering_buffer.hpp
+++ b/include/mapnik/csv/csv_types.hpp
@@ -20,16 +20,18 @@
  *
  *****************************************************************************/
 
-#ifndef MAPNIK_GRID_RENDERING_BUFFER_HPP
-#define MAPNIK_GRID_RENDERING_BUFFER_HPP
+#ifndef MAPNIK_CSV_TYPES_HPP
+#define MAPNIK_CSV_TYPES_HPP
 
-#include <mapnik/grid/grid.hpp>
-#include "agg_rendering_buffer.h"
+#include <string>
+#include <vector>
 
 namespace mapnik {
 
-using grid_rendering_buffer = agg::row_ptr_cache<mapnik::grid::value_type>;
+using csv_value = std::string;
+using csv_line = std::vector<csv_value>;
+using csv_data = std::vector<csv_line>;
 
 }
 
-#endif //MAPNIK_AGG_RASTERIZER_HPP
+#endif // MAPNIK_CSV_TYPES_HPP
diff --git a/include/mapnik/expression_grammar.hpp b/include/mapnik/expression_grammar.hpp
index ea65425..ad35589 100644
--- a/include/mapnik/expression_grammar.hpp
+++ b/include/mapnik/expression_grammar.hpp
@@ -25,88 +25,18 @@
 
 // mapnik
 #include <mapnik/config.hpp>
-#include <mapnik/value_types.hpp>
-#include <mapnik/unicode.hpp>
 #include <mapnik/expression_node.hpp>
-#include <mapnik/function_call.hpp>
-
 #pragma GCC diagnostic push
 #include <mapnik/warning_ignore.hpp>
 #include <boost/spirit/include/qi.hpp>
-#include <boost/spirit/include/support_locals.hpp>
-#include <boost/spirit/include/phoenix_function.hpp>
-#include <boost/fusion/adapted/struct.hpp>
 #pragma GCC diagnostic pop
 
-BOOST_FUSION_ADAPT_STRUCT(mapnik::unary_function_call,
-                          (mapnik::unary_function_impl, fun)
-                          (mapnik::unary_function_call::argument_type, arg))
-
-BOOST_FUSION_ADAPT_STRUCT(mapnik::binary_function_call,
-                          (mapnik::binary_function_impl, fun)
-                          (mapnik::binary_function_call::argument_type, arg1)
-                          (mapnik::binary_function_call::argument_type, arg2))
-
 namespace mapnik
 {
 namespace qi = boost::spirit::qi;
 namespace standard_wide =  boost::spirit::standard_wide;
 using standard_wide::space_type;
 
-struct unicode_impl
-{
-    template <typename T>
-    struct result
-    {
-        using type = mapnik::value_unicode_string;
-    };
-
-    explicit unicode_impl(mapnik::transcoder const& tr)
-        : tr_(tr) {}
-
-    mapnik::value_unicode_string operator()(std::string const& str) const
-    {
-        return tr_.transcode(str.c_str());
-    }
-
-    mapnik::transcoder const& tr_;
-};
-
-struct regex_match_impl
-{
-    template <typename T>
-    struct result
-    {
-        using type = expr_node;
-    };
-
-    explicit regex_match_impl(mapnik::transcoder const& tr)
-        : tr_(tr) {}
-
-    template <typename T0,typename T1>
-    expr_node operator() (T0 & node, T1 const& pattern) const;
-
-    mapnik::transcoder const& tr_;
-};
-
-struct regex_replace_impl
-{
-
-    template <typename T>
-    struct result
-    {
-        using type = expr_node;
-    };
-
-    explicit regex_replace_impl(mapnik::transcoder const& tr)
-        : tr_(tr) {}
-
-    template <typename T0,typename T1,typename T2>
-    expr_node operator() (T0 & node, T1 const& pattern, T2 const& format) const;
-
-    mapnik::transcoder const& tr_;
-};
-
 template <typename T>
 struct integer_parser
 {
@@ -139,9 +69,7 @@ struct expression_grammar : qi::grammar<Iterator, expr_node(), space_type>
     qi::real_parser<double, qi::strict_real_policies<double> > strict_double;
     typename integer_parser<mapnik::value_integer>::type int__;
     mapnik::transcoder tr_;
-    boost::phoenix::function<unicode_impl> unicode_;
-    boost::phoenix::function<regex_match_impl> regex_match_;
-    boost::phoenix::function<regex_replace_impl> regex_replace_;
+
     rule_type expr;
     rule_type equality_expr;
     rule_type cond_expr;
@@ -159,6 +87,7 @@ struct expression_grammar : qi::grammar<Iterator, expr_node(), space_type>
     qi::rule<Iterator, std::string() , space_type> attr;
     qi::rule<Iterator, std::string() , space_type> global_attr;
     qi::rule<Iterator, std::string(), qi::locals<char> > quoted_ustring;
+    qi::rule<Iterator, std::string()> unquoted_ustring;
     qi::rule<Iterator, std::string(), space_type> ustring;
 
     qi::symbols<char const, char const> unesc_char;
diff --git a/include/mapnik/expression_grammar_impl.hpp b/include/mapnik/expression_grammar_impl.hpp
index 8202fca..40be6b9 100644
--- a/include/mapnik/expression_grammar_impl.hpp
+++ b/include/mapnik/expression_grammar_impl.hpp
@@ -32,11 +32,21 @@
 
 #pragma GCC diagnostic push
 #include <mapnik/warning_ignore.hpp>
-#include <boost/spirit/include/qi.hpp>
+#include <boost/fusion/adapted/struct.hpp>
 #include <boost/spirit/include/phoenix_operator.hpp>
 #include <boost/spirit/include/phoenix_object.hpp>
+#include <boost/spirit/include/phoenix_function.hpp>
 #pragma GCC diagnostic pop
 
+BOOST_FUSION_ADAPT_STRUCT(mapnik::unary_function_call,
+                          (mapnik::unary_function_impl, fun)
+                          (mapnik::unary_function_call::argument_type, arg))
+
+BOOST_FUSION_ADAPT_STRUCT(mapnik::binary_function_call,
+                          (mapnik::binary_function_impl, fun)
+                          (mapnik::binary_function_call::argument_type, arg1)
+                          (mapnik::binary_function_call::argument_type, arg2))
+
 // fwd declare
 namespace mapnik {
   struct attribute;
@@ -46,6 +56,44 @@ namespace mapnik {
 namespace mapnik
 {
 
+struct unicode_impl
+{
+    using result_type = mapnik::value_unicode_string;
+    explicit unicode_impl(mapnik::transcoder const& tr)
+        : tr_(tr) {}
+
+    mapnik::value_unicode_string operator()(std::string const& str) const
+    {
+        return tr_.transcode(str.c_str());
+    }
+
+    mapnik::transcoder const& tr_;
+};
+
+struct regex_match_impl
+{
+    using result_type = expr_node;
+    explicit regex_match_impl(mapnik::transcoder const& tr)
+        : tr_(tr) {}
+
+    template <typename T0,typename T1>
+    expr_node operator() (T0 & node, T1 const& pattern) const;
+
+    mapnik::transcoder const& tr_;
+};
+
+struct regex_replace_impl
+{
+    using result_type = expr_node;
+    explicit regex_replace_impl(mapnik::transcoder const& tr)
+        : tr_(tr) {}
+
+    template <typename T0,typename T1,typename T2>
+    expr_node operator() (T0 & node, T1 const& pattern, T2 const& format) const;
+
+    mapnik::transcoder const& tr_;
+};
+
 unary_function_types::unary_function_types()
 {
     add
@@ -83,10 +131,7 @@ expr_node regex_replace_impl::operator() (T0 & node, T1 const& pattern, T2 const
 template <typename Iterator>
 expression_grammar<Iterator>::expression_grammar(std::string const& encoding)
     : expression_grammar::base_type(expr),
-      tr_(encoding),
-      unicode_(unicode_impl(tr_)),
-      regex_match_(regex_match_impl(tr_)),
-      regex_replace_(regex_replace_impl(tr_))
+      tr_(encoding)
 {
     qi::_1_type _1;
     qi::_a_type _a;
@@ -105,6 +150,10 @@ expression_grammar<Iterator>::expression_grammar(std::string const& encoding)
     using boost::phoenix::construct;
     using boost::phoenix::if_else;
 
+    boost::phoenix::function<unicode_impl> unicode = unicode_impl(tr_);
+    boost::phoenix::function<regex_match_impl> regex_match = regex_match_impl(tr_);
+    boost::phoenix::function<regex_replace_impl> regex_replace = regex_replace_impl(tr_);
+
     constant.add
         ("null",        mapnik::value_null())
         ("false",       mapnik::value_bool(false))
@@ -119,7 +168,7 @@ expression_grammar<Iterator>::expression_grammar(std::string const& encoding)
         ;
 
     expr = logical_expr [_val = _1]
-        | ustring [_val = unicode_(_1)]
+        //| ustring [_val = unicode(_1)]
         ;
 
     logical_expr = not_expr [_val = _1]
@@ -156,7 +205,7 @@ expression_grammar<Iterator>::expression_grammar(std::string const& encoding)
         >> quoted_ustring           [_a = _1]
         >> lit(',')
         >> quoted_ustring           [_b = _1]
-        >> lit(')')          [_val = regex_replace_(_r1,_a,_b)]
+        >> lit(')')          [_val = regex_replace(_r1,_a,_b)]
         ;
 
     relational_expr = additive_expr[_val = _1]
@@ -178,7 +227,7 @@ expression_grammar<Iterator>::expression_grammar(std::string const& encoding)
         >> *(     '*' >> unary_expr [_val *= _1]
                   | '/' >> unary_expr [_val /= _1]
                   | '%' >> unary_expr [_val %= construct<mapnik::expr_node>(_1)] //needed by clang++ with -std=c++11
-                  |  regex_match_expr[_val = regex_match_(_val, _1)]
+                  |  regex_match_expr[_val = regex_match(_val, _1)]
                   |  regex_replace_expr(_val) [_val = _1]
             )
         ;
@@ -198,7 +247,7 @@ expression_grammar<Iterator>::expression_grammar(std::string const& encoding)
     primary_expr = strict_double [_val = _1]
         | int__[_val = _1]
         | no_case[constant] [_val = _1]
-        | quoted_ustring [_val = unicode_(_1)]
+        | quoted_ustring [_val = unicode(_1)]
         | attr [if_else(_1 == "mapnik::geometry_type",
                         _val = construct<mapnik::geometry_type_attribute>(),
                         _val = construct<mapnik::attribute>(_1))]
@@ -206,6 +255,9 @@ expression_grammar<Iterator>::expression_grammar(std::string const& encoding)
         | unary_function_expr [_val = _1]
         | binary_function_expr [_val = _1]
         | '(' > logical_expr [_val = _1 ] > ')'
+        //  TODO: this is a backward compatibility hack to allow unquoted strings
+        | unquoted_ustring [_val = unicode(_1)]
+        // ^ https://github.com/mapnik/mapnik/pull/3389
         ;
 
     unesc_char.add("\\a", '\a')("\\b", '\b')("\\f", '\f')("\\n", '\n')
@@ -218,6 +270,7 @@ expression_grammar<Iterator>::expression_grammar(std::string const& encoding)
     quoted_ustring %= omit[quote_char[_a = _1]]
         >> *(unesc_char | "\\x" >> hex | (char_ - lit(_a)))
         >> lit(_a);
+    unquoted_ustring %= no_skip[alpha >> *alnum] - lit("not");
     attr %= '[' >> no_skip[+~char_(']')] >> ']';
     global_attr %= '@' >> no_skip[alpha >> * (alnum | char_('-'))];
 
diff --git a/include/mapnik/expression_node.hpp b/include/mapnik/expression_node.hpp
index 7731414..6fdad8f 100644
--- a/include/mapnik/expression_node.hpp
+++ b/include/mapnik/expression_node.hpp
@@ -31,6 +31,8 @@
 #include <mapnik/attribute.hpp>
 #include <mapnik/function_call.hpp>
 #include <mapnik/expression_node_types.hpp>
+// stl
+#include <memory>
 
 namespace mapnik
 {
diff --git a/include/mapnik/feature_kv_iterator.hpp b/include/mapnik/feature_kv_iterator.hpp
index 37093a8..77b292f 100644
--- a/include/mapnik/feature_kv_iterator.hpp
+++ b/include/mapnik/feature_kv_iterator.hpp
@@ -27,12 +27,14 @@
 #include <mapnik/config.hpp>
 #include <mapnik/value.hpp>
 #include <mapnik/util/variant.hpp>
-// boost
 
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/iterator/iterator_traits.hpp>
 #include <boost/iterator/iterator_facade.hpp>
 #include <boost/iterator/iterator_adaptor.hpp>
 #include <boost/iterator/filter_iterator.hpp>
+#pragma GCC diagnostic pop
 
 // stl
 #include <map>
diff --git a/include/mapnik/feature_type_style.hpp b/include/mapnik/feature_type_style.hpp
index 68240af..9f9f1ae 100644
--- a/include/mapnik/feature_type_style.hpp
+++ b/include/mapnik/feature_type_style.hpp
@@ -29,8 +29,10 @@
 #include <mapnik/image_filter_types.hpp>
 #include <mapnik/image_compositing.hpp>
 
-// boost
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/optional.hpp>
+#pragma GCC diagnostic pop
 
 // stl
 #include <vector>
diff --git a/include/mapnik/global.hpp b/include/mapnik/global.hpp
index aa5be35..39a8c5f 100644
--- a/include/mapnik/global.hpp
+++ b/include/mapnik/global.hpp
@@ -99,14 +99,14 @@ inline void read_int32_xdr(const char* data, std::int32_t & val)
 // read double XDR (big endian)
 inline void read_double_xdr(const char* data, double & val)
 {
-    std::int64_t bits = ((std::int64_t)data[7] & 0xff) |
-        ((std::int64_t)data[6] & 0xff) << 8   |
-        ((std::int64_t)data[5] & 0xff) << 16  |
-        ((std::int64_t)data[4] & 0xff) << 24  |
-        ((std::int64_t)data[3] & 0xff) << 32  |
-        ((std::int64_t)data[2] & 0xff) << 40  |
-        ((std::int64_t)data[1] & 0xff) << 48  |
-        ((std::int64_t)data[0] & 0xff) << 56  ;
+    std::int64_t bits = (static_cast<std::int64_t>(data[7]) & 0xff) |
+        (static_cast<std::int64_t>(data[6]) & 0xff) << 8   |
+        (static_cast<std::int64_t>(data[5]) & 0xff) << 16  |
+        (static_cast<std::int64_t>(data[4]) & 0xff) << 24  |
+        (static_cast<std::int64_t>(data[3]) & 0xff) << 32  |
+        (static_cast<std::int64_t>(data[2]) & 0xff) << 40  |
+        (static_cast<std::int64_t>(data[1]) & 0xff) << 48  |
+        (static_cast<std::int64_t>(data[0]) & 0xff) << 56  ;
     std::memcpy(&val,&bits,8);
 }
 
diff --git a/include/mapnik/gradient.hpp b/include/mapnik/gradient.hpp
index f151ebe..ae9acb5 100644
--- a/include/mapnik/gradient.hpp
+++ b/include/mapnik/gradient.hpp
@@ -23,8 +23,10 @@
 #ifndef MAPNIK_GRADIENT_HPP
 #define MAPNIK_GRADIENT_HPP
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include <agg_trans_affine.h>
+#pragma GCC diagnostic pop
 
 // mapnik
 #include <mapnik/color.hpp>
diff --git a/include/mapnik/grid/grid_rasterizer.hpp b/include/mapnik/grid/grid_rasterizer.hpp
index 98a6dd3..6129447 100644
--- a/include/mapnik/grid/grid_rasterizer.hpp
+++ b/include/mapnik/grid/grid_rasterizer.hpp
@@ -24,7 +24,11 @@
 #define MAPNIK_GRID_RASTERIZER_HPP
 
 #include <mapnik/util/noncopyable.hpp>
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_rasterizer_scanline_aa.h"
+#pragma GCC diagnostic pop
 
 namespace mapnik {
 
diff --git a/include/mapnik/grid/grid_render_marker.hpp b/include/mapnik/grid/grid_render_marker.hpp
index 8f345e3..5ad5fea 100644
--- a/include/mapnik/grid/grid_render_marker.hpp
+++ b/include/mapnik/grid/grid_render_marker.hpp
@@ -26,7 +26,8 @@
 // mapnik
 #include <mapnik/feature.hpp>
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_renderer_scanline.h"
 #include "agg_scanline_bin.h"
 #include "agg_image_filters.h"
@@ -34,7 +35,7 @@
 #include "agg_span_allocator.h"
 #include "agg_image_accessors.h"
 #include "agg_span_image_filter_gray.h"
-
+#pragma GCC diagnostic pop
 
 namespace mapnik {
 
diff --git a/include/mapnik/grid/grid_renderer_base.hpp b/include/mapnik/grid/grid_renderer_base.hpp
index 1000083..bcc2e18 100644
--- a/include/mapnik/grid/grid_renderer_base.hpp
+++ b/include/mapnik/grid/grid_renderer_base.hpp
@@ -24,11 +24,11 @@
 #define MAPNIK_GRID_RENDERER_BASE_HPP
 
 #pragma GCC diagnostic push
-#include <mapnik/warning_ignore.hpp>
-#include "agg_renderer_base.h"
+#include <mapnik/warning_ignore_agg.hpp>
 #include <mapnik/grid/grid_pixel.hpp>
-#pragma GCC diagnostic pop
 #include <mapnik/grid/grid_pixfmt.hpp>
+#include "agg_renderer_base.h"
+#pragma GCC diagnostic pop
 
 namespace mapnik {
 
diff --git a/include/mapnik/grid/grid_rendering_buffer.hpp b/include/mapnik/grid/grid_rendering_buffer.hpp
index 4282e3b..8ab12cf 100644
--- a/include/mapnik/grid/grid_rendering_buffer.hpp
+++ b/include/mapnik/grid/grid_rendering_buffer.hpp
@@ -24,7 +24,11 @@
 #define MAPNIK_GRID_RENDERING_BUFFER_HPP
 
 #include <mapnik/grid/grid.hpp>
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_rendering_buffer.h"
+#pragma GCC diagnostic pop
 
 namespace mapnik {
 
diff --git a/include/mapnik/hextree.hpp b/include/mapnik/hextree.hpp
index 4664624..5d8adc1 100644
--- a/include/mapnik/hextree.hpp
+++ b/include/mapnik/hextree.hpp
@@ -365,20 +365,20 @@ private:
         if (r->count>0)
         {
             printf("%d: (+%d/%d/%.5f) (%d %d %d %d)\n",
-                   id, (int)r->count, (int)r->pixel_count, r->reduce_cost,
-                   (int)round(gamma(r->reds / r->count, gamma_)),
-                   (int)round(gamma(r->greens / r->count, gamma_)),
-                   (int)round(gamma(r->blues / r->count, gamma_)),
-                   (int)(r->alphas / r->count));
+                   id, static_cast<int>(r->count), static_cast<int>(r->pixel_count), r->reduce_cost,
+                   static_cast<int>(round(gamma(r->reds / r->count, gamma_))),
+                   static_cast<int>(round(gamma(r->greens / r->count, gamma_))),
+                   static_cast<int>(round(gamma(r->blues / r->count, gamma_))),
+                   static_cast<int>((r->alphas / r->count)));
         }
         else
         {
             printf("%d: (%d/%d/%.5f) (%d %d %d %d)\n", id,
-                   (int)r->count, (int)r->pixel_count, r->reduce_cost,
-                   (int)round(gamma(r->reds / r->pixel_count, gamma_)),
-                   (int)round(gamma(r->greens / r->pixel_count, gamma_)),
-                   (int)round(gamma(r->blues / r->pixel_count, gamma_)),
-                   (int)(r->alphas / r->pixel_count));
+                   static_cast<int>(r->count), static_cast<int>(r->pixel_count), r->reduce_cost,
+                   static_cast<int>(round(gamma(r->reds / r->pixel_count, gamma_))),
+                   static_cast<int>(round(gamma(r->greens / r->pixel_count, gamma_))),
+                   static_cast<int>(round(gamma(r->blues / r->pixel_count, gamma_))),
+                   static_cast<int>((r->alphas / r->pixel_count)));
         }
         for (unsigned idx=0; idx < 16; ++idx)
         {
@@ -399,9 +399,9 @@ private:
             std::uint8_t a = std::uint8_t(itr->alphas/float(count));
             if (a > InsertPolicy::MAX_ALPHA) a = 255;
             if (a < InsertPolicy::MIN_ALPHA) a = 0;
-            palette.push_back(rgba((std::uint8_t)round(gamma(itr->reds   / count, gamma_)),
-                                   (std::uint8_t)round(gamma(itr->greens / count, gamma_)),
-                                   (std::uint8_t)round(gamma(itr->blues  / count, gamma_)), a));
+            palette.push_back(rgba(static_cast<std::uint8_t>(round(gamma(itr->reds   / count, gamma_))),
+                                   static_cast<std::uint8_t>(round(gamma(itr->greens / count, gamma_))),
+                                   static_cast<std::uint8_t>(round(gamma(itr->blues  / count, gamma_))), a));
         }
         for (unsigned idx=0; idx < 16; ++idx)
         {
diff --git a/include/mapnik/image_compositing.hpp b/include/mapnik/image_compositing.hpp
index 2967be7..82b89a3 100644
--- a/include/mapnik/image_compositing.hpp
+++ b/include/mapnik/image_compositing.hpp
@@ -26,8 +26,10 @@
 #include <mapnik/config.hpp>
 #include <mapnik/image.hpp>
 
-// boost
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/optional.hpp>
+#pragma GCC diagnostic pop
 
 // stl
 #include <string>
diff --git a/include/mapnik/image_filter.hpp b/include/mapnik/image_filter.hpp
index 9b0b754..a96d4cd 100644
--- a/include/mapnik/image_filter.hpp
+++ b/include/mapnik/image_filter.hpp
@@ -34,7 +34,8 @@
 #include <boost/gil/gil_all.hpp>
 #pragma GCC diagnostic pop
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_basics.h"
 #include "agg_rendering_buffer.h"
 #include "agg_color_rgba.h"
@@ -42,6 +43,8 @@
 #include "agg_scanline_u.h"
 #include "agg_blur.h"
 #include "agg_gradient_lut.h"
+#pragma GCC diagnostic pop
+
 // stl
 #include <cmath>
 
diff --git a/include/mapnik/image_filter_grammar.hpp b/include/mapnik/image_filter_grammar.hpp
index 7ab2d12..ca96116 100644
--- a/include/mapnik/image_filter_grammar.hpp
+++ b/include/mapnik/image_filter_grammar.hpp
@@ -47,12 +47,7 @@ namespace qi = boost::spirit::qi;
 
 struct percent_offset_impl
 {
-    template <typename T>
-    struct result
-    {
-        using type = double;
-    };
-
+    using result_type = double;
     double operator() (double val) const
     {
         double result = std::abs(val/100.0);
@@ -79,11 +74,9 @@ struct image_filter_grammar :
     css_color_grammar<Iterator> css_color_;
     qi::rule<Iterator, filter::color_stop(), qi::ascii::space_type> color_stop_;
     qi::rule<Iterator, double(), qi::ascii::space_type> color_stop_offset;
-    phoenix::function<percent_offset_impl> percent_offset;
 
 private:
     alternative_type & add(std::string const& symbol);
-
     static constexpr unsigned max_alternatives = 16;
     unsigned num_alternatives = 0;
     alternative_type alternative_storage[max_alternatives];
diff --git a/include/mapnik/image_filter_grammar_impl.hpp b/include/mapnik/image_filter_grammar_impl.hpp
index 98de711..bf17700 100644
--- a/include/mapnik/image_filter_grammar_impl.hpp
+++ b/include/mapnik/image_filter_grammar_impl.hpp
@@ -64,6 +64,9 @@ image_filter_grammar<Iterator,ContType>::image_filter_grammar()
     using phoenix::push_back;
     using phoenix::construct;
 
+    // functions
+    phoenix::function<percent_offset_impl> percent_offset;
+
     start = -(filter % *lit(','))
         ;
 
diff --git a/include/mapnik/image_options.hpp b/include/mapnik/image_options.hpp
index fc8f9f1..d44b2bf 100644
--- a/include/mapnik/image_options.hpp
+++ b/include/mapnik/image_options.hpp
@@ -25,7 +25,12 @@
 
 #include <map>
 #include <string>
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/optional.hpp>
+#pragma GCC diagnostic pop
+
 
 namespace mapnik {
 
diff --git a/include/mapnik/image_reader.hpp b/include/mapnik/image_reader.hpp
index a15d7c9..6c1c232 100644
--- a/include/mapnik/image_reader.hpp
+++ b/include/mapnik/image_reader.hpp
@@ -29,8 +29,12 @@
 #include <mapnik/util/noncopyable.hpp>
 #include <mapnik/factory.hpp>
 #include <mapnik/box2d.hpp>
-// boost
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/optional.hpp>
+#pragma GCC diagnostic pop
+
 // stl
 #include <stdexcept>
 #include <string>
diff --git a/include/mapnik/image_scaling.hpp b/include/mapnik/image_scaling.hpp
index ddae368..461e99f 100644
--- a/include/mapnik/image_scaling.hpp
+++ b/include/mapnik/image_scaling.hpp
@@ -30,8 +30,11 @@
 // stl
 #include <iosfwd>
 
-// boost
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/optional.hpp>
+#pragma GCC diagnostic pop
+
 
 namespace mapnik
 {
diff --git a/include/mapnik/image_scaling_traits.hpp b/include/mapnik/image_scaling_traits.hpp
index 81ddf54..b8daff1 100644
--- a/include/mapnik/image_scaling_traits.hpp
+++ b/include/mapnik/image_scaling_traits.hpp
@@ -28,7 +28,8 @@
 #include <mapnik/image_scaling.hpp>
 #include <mapnik/span_image_filter.hpp>
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_image_accessors.h"
 #include "agg_pixfmt_rgba.h"
 #include "agg_pixfmt_gray.h"
@@ -36,6 +37,7 @@
 #include "agg_span_image_filter_gray.h"
 #include "agg_span_image_filter_rgba.h"
 #include "agg_span_interpolator_linear.h"
+#pragma GCC diagnostic pop
 
 namespace mapnik  { namespace detail {
 
diff --git a/include/mapnik/json/error_handler.hpp b/include/mapnik/json/error_handler.hpp
index 46a92c8..1e66427 100644
--- a/include/mapnik/json/error_handler.hpp
+++ b/include/mapnik/json/error_handler.hpp
@@ -24,13 +24,18 @@
 #define MAPNIK_JSON_ERROR_HANDLER_HPP
 
 #include <mapnik/config.hpp>
+
 #pragma GCC diagnostic push
 #include <mapnik/warning_ignore.hpp>
-#include <boost/spirit/home/qi.hpp>
-#include <boost/spirit/home/support/info.hpp>
+#include <boost/spirit/home/qi/nonterminal/error_handler.hpp>
+namespace boost { namespace spirit { struct info; } }
 #pragma GCC diagnostic pop
+
 // mapnik
+#ifdef MAPNIK_LOG
 #include <mapnik/debug.hpp>
+#endif
+
 // stl
 #include <cassert>
 #include <string>
diff --git a/include/mapnik/json/extract_bounding_box_grammar.hpp b/include/mapnik/json/extract_bounding_box_grammar.hpp
index 7d0b7a1..906e712 100644
--- a/include/mapnik/json/extract_bounding_box_grammar.hpp
+++ b/include/mapnik/json/extract_bounding_box_grammar.hpp
@@ -32,73 +32,31 @@
 #pragma GCC diagnostic push
 #include <mapnik/warning_ignore.hpp>
 #include <boost/spirit/include/qi.hpp>
-#include <boost/spirit/include/phoenix_function.hpp>
-#include <boost/fusion/adapted/std_tuple.hpp>
 #pragma GCC diagnostic pop
 
-// stl
-#include <tuple>
-
 namespace mapnik { namespace json {
 
-using position_type = mapnik::geometry::point<double>;
-using boxes_type = std::vector<std::pair<box2d<double>, std::pair<std::size_t, std::size_t>>>;
-
 namespace qi = boost::spirit::qi;
 
-struct calculate_bounding_box_impl
-{
-    using result_type = void;
-    template <typename T0, typename T1>
-    result_type operator() (T0 & bbox, T1 const& pos) const
-    {
-        if (pos)
-        {
-            double x = pos->x;
-            double y = pos->y;
-            if (!bbox.valid())
-            {
-                bbox.init(x, y, x, y); //TODO: add init(x,y) convinience method
-            }
-            else
-            {
-                bbox.expand_to_include(x, y);
-            }
-        }
-    }
-};
-
-struct push_box_impl
-{
-    using result_type = void;
-    template <typename T0, typename T1, typename T2, typename T3>
-    void operator() (T0 & boxes, T1 const& begin, T2 const& box, T3 const& range) const
-    {
-        if (box.valid()) boxes.emplace_back(box, std::make_pair(std::distance(begin, range.begin()), std::distance(range.begin(), range.end())));
-    }
-};
-
-template <typename Iterator, typename ErrorHandler = error_handler<Iterator> >
+template <typename Iterator, typename Boxes, typename ErrorHandler = error_handler<Iterator> >
 struct extract_bounding_box_grammar :
-        qi::grammar<Iterator, void(boxes_type&), space_type>
+        qi::grammar<Iterator, void(Boxes&), space_type>
 {
+    using position_type = mapnik::geometry::point<double>;
+    using boxes_type = Boxes;
+    using box_type = typename Boxes::value_type::first_type;
     extract_bounding_box_grammar();
     // rules
     qi::rule<Iterator, void(boxes_type&), space_type> start;
     qi::rule<Iterator, qi::locals<Iterator>, void(boxes_type&), space_type> features;
-    qi::rule<Iterator, qi::locals<int, box2d<double>>, void(boxes_type&, Iterator const&), space_type> feature;
-    qi::rule<Iterator, qi::locals<box2d<double>>, box2d<double>(), space_type> coords;
+    qi::rule<Iterator, qi::locals<int, box_type>, void(boxes_type&, Iterator const&), space_type> feature;
+    qi::rule<Iterator, qi::locals<box_type>, box_type(), space_type> coords;
     qi::rule<Iterator, boost::optional<position_type>(), space_type> pos;
-    qi::rule<Iterator, void(box2d<double>&), space_type> ring;
-    qi::rule<Iterator, void(box2d<double>&), space_type> rings;
-    qi::rule<Iterator, void(box2d<double>&), space_type> rings_array;
+    qi::rule<Iterator, void(box_type&), space_type> ring;
+    qi::rule<Iterator, void(box_type&), space_type> rings;
+    qi::rule<Iterator, void(box_type&), space_type> rings_array;
     // generic JSON support
     json::generic_json<Iterator> json;
-    // phoenix functions
-    boost::phoenix::function<push_box_impl> push_box;
-    boost::phoenix::function<calculate_bounding_box_impl> calculate_bounding_box;
-    // error handler
-    boost::phoenix::function<ErrorHandler> const error_handler;
 };
 
 }}
diff --git a/include/mapnik/json/extract_bounding_box_grammar_impl.hpp b/include/mapnik/json/extract_bounding_box_grammar_impl.hpp
index a6d3218..8a7fc33 100644
--- a/include/mapnik/json/extract_bounding_box_grammar_impl.hpp
+++ b/include/mapnik/json/extract_bounding_box_grammar_impl.hpp
@@ -22,24 +22,60 @@
 
 // mapnik
 #include <mapnik/json/extract_bounding_box_grammar.hpp>
-
+#include <mapnik/geometry_fusion_adapted.hpp>
 // boost
 #include <boost/spirit/include/qi_omit.hpp>
 #include <boost/spirit/include/phoenix_object.hpp>
 #include <boost/spirit/include/phoenix_stl.hpp>
 #include <boost/spirit/include/phoenix_operator.hpp>
 #include <boost/spirit/repository/include/qi_iter_pos.hpp>
+#include <boost/spirit/include/phoenix_function.hpp>
 // stl
 #include <iostream>
 #include <string>
 
 namespace mapnik { namespace json {
 
+struct calculate_bounding_box_impl
+{
+    using result_type = void;
+    template <typename T0, typename T1>
+    result_type operator() (T0 & bbox, T1 const& pos) const
+    {
+        if (pos)
+        {
+            typename T0::value_type x = pos->x;
+            typename T0::value_type y = pos->y;
+            if (!bbox.valid())
+            {
+                bbox.init(x, y);
+            }
+            else
+            {
+                bbox.expand_to_include(x, y);
+            }
+        }
+    }
+};
+
+struct push_box_impl
+{
+    using result_type = void;
+    template <typename T0, typename T1, typename T2, typename T3>
+    void operator() (T0 & boxes, T1 const& begin, T2 const& box, T3 const& range) const
+    {
+        if (box.valid()) boxes.emplace_back(box,
+                                            std::make_pair(std::distance(begin,
+                                                                         range.begin()),
+                                                           std::distance(range.begin(), range.end())));
+    }
+};
+
 namespace repo = boost::spirit::repository;
 
-template <typename Iterator, typename ErrorHandler>
-extract_bounding_box_grammar<Iterator, ErrorHandler>::extract_bounding_box_grammar()
-    : extract_bounding_box_grammar::base_type(start,"bounding boxes")
+template <typename Iterator, typename Boxes, typename ErrorHandler>
+extract_bounding_box_grammar<Iterator, Boxes, ErrorHandler>::extract_bounding_box_grammar()
+    : extract_bounding_box_grammar::base_type(start, "GeoJSON bounding boxes")
 {
     qi::lit_type lit;
     qi::double_type double_;
@@ -61,6 +97,12 @@ extract_bounding_box_grammar<Iterator, ErrorHandler>::extract_bounding_box_gramm
     using qi::fail;
     using qi::on_error;
 
+    // phoenix functions
+    boost::phoenix::function<push_box_impl> push_box;
+    boost::phoenix::function<calculate_bounding_box_impl> calculate_bounding_box;
+    // error handler
+    boost::phoenix::function<ErrorHandler> const error_handler;
+
     start = features(_r1)
         ;
 
diff --git a/include/mapnik/json/feature_grammar.hpp b/include/mapnik/json/feature_grammar.hpp
index a4bdfa1..ae59e3b 100644
--- a/include/mapnik/json/feature_grammar.hpp
+++ b/include/mapnik/json/feature_grammar.hpp
@@ -89,13 +89,10 @@ struct set_geometry_impl
     }
 };
 
-template <typename Iterator, typename FeatureType, typename ErrorHandler = error_handler<Iterator> >
-struct feature_grammar :
-        qi::grammar<Iterator, void(FeatureType&),
-                    space_type>
+template <typename Iterator, typename FeatureType, typename ErrorHandler = error_handler<Iterator>>
+struct feature_grammar : qi::grammar<Iterator, void(FeatureType&), space_type>
 {
-    feature_grammar(mapnik::transcoder const& tr);
-
+    explicit feature_grammar(mapnik::transcoder const& tr);
     // generic JSON
     generic_json<Iterator> json_;
     // geoJSON
diff --git a/include/mapnik/json/geometry_generator_grammar.hpp b/include/mapnik/json/geometry_generator_grammar.hpp
index eb484b6..0e31465 100644
--- a/include/mapnik/json/geometry_generator_grammar.hpp
+++ b/include/mapnik/json/geometry_generator_grammar.hpp
@@ -27,12 +27,12 @@
 #include <mapnik/global.hpp>
 #include <mapnik/geometry.hpp>
 #include <mapnik/geometry_type.hpp>
-#include <mapnik/geometry_fusion_adapted.hpp>
 // boost
 #pragma GCC diagnostic push
 #include <mapnik/warning_ignore.hpp>
 #include <boost/spirit/include/karma.hpp>
 #include <boost/spirit/include/phoenix_function.hpp>
+#include <boost/fusion/adapted/std_tuple.hpp>
 #include <boost/math/special_functions/trunc.hpp> // for vc++ and android whose c++11 libs lack std::trunc
 #include <boost/spirit/home/karma/domain.hpp>
 #pragma GCC diagnostic pop
diff --git a/include/mapnik/json/geometry_generator_grammar_impl.hpp b/include/mapnik/json/geometry_generator_grammar_impl.hpp
index 62d6a85..87a60db 100644
--- a/include/mapnik/json/geometry_generator_grammar_impl.hpp
+++ b/include/mapnik/json/geometry_generator_grammar_impl.hpp
@@ -24,6 +24,7 @@
 #include <mapnik/json/geometry_generator_grammar.hpp>
 #include <mapnik/util/spirit_transform_attribute.hpp>
 #include <mapnik/geometry_types.hpp>
+#include <mapnik/geometry_fusion_adapted.hpp>
 
 // boost
 #pragma GCC diagnostic push
diff --git a/include/mapnik/json/geometry_grammar.hpp b/include/mapnik/json/geometry_grammar.hpp
index 800a48b..4b0d119 100644
--- a/include/mapnik/json/geometry_grammar.hpp
+++ b/include/mapnik/json/geometry_grammar.hpp
@@ -30,9 +30,11 @@
 #include <mapnik/json/positions_grammar.hpp>
 #include <mapnik/json/geometry_util.hpp>
 
-// spirit::qi
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/spirit/include/qi.hpp>
 #include <boost/spirit/include/phoenix_function.hpp>
+#pragma GCC diagnostic pop
 
 namespace mapnik { namespace json {
 
diff --git a/include/mapnik/json/geometry_grammar_impl.hpp b/include/mapnik/json/geometry_grammar_impl.hpp
index 90f09bf..3c5693f 100644
--- a/include/mapnik/json/geometry_grammar_impl.hpp
+++ b/include/mapnik/json/geometry_grammar_impl.hpp
@@ -24,12 +24,10 @@
 #include <mapnik/config.hpp>
 #include <mapnik/json/error_handler.hpp>
 #include <mapnik/json/geometry_grammar.hpp>
-#include <mapnik/json/positions_grammar_impl.hpp>
-
+#include <mapnik/geometry_fusion_adapted.hpp>
 // boost
-#include <boost/spirit/include/phoenix_object.hpp>
 #include <boost/spirit/include/phoenix_stl.hpp>
-#include <boost/spirit/include/phoenix_operator.hpp>
+#include <boost/spirit/include/phoenix_function.hpp>
 
 namespace mapnik { namespace json {
 
diff --git a/include/mapnik/json/geometry_parser.hpp b/include/mapnik/json/geometry_parser.hpp
index c83901d..761c193 100644
--- a/include/mapnik/json/geometry_parser.hpp
+++ b/include/mapnik/json/geometry_parser.hpp
@@ -24,25 +24,13 @@
 #define MAPNIK_JSON_GEOMETRY_PARSER_HPP
 
 // mapnik
+#include <mapnik/geometry.hpp>
 
-
-#include <mapnik/json/geometry_grammar.hpp>
-
-// boost
-#include <boost/spirit/include/qi.hpp>
-#include <boost/spirit/include/phoenix_core.hpp>
+#include <string>
 
 namespace mapnik { namespace json {
 
-inline bool from_geojson(std::string const& json, mapnik::geometry::geometry<double> & geom)
-{
-    using namespace boost::spirit;
-    static const geometry_grammar<char const*> g;
-    standard::space_type space;
-    char const* start = json.c_str();
-    char const* end = start + json.length();
-    return qi::phrase_parse(start, end, g, space, geom);
-}
+bool from_geojson(std::string const& json, mapnik::geometry::geometry<double> & geom);
 
 }}
 
diff --git a/include/mapnik/json/geometry_util.hpp b/include/mapnik/json/geometry_util.hpp
index 6e8fb67..cf538ae 100644
--- a/include/mapnik/json/geometry_util.hpp
+++ b/include/mapnik/json/geometry_util.hpp
@@ -25,6 +25,7 @@
 
 #include <mapnik/geometry.hpp>
 #include <mapnik/geometry_correct.hpp>
+#include <mapnik/json/positions.hpp>
 
 namespace mapnik { namespace json {
 
diff --git a/include/mapnik/agg_rasterizer.hpp b/include/mapnik/json/positions.hpp
similarity index 69%
copy from include/mapnik/agg_rasterizer.hpp
copy to include/mapnik/json/positions.hpp
index 51cf4cd..9ad10f9 100644
--- a/include/mapnik/agg_rasterizer.hpp
+++ b/include/mapnik/json/positions.hpp
@@ -20,19 +20,21 @@
  *
  *****************************************************************************/
 
-#ifndef MAPNIK_AGG_RASTERIZER_HPP
-#define MAPNIK_AGG_RASTERIZER_HPP
+#ifndef MAPNIK_JSON_POSITIONS_HPP
+#define MAPNIK_JSON_POSITIONS_HPP
 
 // mapnik
-#include <mapnik/util/noncopyable.hpp>
+#include <mapnik/util/variant.hpp>
+#include <mapnik/geometry.hpp>
 
-// agg
-#include "agg_rasterizer_scanline_aa.h"
+namespace mapnik { namespace json {
 
-namespace mapnik {
+struct empty {};
 
-struct rasterizer :  agg::rasterizer_scanline_aa<agg::rasterizer_sl_clip_int_sat>, util::noncopyable {};
+using position = mapnik::geometry::point<double>;
+using positions = std::vector<position>;
+using coordinates = util::variant<empty, position, positions, std::vector<positions>, std::vector<std::vector<positions> > > ;
 
-}
+}}
 
-#endif // MAPNIK_AGG_RASTERIZER_HPP
+#endif // MAPNIK_JSON_POSITIONS_HPP
diff --git a/include/mapnik/json/positions_grammar.hpp b/include/mapnik/json/positions_grammar.hpp
index 1535422..bc81046 100644
--- a/include/mapnik/json/positions_grammar.hpp
+++ b/include/mapnik/json/positions_grammar.hpp
@@ -25,29 +25,19 @@
 
 // mapnik
 #include <mapnik/util/variant.hpp>
+#include <mapnik/json/positions.hpp>
 #include <mapnik/json/generic_json.hpp>
 #include <mapnik/json/error_handler.hpp>
 #include <mapnik/geometry.hpp>
-#include <mapnik/geometry_fusion_adapted.hpp>
-
 #pragma GCC diagnostic push
 #include <mapnik/warning_ignore.hpp>
 #include <boost/spirit/include/qi.hpp>
 #include <boost/spirit/include/phoenix_function.hpp>
-#include <boost/fusion/adapted/std_tuple.hpp>
 #pragma GCC diagnostic pop
 
-// stl
-#include <tuple>
 
 namespace mapnik { namespace json {
 
-struct empty {};
-
-using position = mapnik::geometry::point<double>;
-using positions = std::vector<position>;
-using coordinates = util::variant<empty, position, positions, std::vector<positions>, std::vector<std::vector<positions> > > ;
-
 namespace qi = boost::spirit::qi;
 
 struct set_position_impl
diff --git a/include/mapnik/json/positions_grammar_impl.hpp b/include/mapnik/json/positions_grammar_impl.hpp
index 1347675..90df172 100644
--- a/include/mapnik/json/positions_grammar_impl.hpp
+++ b/include/mapnik/json/positions_grammar_impl.hpp
@@ -22,7 +22,7 @@
 
 // mapnik
 #include <mapnik/json/positions_grammar.hpp>
-
+#include <mapnik/geometry_fusion_adapted.hpp>
 // boost
 #include <boost/spirit/include/qi_omit.hpp>
 #include <boost/spirit/include/phoenix_object.hpp>
diff --git a/include/mapnik/json/properties_generator_grammar.hpp b/include/mapnik/json/properties_generator_grammar.hpp
index e0f7be6..69145b8 100644
--- a/include/mapnik/json/properties_generator_grammar.hpp
+++ b/include/mapnik/json/properties_generator_grammar.hpp
@@ -25,23 +25,20 @@
 
 #include <mapnik/value_types.hpp>
 #include <mapnik/value.hpp>
-#include <mapnik/feature_kv_iterator.hpp>
 
 #pragma GCC diagnostic push
 #include <mapnik/warning_ignore.hpp>
 #include <boost/spirit/include/karma.hpp>
-#include <boost/spirit/include/phoenix.hpp>
 #include <boost/spirit/include/phoenix_function.hpp>
-#include <boost/spirit/include/phoenix_fusion.hpp>
-#include <boost/spirit/include/phoenix_core.hpp>
-#include <boost/spirit/include/phoenix_operator.hpp>
-#include <boost/fusion/adapted/std_tuple.hpp>
-#include <boost/fusion/include/at.hpp>
-#include <boost/fusion/include/cons.hpp>
 #pragma GCC diagnostic pop
 
+#include <string>
+#include <tuple>
+
 namespace mapnik { namespace json {
 
+namespace karma = boost::spirit::karma;
+
 template <typename OutputIterator>
 struct escaped_string
     : karma::grammar<OutputIterator, std::string(char const*)>
diff --git a/include/mapnik/json/symbolizer_grammar.hpp b/include/mapnik/json/symbolizer_grammar.hpp
deleted file mode 100644
index 494b81f..0000000
--- a/include/mapnik/json/symbolizer_grammar.hpp
+++ /dev/null
@@ -1,216 +0,0 @@
-/*****************************************************************************
- *
- * This file is part of Mapnik (c++ mapping toolkit)
- *
- * Copyright (C) 2015 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_SYMBOLIZER_GRAMMAR_HPP
-#define MAPNIK_SYMBOLIZER_GRAMMAR_HPP
-
-#include <mapnik/config.hpp>
-
-// boost
-#include <boost/spirit/include/qi.hpp>
-#include <boost/spirit/include/phoenix.hpp>
-
-// mapnik
-#include <mapnik/util/variant.hpp>
-#include <mapnik/symbolizer.hpp>
-#include <mapnik/symbolizer_utils.hpp>
-#include <mapnik/json/error_handler.hpp>
-#include <mapnik/json/generic_json.hpp>
-
-namespace mapnik { namespace json {
-
-namespace qi = boost::spirit::qi;
-namespace phoenix = boost::phoenix;
-namespace fusion = boost::fusion;
-namespace standard_wide =  boost::spirit::standard_wide;
-using standard_wide::space_type;
-
-template <typename Symbolizer>
-struct json_value_visitor
-{
-    json_value_visitor(Symbolizer & sym, mapnik::keys key)
-        : sym_(sym), key_(key) {}
-
-    void operator() (value_bool val) const
-    {
-        put<value_bool>(sym_, key_, val);
-    }
-
-    void operator() (value_integer val) const
-    {
-        put<value_integer>(sym_, key_, val);
-    }
-
-    void operator() (value_double val) const
-    {
-        put<value_double>(sym_, key_, val);
-    }
-
-    void operator() (std::string const& val) const
-    {
-        set_property(sym_, key_, val);
-    }
-
-    template <typename T>
-    void operator() (T const& val) const
-    {
-        std::cerr << std::get<0>(get_meta(key_)) << ":" << val <<  std::endl;
-        //put<T>(sym_, key_, val);
-    }
-
-    Symbolizer & sym_;
-    keys key_;
-};
-
-template <typename T>
-struct put_property_visitor
-{
-    using value_type = T;
-
-    put_property_visitor(mapnik::keys key, value_type const& val)
-        : key_(key), val_(val) {}
-
-    template <typename Symbolizer>
-    void operator() (Symbolizer & sym) const
-    {
-        mapnik::util::apply_visitor(json_value_visitor<Symbolizer>(sym, key_), val_);
-    }
-
-    keys key_;
-    value_type const& val_;
-};
-
-struct put_property
-{
-    using result_type = void;
-    template <typename T0,typename T1, typename T2>
-    result_type operator() (T0 & sym, T1 const& name, T2 const& val) const
-    {
-        try
-        {
-            mapnik::util::apply_visitor(put_property_visitor<T2>(get_key(name),val), sym);
-        }
-        catch (std::runtime_error const& err)
-        {
-            std::cerr <<  err.what() << std::endl;
-        }
-    }
-};
-
-template <typename Iterator, typename ErrorHandler = error_handler<Iterator>>
-struct symbolizer_grammar : qi::grammar<Iterator, space_type, symbolizer()>
-{
-    using json_value_type = util::variant<value_null,value_bool,value_integer,value_double, std::string>;
-    symbolizer_grammar()
-        : symbolizer_grammar::base_type(sym, "symbolizer"),
-          json_()
-    {
-        qi::lit_type lit;
-        qi::double_type double_;
-        qi::int_type int_;
-        qi::no_skip_type no_skip;
-        qi::_val_type _val;
-        qi::_a_type _a;
-        qi::_r1_type _r1;
-        qi::_1_type _1;
-        standard_wide::char_type char_;
-        using phoenix::construct;
-
-        // generic json types
-        json_.value =  json_.object | json_.array | json_.string_
-            | json_.number
-            ;
-
-        json_.pairs = json_.key_value % lit(',')
-            ;
-
-        json_.key_value = (json_.string_ >> lit(':') >> json_.value)
-            ;
-
-        json_.object = lit('{')
-            >> *json_.pairs
-            >> lit('}')
-            ;
-
-        json_.array = lit('[')
-            >> json_.value >> *(lit(',') >> json_.value)
-            >> lit(']')
-        ;
-
-        json_.number %= json_.strict_double
-            | json_.int__
-            | lit("true") [_val = true]
-            | lit ("false") [_val = false]
-            | lit("null")[_val = construct<value_null>()]
-            ;
-        json_.unesc_char.add
-            ("\\\"", '\"') // quotation mark
-            ("\\\\", '\\') // reverse solidus
-            ("\\/", '/')   // solidus
-            ("\\b", '\b')  // backspace
-            ("\\f", '\f')  // formfeed
-            ("\\n", '\n')  // newline
-            ("\\r", '\r')  // carrige return
-            ("\\t", '\t')  // tab
-        ;
-
-        json_.string_ %= lit('"') >> no_skip[*(json_.unesc_char | "\\u" >> json_.hex4 | (char_ - lit('"')))] >> lit('"')
-            ;
-
-        sym = lit('{')
-            >> lit("\"type\"") >> lit(':')
-            >> (lit("\"PointSymbolizer\"")[_val = construct<point_symbolizer>()]
-                |
-                lit("\"LineSymbolizer\"")[_val = construct<line_symbolizer>()]
-                |
-                lit("\"PolygonSymbolizer\"")[_val = construct<polygon_symbolizer>()]
-                )
-            >> lit(',')
-            >> lit("\"properties\"") >> lit(':')
-            >> ((lit('{') >> *property(_val) >> lit('}')) | lit("null"))
-            >> lit('}')
-            ;
-
-        property = (json_.string_ [_a = _1] >> lit(':') >> property_value [put_property_(_r1,_a,_1)]) % lit(',')
-            ;
-
-        property_value %= json_.number | json_.string_  ;
-
-
-    }
-
-    // generic JSON
-    generic_json<Iterator> json_;
-    // symbolizer
-    qi::rule<Iterator, space_type, mapnik::symbolizer()> sym;
-    qi::rule<Iterator,qi::locals<std::string>, void(mapnik::symbolizer&),space_type> property;
-    qi::rule<Iterator, space_type, json_value_type()> property_value;
-
-    phoenix::function<put_property> put_property_;
-    // error
-    //qi::on_error<qi::fail>(sym, error_handler(_1, _2, _3, _4));
-};
-
-
-}}
-
-#endif // MAPNIK_SYMBOLIZER_GRAMMAR_HPP
diff --git a/include/mapnik/json/topojson_grammar.hpp b/include/mapnik/json/topojson_grammar.hpp
index be64b91..eec2bb4 100644
--- a/include/mapnik/json/topojson_grammar.hpp
+++ b/include/mapnik/json/topojson_grammar.hpp
@@ -25,14 +25,12 @@
 
 // mapnik
 #include <mapnik/json/error_handler.hpp>
-#include <mapnik/json/generic_json.hpp>
 #include <mapnik/json/topology.hpp>
 #include <mapnik/json/value_converters.hpp>
 
 #pragma GCC diagnostic push
 #include <mapnik/warning_ignore.hpp>
 #include <boost/spirit/include/qi.hpp>
-#include <boost/spirit/include/phoenix_function.hpp>
 #pragma GCC diagnostic pop
 
 // stl
@@ -51,7 +49,7 @@ struct topojson_grammar : qi::grammar<Iterator, space_type, topology()>
     topojson_grammar();
 private:
     // generic JSON support
-    json::generic_json<Iterator> json_;
+    json::generic_json<Iterator> json;
     // topoJSON
     qi::rule<Iterator, space_type, mapnik::topojson::topology()> topology;
     qi::rule<Iterator, space_type, std::vector<mapnik::topojson::geometry>()> objects;
@@ -68,17 +66,13 @@ private:
     qi::rule<Iterator, space_type, mapnik::topojson::polygon()> polygon;
     qi::rule<Iterator, space_type, mapnik::topojson::multi_polygon()> multi_polygon;
     qi::rule<Iterator, space_type, void(std::vector<mapnik::topojson::geometry>&)> geometry_collection;
-
     qi::rule<Iterator, space_type, std::vector<index_type>()> ring;
-
     // properties
     qi::rule<Iterator, space_type, mapnik::topojson::properties()> properties;
     qi::rule<Iterator, space_type, mapnik::topojson::properties()> attributes;
     qi::rule<Iterator, space_type, mapnik::json::json_value()> attribute_value;
     // id
     qi::rule<Iterator,space_type> id;
-    // error handler
-    boost::phoenix::function<ErrorHandler> const error_handler;
 };
 
 }}
diff --git a/include/mapnik/json/topojson_grammar_impl.hpp b/include/mapnik/json/topojson_grammar_impl.hpp
index 90e3f1a..ca86079 100644
--- a/include/mapnik/json/topojson_grammar_impl.hpp
+++ b/include/mapnik/json/topojson_grammar_impl.hpp
@@ -21,6 +21,85 @@
  *****************************************************************************/
 
 #include <mapnik/json/topojson_grammar.hpp>
+#include <mapnik/json/generic_json.hpp>
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
+#include <boost/fusion/include/adapt_struct.hpp>
+#include <boost/fusion/adapted/std_tuple.hpp>
+#include <boost/spirit/include/phoenix_function.hpp>
+#pragma GCC diagnostic pop
+
+BOOST_FUSION_ADAPT_STRUCT(
+    mapnik::topojson::coordinate,
+    (double, x)
+    (double, y)
+    )
+
+BOOST_FUSION_ADAPT_STRUCT(
+    mapnik::topojson::arc,
+    (std::list<mapnik::topojson::coordinate>, coordinates)
+    )
+
+BOOST_FUSION_ADAPT_STRUCT(
+    mapnik::topojson::transform,
+    (double, scale_x)
+    (double, scale_y)
+    (double, translate_x)
+    (double, translate_y)
+    )
+
+BOOST_FUSION_ADAPT_STRUCT(
+    mapnik::topojson::bounding_box,
+    (double, minx)
+    (double, miny)
+    (double, maxx)
+    (double, maxy)
+    )
+
+BOOST_FUSION_ADAPT_STRUCT(
+    mapnik::topojson::point,
+    (mapnik::topojson::coordinate, coord)
+    (boost::optional<mapnik::topojson::properties>, props)
+    )
+
+BOOST_FUSION_ADAPT_STRUCT(
+    mapnik::topojson::multi_point,
+    (std::vector<mapnik::topojson::coordinate>, points)
+    (boost::optional<mapnik::topojson::properties>, props)
+    )
+
+BOOST_FUSION_ADAPT_STRUCT(
+    mapnik::topojson::linestring,
+    (mapnik::topojson::index_type, ring)
+    (boost::optional<mapnik::topojson::properties>, props)
+    )
+
+BOOST_FUSION_ADAPT_STRUCT(
+    mapnik::topojson::multi_linestring,
+    (std::vector<mapnik::topojson::index_type>, rings)
+    (boost::optional<mapnik::topojson::properties>, props)
+    )
+
+BOOST_FUSION_ADAPT_STRUCT(
+    mapnik::topojson::polygon,
+    (std::vector<std::vector<mapnik::topojson::index_type> >, rings)
+    (boost::optional<mapnik::topojson::properties>, props)
+    )
+
+BOOST_FUSION_ADAPT_STRUCT(
+    mapnik::topojson::multi_polygon,
+    (std::vector<std::vector<std::vector<mapnik::topojson::index_type> > >, polygons)
+    (boost::optional<mapnik::topojson::properties>, props)
+    )
+
+BOOST_FUSION_ADAPT_STRUCT(
+    mapnik::topojson::topology,
+    (std::vector<mapnik::topojson::geometry>, geometries)
+    (std::vector<mapnik::topojson::arc>, arcs)
+    (boost::optional<mapnik::topojson::transform>, tr)
+    (boost::optional<mapnik::topojson::bounding_box>, bbox)
+   )
 
 namespace mapnik { namespace topojson {
 
@@ -46,26 +125,30 @@ topojson_grammar<Iterator, ErrorHandler>::topojson_grammar()
     using qi::on_error;
     using phoenix::push_back;
     using phoenix::construct;
-    // generic json types
-    json_.value = json_.object | json_.array | json_.string_ | json_.number
+
+    // error handler
+    boost::phoenix::function<ErrorHandler> const error_handler;
+
+    // generic JSON types
+    json.value = json.object | json.array | json.string_ | json.number
         ;
 
-    json_.pairs = json_.key_value % lit(',')
+    json.pairs = json.key_value % lit(',')
         ;
 
-    json_.key_value = (json_.string_ >> lit(':') >> json_.value)
+    json.key_value = (json.string_ >> lit(':') >> json.value)
         ;
 
-    json_.object = lit('{') >> *json_.pairs >> lit('}')
+    json.object = lit('{') >> *json.pairs >> lit('}')
         ;
 
-    json_.array = lit('[')
-        >> json_.value >> *(lit(',') >> json_.value)
+    json.array = lit('[')
+        >> json.value >> *(lit(',') >> json.value)
         >> lit(']')
         ;
 
-    json_.number = json_.strict_double[_val = json_.double_converter(_1)]
-        | json_.int__[_val = json_.integer_converter(_1)]
+    json.number = json.strict_double[_val = json.double_converter(_1)]
+        | json.int__[_val = json.integer_converter(_1)]
         | lit("true")[_val = true]
         | lit("false")[_val = false]
         | lit("null")[_val = construct<value_null>()]
@@ -96,7 +179,7 @@ topojson_grammar<Iterator, ErrorHandler>::topojson_grammar()
     objects = lit("\"objects\"")
         >> lit(':')
         >> lit('{')
-        >> -((omit[json_.string_]
+        >> -((omit[json.string_]
               >> lit(':')
               >>  (geometry_collection(_val) | geometry)) % lit(','))
         >> lit('}')
@@ -109,7 +192,7 @@ topojson_grammar<Iterator, ErrorHandler>::topojson_grammar()
         multi_point |
         multi_linestring |
         multi_polygon |
-        omit[json_.object]
+        omit[json.object]
         ;
 
     geometry_collection =  lit('{')
@@ -171,7 +254,7 @@ topojson_grammar<Iterator, ErrorHandler>::topojson_grammar()
         >> lit('}')
         ;
 
-    id = lit("\"id\"") >> lit(':') >> omit[json_.value]
+    id = lit("\"id\"") >> lit(':') >> omit[json.value]
         ;
 
     ring = lit('[') >> -(int_ % lit(',')) >> lit(']')
@@ -179,13 +262,13 @@ topojson_grammar<Iterator, ErrorHandler>::topojson_grammar()
 
     properties = lit("\"properties\"")
         >> lit(':')
-        >> (( lit('{') >> attributes >> lit('}')) | json_.object)
+        >> (( lit('{') >> attributes >> lit('}')) | json.object)
         ;
 
-    attributes = (json_.string_ >> lit(':') >> attribute_value) % lit(',')
+    attributes = (json.string_ >> lit(':') >> attribute_value) % lit(',')
         ;
 
-    attribute_value %= json_.number | json_.string_  ;
+    attribute_value %= json.number | json.string_  ;
 
     arcs = lit("\"arcs\"") >> lit(':')
                            >> lit('[') >> -( arc % lit(',')) >> lit(']') ;
@@ -199,7 +282,7 @@ topojson_grammar<Iterator, ErrorHandler>::topojson_grammar()
     objects.name("objects");
     arc.name("arc");
     arcs.name("arcs");
-    json_.value.name("value");
+    json.value.name("value");
     coordinate.name("coordinate");
 
     point.name("point");
diff --git a/include/mapnik/json/topojson_utils.hpp b/include/mapnik/json/topojson_utils.hpp
index be6a83a..c4de306 100644
--- a/include/mapnik/json/topojson_utils.hpp
+++ b/include/mapnik/json/topojson_utils.hpp
@@ -25,7 +25,11 @@
 
 // mapnik
 #include <mapnik/box2d.hpp>
+#include <mapnik/unicode.hpp>
 #include <mapnik/json/topology.hpp>
+#include <mapnik/feature_factory.hpp>
+#include <mapnik/geometry_adapters.hpp>
+#include <mapnik/geometry_correct.hpp>
 
 namespace mapnik { namespace topojson {
 
@@ -50,27 +54,25 @@ struct bounding_box_visitor
     box2d<double> operator() (mapnik::topojson::multi_point const& multi_pt) const
     {
         box2d<double> bbox;
-        if (num_arcs_ > 0)
+        bool first = true;
+        double px = 0, py = 0;
+        for (auto const& pt : multi_pt.points)
         {
-            bool first = true;
-            for (auto const& pt : multi_pt.points)
+            double x = pt.x;
+            double y = pt.y;
+            if (topo_.tr)
             {
-                double x = pt.x;
-                double y = pt.y;
-                if (topo_.tr)
-                {
-                    x =  x * (*topo_.tr).scale_x + (*topo_.tr).translate_x;
-                    y =  y * (*topo_.tr).scale_y + (*topo_.tr).translate_y; // TODO : delta encoded ?
-                }
-                if (first)
-                {
-                    first = false;
-                    bbox.init(x,y,x,y);
-                }
-                else
-                {
-                    bbox.expand_to_include(x,y);
-                }
+                x = (px += x) * (*topo_.tr).scale_x + (*topo_.tr).translate_x;
+                y = (py += y) * (*topo_.tr).scale_y + (*topo_.tr).translate_y;
+            }
+            if (first)
+            {
+                first = false;
+                bbox.init(x,y,x,y);
+            }
+            else
+            {
+                bbox.expand_to_include(x,y);
             }
         }
         return bbox;
@@ -243,6 +245,334 @@ private:
     std::size_t num_arcs_;
 };
 
+namespace {
+struct attribute_value_visitor
+
+{
+public:
+    attribute_value_visitor(mapnik::transcoder const& tr)
+        : tr_(tr) {}
+
+    mapnik::value operator()(std::string const& val) const
+    {
+        return mapnik::value(tr_.transcode(val.c_str()));
+    }
+
+    template <typename T>
+    mapnik::value operator()(T const& val) const
+    {
+        return mapnik::value(val);
+    }
+
+    mapnik::transcoder const& tr_;
+};
+
+template <typename T>
+void assign_properties(mapnik::feature_impl & feature, T const& geom, mapnik::transcoder const& tr)
+{
+    if ( geom.props)
+    {
+        for (auto const& p : *geom.props)
+        {
+            feature.put_new(std::get<0>(p), mapnik::util::apply_visitor(attribute_value_visitor(tr),std::get<1>(p)));
+        }
+    }
+}
+
+}
+
+template <typename Context>
+struct feature_generator
+{
+    feature_generator(Context & ctx,  mapnik::transcoder const& tr, topology const& topo, std::size_t feature_id)
+        : ctx_(ctx),
+          tr_(tr),
+          topo_(topo),
+          num_arcs_(topo.arcs.size()),
+          feature_id_(feature_id) {}
+
+    feature_ptr operator() (point const& pt) const
+    {
+        mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_,feature_id_));
+        double x = pt.coord.x;
+        double y = pt.coord.y;
+        if (topo_.tr)
+        {
+            x =  x * (*topo_.tr).scale_x + (*topo_.tr).translate_x;
+            y =  y * (*topo_.tr).scale_y + (*topo_.tr).translate_y;
+        }
+        mapnik::geometry::point<double> point(x, y);
+        feature->set_geometry(std::move(point));
+        assign_properties(*feature, pt, tr_);
+        return feature;
+    }
+
+    feature_ptr operator() (multi_point const& multi_pt) const
+    {
+        mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_,feature_id_));
+        mapnik::geometry::multi_point<double> multi_point;
+        multi_point.reserve(multi_pt.points.size());
+        for (auto const& pt : multi_pt.points)
+        {
+            double x = pt.x;
+            double y = pt.y;
+            if (topo_.tr)
+            {
+                x =  x * (*topo_.tr).scale_x + (*topo_.tr).translate_x;
+                y =  y * (*topo_.tr).scale_y + (*topo_.tr).translate_y;
+            }
+            multi_point.add_coord(x, y);
+        }
+        feature->set_geometry(std::move(multi_point));
+        assign_properties(*feature, multi_pt, tr_);
+        return feature;
+    }
+
+    feature_ptr operator() (linestring const& line) const
+    {
+        mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_,feature_id_));
+        if (num_arcs_ > 0)
+        {
+            index_type index = line.ring;
+            index_type arc_index = index < 0 ? std::abs(index) - 1 : index;
+            if (arc_index >= 0 && arc_index < static_cast<int>(num_arcs_))
+            {
+                auto const& arcs = topo_.arcs[arc_index];
+                double px = 0, py = 0;
+                mapnik::geometry::line_string<double> line_string;
+                line_string.reserve(arcs.coordinates.size());
+
+                for (auto pt : arcs.coordinates)
+                {
+                    double x = pt.x;
+                    double y = pt.y;
+                    if (topo_.tr)
+                    {
+                        x =  (px += x) * (*topo_.tr).scale_x + (*topo_.tr).translate_x;
+                        y =  (py += y) * (*topo_.tr).scale_y + (*topo_.tr).translate_y;
+                    }
+                    line_string.add_coord(x,y);
+                }
+                feature->set_geometry(std::move(line_string));
+                assign_properties(*feature, line, tr_);
+            }
+        }
+        return feature;
+    }
+
+    feature_ptr operator() (multi_linestring const& multi_line) const
+    {
+        mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_,feature_id_));
+        if (num_arcs_ > 0)
+        {
+            mapnik::geometry::multi_line_string<double> multi_line_string;
+            bool hit = false;
+            multi_line_string.reserve(multi_line.rings.size());
+            for (auto const& index : multi_line.rings)
+            {
+                index_type arc_index = index < 0 ? std::abs(index) - 1 : index;
+                if (arc_index >= 0 && arc_index < static_cast<int>(num_arcs_))
+                {
+                    hit = true;
+                    double px = 0, py = 0;
+                    mapnik::geometry::line_string<double> line_string;
+                    auto const& arcs = topo_.arcs[arc_index];
+                    line_string.reserve(arcs.coordinates.size());
+                    for (auto pt : arcs.coordinates)
+                    {
+                        double x = pt.x;
+                        double y = pt.y;
+                        if (topo_.tr)
+                        {
+                            x =  (px += x) * (*topo_.tr).scale_x + (*topo_.tr).translate_x;
+                            y =  (py += y) * (*topo_.tr).scale_y + (*topo_.tr).translate_y;
+                        }
+                        line_string.add_coord(x, y);
+                    }
+                    multi_line_string.push_back(std::move(line_string));
+                }
+            }
+            if (hit)
+            {
+                feature->set_geometry(std::move(multi_line_string));
+                assign_properties(*feature, multi_line, tr_);
+            }
+        }
+        return feature;
+    }
+
+    feature_ptr operator() (polygon const& poly) const
+    {
+        mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_,feature_id_));
+        if (num_arcs_ > 0)
+        {
+            std::vector<mapnik::topojson::coordinate> processed_coords;
+            mapnik::geometry::polygon<double> polygon;
+            if (poly.rings.size() > 1) polygon.interior_rings.reserve(poly.rings.size() - 1);
+            bool first = true;
+            bool hit = false;
+            for (auto const& ring : poly.rings)
+            {
+                mapnik::geometry::linear_ring<double> linear_ring;
+                for (auto const& index : ring)
+                {
+                    double px = 0, py = 0;
+                    bool reverse = index < 0;
+                    index_type arc_index = reverse ? std::abs(index) - 1 : index;
+                    if (arc_index >= 0 && arc_index < static_cast<int>(num_arcs_))
+                    {
+                        hit = true;
+                        auto const& arcs = topo_.arcs[arc_index];
+                        auto const& coords = arcs.coordinates;
+                        processed_coords.clear();
+                        processed_coords.reserve(coords.size());
+                        for (auto const& pt : coords )
+                        {
+                            double x = pt.x;
+                            double y = pt.y;
+
+                            if (topo_.tr)
+                            {
+                                transform const& tr = *topo_.tr;
+                                x =  (px += x) * tr.scale_x + tr.translate_x;
+                                y =  (py += y) * tr.scale_y + tr.translate_y;
+                            }
+                            processed_coords.emplace_back(coordinate{x,y});
+                        }
+
+                        if (reverse)
+                        {
+                            for (auto const& c : processed_coords | boost::adaptors::reversed)
+                            {
+                                linear_ring.emplace_back(c.x, c.y);
+                            }
+                        }
+                        else
+                        {
+                            for (auto const& c : processed_coords)
+                            {
+                                linear_ring.emplace_back(c.x, c.y);
+                            }
+                        }
+                    }
+                }
+                if (first)
+                {
+                    first = false;
+                    polygon.set_exterior_ring(std::move(linear_ring));
+                }
+                else
+                {
+                    polygon.add_hole(std::move(linear_ring));
+                }
+            }
+            if (hit)
+            {
+                mapnik::geometry::correct(polygon);
+                feature->set_geometry(std::move(polygon));
+                assign_properties(*feature, poly, tr_);
+            }
+        }
+        return feature;
+    }
+
+    feature_ptr operator() (multi_polygon const& multi_poly) const
+    {
+        mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_,feature_id_));
+        if (num_arcs_ > 0)
+        {
+            std::vector<mapnik::topojson::coordinate> processed_coords;
+            mapnik::geometry::multi_polygon<double> multi_polygon;
+            multi_polygon.reserve(multi_poly.polygons.size());
+            bool hit = false;
+            for (auto const& poly : multi_poly.polygons)
+            {
+                bool first = true;
+                mapnik::geometry::polygon<double> polygon;
+                if (poly.size() > 1) polygon.interior_rings.reserve(poly.size() - 1);
+
+                for (auto const& ring : poly)
+                {
+                    mapnik::geometry::linear_ring<double> linear_ring;
+                    for (auto const& index : ring)
+                    {
+                        double px = 0, py = 0;
+                        bool reverse = index < 0;
+                        index_type arc_index = reverse ? std::abs(index) - 1 : index;
+                        if (arc_index >= 0 && arc_index < static_cast<int>(num_arcs_))
+                        {
+                            hit = true;
+                            auto const& arcs = topo_.arcs[arc_index];
+                            auto const& coords = arcs.coordinates;
+                            processed_coords.clear();
+                            processed_coords.reserve(coords.size());
+                            for (auto const& pt : coords )
+                            {
+                                double x = pt.x;
+                                double y = pt.y;
+
+                                if (topo_.tr)
+                                {
+                                    x =  (px += x) * (*topo_.tr).scale_x + (*topo_.tr).translate_x;
+                                    y =  (py += y) * (*topo_.tr).scale_y + (*topo_.tr).translate_y;
+                                }
+                                processed_coords.emplace_back(coordinate{x,y});
+                            }
+
+                            using namespace boost::adaptors;
+
+                            if (reverse)
+                            {
+                                for (auto const& c : (processed_coords | reversed))
+                                {
+                                    linear_ring.add_coord(c.x, c.y);
+                                }
+                            }
+                            else
+                            {
+                                for (auto const& c : processed_coords)
+                                {
+                                    linear_ring.add_coord(c.x, c.y);
+                                }
+                            }
+                        }
+                    }
+                    if (first)
+                    {
+                        first = false;
+                        polygon.set_exterior_ring(std::move(linear_ring));
+                    }
+                    else
+                    {
+                        polygon.add_hole(std::move(linear_ring));
+                    }
+                }
+                multi_polygon.push_back(std::move(polygon));
+            }
+            if (hit)
+            {
+                mapnik::geometry::correct(multi_polygon);
+                feature->set_geometry(std::move(multi_polygon));
+                assign_properties(*feature, multi_poly, tr_);
+            }
+        }
+        return feature;
+    }
+
+    template<typename T>
+    feature_ptr operator() (T const& ) const
+    {
+        return feature_ptr();
+    }
+
+    Context & ctx_;
+    mapnik::transcoder const& tr_;
+    topology const& topo_;
+    std::size_t num_arcs_;
+    std::size_t feature_id_;
+};
+
+
 }}
 
 #endif //MAPNIK_TOPOJSON_UTILS_HPP
diff --git a/include/mapnik/json/topology.hpp b/include/mapnik/json/topology.hpp
index b859cfc..05f35b4 100644
--- a/include/mapnik/json/topology.hpp
+++ b/include/mapnik/json/topology.hpp
@@ -28,8 +28,6 @@
 
 #pragma GCC diagnostic push
 #include <mapnik/warning_ignore.hpp>
-#include <boost/fusion/include/adapt_struct.hpp>
-#include <boost/fusion/adapted/std_tuple.hpp>
 #include <boost/optional.hpp>
 #pragma GCC diagnostic pop
 
@@ -126,75 +124,4 @@ struct topology
 
 }}
 
-BOOST_FUSION_ADAPT_STRUCT(
-    mapnik::topojson::coordinate,
-    (double, x)
-    (double, y)
-    )
-
-BOOST_FUSION_ADAPT_STRUCT(
-    mapnik::topojson::arc,
-    (std::list<mapnik::topojson::coordinate>, coordinates)
-    )
-
-BOOST_FUSION_ADAPT_STRUCT(
-    mapnik::topojson::transform,
-    (double, scale_x)
-    (double, scale_y)
-    (double, translate_x)
-    (double, translate_y)
-    )
-
-BOOST_FUSION_ADAPT_STRUCT(
-    mapnik::topojson::bounding_box,
-    (double, minx)
-    (double, miny)
-    (double, maxx)
-    (double, maxy)
-    )
-
-BOOST_FUSION_ADAPT_STRUCT(
-    mapnik::topojson::point,
-    (mapnik::topojson::coordinate, coord)
-    (boost::optional<mapnik::topojson::properties>, props)
-    )
-
-BOOST_FUSION_ADAPT_STRUCT(
-    mapnik::topojson::multi_point,
-    (std::vector<mapnik::topojson::coordinate>, points)
-    (boost::optional<mapnik::topojson::properties>, props)
-    )
-
-BOOST_FUSION_ADAPT_STRUCT(
-    mapnik::topojson::linestring,
-    (mapnik::topojson::index_type, ring)
-    (boost::optional<mapnik::topojson::properties>, props)
-    )
-
-BOOST_FUSION_ADAPT_STRUCT(
-    mapnik::topojson::multi_linestring,
-    (std::vector<mapnik::topojson::index_type>, rings)
-    (boost::optional<mapnik::topojson::properties>, props)
-    )
-
-BOOST_FUSION_ADAPT_STRUCT(
-    mapnik::topojson::polygon,
-    (std::vector<std::vector<mapnik::topojson::index_type> >, rings)
-    (boost::optional<mapnik::topojson::properties>, props)
-    )
-
-BOOST_FUSION_ADAPT_STRUCT(
-    mapnik::topojson::multi_polygon,
-    (std::vector<std::vector<std::vector<mapnik::topojson::index_type> > >, polygons)
-    (boost::optional<mapnik::topojson::properties>, props)
-    )
-
-BOOST_FUSION_ADAPT_STRUCT(
-    mapnik::topojson::topology,
-    (std::vector<mapnik::topojson::geometry>, geometries)
-    (std::vector<mapnik::topojson::arc>, arcs)
-    (boost::optional<mapnik::topojson::transform>, tr)
-    (boost::optional<mapnik::topojson::bounding_box>, bbox)
-   )
-
 #endif // MAPNIK_TOPOLOGY_HPP
diff --git a/include/mapnik/label_collision_detector.hpp b/include/mapnik/label_collision_detector.hpp
index 6846180..f751f31 100644
--- a/include/mapnik/label_collision_detector.hpp
+++ b/include/mapnik/label_collision_detector.hpp
@@ -28,8 +28,10 @@
 #include <mapnik/util/noncopyable.hpp>
 #include <mapnik/value_types.hpp>
 
-// icu
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <unicode/unistr.h>
+#pragma GCC diagnostic pop
 
 // stl
 #include <vector>
diff --git a/include/mapnik/map.hpp b/include/mapnik/map.hpp
index 23ea96a..9f58279 100644
--- a/include/mapnik/map.hpp
+++ b/include/mapnik/map.hpp
@@ -34,8 +34,10 @@
 #include <mapnik/image_compositing.hpp>
 #include <mapnik/font_engine_freetype.hpp>
 
-// boost
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/optional.hpp>
+#pragma GCC diagnostic pop
 
 // stl
 #include <map>
diff --git a/include/mapnik/mapped_memory_cache.hpp b/include/mapnik/mapped_memory_cache.hpp
index c67d63a..1ac8d87 100644
--- a/include/mapnik/mapped_memory_cache.hpp
+++ b/include/mapnik/mapped_memory_cache.hpp
@@ -31,7 +31,12 @@
 #include <memory>
 #include <string>
 #include <unordered_map>
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/optional.hpp>
+#pragma GCC diagnostic pop
+
 
 namespace boost { namespace interprocess { class mapped_region; } }
 
diff --git a/include/mapnik/marker.hpp b/include/mapnik/marker.hpp
index 8ba117e..1feb0fe 100644
--- a/include/mapnik/marker.hpp
+++ b/include/mapnik/marker.hpp
@@ -29,8 +29,10 @@
 #include <mapnik/svg/svg_path_adapter.hpp>
 #include <mapnik/util/variant.hpp>
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_array.h"
+#pragma GCC diagnostic pop
 
 // stl
 #include <memory>
diff --git a/include/mapnik/marker_helpers.hpp b/include/mapnik/marker_helpers.hpp
index 49c011a..8ba3c6f 100644
--- a/include/mapnik/marker_helpers.hpp
+++ b/include/mapnik/marker_helpers.hpp
@@ -36,9 +36,12 @@
 #include <mapnik/vertex_processor.hpp>
 #include <mapnik/renderer_common/apply_vertex_converter.hpp>
 #include <mapnik/renderer_common/render_markers_symbolizer.hpp>
+#include <mapnik/vertex_converters.hpp>
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_trans_affine.h"
+#pragma GCC diagnostic pop
 
 // stl
 #include <memory>
@@ -158,84 +161,29 @@ void setup_transform_scaling(agg::trans_affine & tr,
                              attributes const& vars,
                              symbolizer_base const& sym);
 
+using vertex_converter_type = vertex_converter<clip_line_tag,
+                                               clip_poly_tag,
+                                               transform_tag,
+                                               affine_transform_tag,
+                                               simplify_tag,
+                                               smooth_tag,
+                                               offset_transform_tag>;
+
 // Apply markers to a feature with multiple geometries
-template <typename Converter, typename Processor>
-void apply_markers_multi(feature_impl const& feature, attributes const& vars, Converter & converter, Processor & proc, symbolizer_base const& sym)
-{
-    using apply_vertex_converter_type = detail::apply_vertex_converter<Converter,Processor>;
-    using vertex_processor_type = geometry::vertex_processor<apply_vertex_converter_type>;
+template <typename Processor>
+void apply_markers_multi(feature_impl const& feature, attributes const& vars,
+                         vertex_converter_type & converter, Processor & proc, symbolizer_base const& sym);
 
-    auto const& geom = feature.get_geometry();
-    geometry::geometry_types type = geometry::geometry_type(geom);
 
-    if (type == geometry::geometry_types::Point
-        || type == geometry::geometry_types::LineString
-        || type == geometry::geometry_types::Polygon)
-    {
-        apply_vertex_converter_type apply(converter, proc);
-        mapnik::util::apply_visitor(vertex_processor_type(apply), geom);
-    }
-    else
-    {
+using vector_dispatch_type = vector_markers_dispatch<mapnik::label_collision_detector4>;
+using raster_dispatch_type = raster_markers_dispatch<mapnik::label_collision_detector4>;
 
-        marker_multi_policy_enum multi_policy = get<marker_multi_policy_enum, keys::markers_multipolicy>(sym, feature, vars);
-        marker_placement_enum placement = get<marker_placement_enum, keys::markers_placement_type>(sym, feature, vars);
+extern template void apply_markers_multi<vector_dispatch_type>(feature_impl const& feature, attributes const& vars,
+                         vertex_converter_type & converter, vector_dispatch_type & proc, symbolizer_base const& sym);
+
+extern template void apply_markers_multi<raster_dispatch_type>(feature_impl const& feature, attributes const& vars,
+                         vertex_converter_type & converter, raster_dispatch_type & proc, symbolizer_base const& sym);
 
-        if (placement == MARKER_POINT_PLACEMENT &&
-            multi_policy == MARKER_WHOLE_MULTI)
-        {
-            geometry::point<double> pt;
-            // test if centroid is contained by bounding box
-            if (geometry::centroid(geom, pt) && converter.disp_.args_.bbox.contains(pt.x, pt.y))
-            {
-                // unset any clipping since we're now dealing with a point
-                converter.template unset<clip_poly_tag>();
-                geometry::point_vertex_adapter<double> va(pt);
-                converter.apply(va, proc);
-            }
-        }
-        else if ((placement == MARKER_POINT_PLACEMENT || placement == MARKER_INTERIOR_PLACEMENT) &&
-                 multi_policy == MARKER_LARGEST_MULTI)
-        {
-            // Only apply to path with largest envelope area
-            // TODO: consider using true area for polygon types
-            if (type == geometry::geometry_types::MultiPolygon)
-            {
-                geometry::multi_polygon<double> const& multi_poly = mapnik::util::get<geometry::multi_polygon<double> >(geom);
-                double maxarea = 0;
-                geometry::polygon<double> const* largest = 0;
-                for (geometry::polygon<double> const& poly : multi_poly)
-                {
-                    box2d<double> bbox = geometry::envelope(poly);
-                    double area = bbox.width() * bbox.height();
-                    if (area > maxarea)
-                    {
-                        maxarea = area;
-                        largest = &poly;
-                    }
-                }
-                if (largest)
-                {
-                    geometry::polygon_vertex_adapter<double> va(*largest);
-                    converter.apply(va, proc);
-                }
-            }
-            else
-            {
-                MAPNIK_LOG_WARN(marker_symbolizer) << "TODO: if you get here -> open an issue";
-            }
-        }
-        else
-        {
-            if (multi_policy != MARKER_EACH_MULTI && placement != MARKER_POINT_PLACEMENT)
-            {
-                MAPNIK_LOG_WARN(marker_symbolizer) << "marker_multi_policy != 'each' has no effect with marker_placement != 'point'";
-            }
-            apply_vertex_converter_type apply(converter, proc);
-            mapnik::util::apply_visitor(vertex_processor_type(apply), geom);
-        }
-    }
-}
 
 }
 
diff --git a/include/mapnik/markers_placement.hpp b/include/mapnik/markers_placement.hpp
index 3e7e3e4..0d43191 100644
--- a/include/mapnik/markers_placement.hpp
+++ b/include/mapnik/markers_placement.hpp
@@ -29,7 +29,6 @@
 #include <mapnik/markers_placements/vertext_first.hpp>
 #include <mapnik/markers_placements/vertext_last.hpp>
 #include <mapnik/symbolizer_enumerations.hpp>
-#include <mapnik/util/variant.hpp>
 
 namespace mapnik
 {
@@ -38,70 +37,99 @@ template <typename Locator, typename Detector>
 class markers_placement_finder : util::noncopyable
 {
 public:
-    using markers_placement = util::variant<markers_point_placement<Locator, Detector>,
-                                            markers_line_placement<Locator, Detector>,
-                                            markers_interior_placement<Locator, Detector>,
-                                            markers_vertex_first_placement<Locator, Detector>,
-                                            markers_vertex_last_placement<Locator, Detector>>;
-
-    class get_point_visitor
-    {
-    public:
-        get_point_visitor(double &x, double &y, double &angle, bool ignore_placement)
-            : x_(x), y_(y), angle_(angle), ignore_placement_(ignore_placement)
-        {
-        }
-
-        template <typename T>
-        bool operator()(T &placement) const
-        {
-            return placement.get_point(x_, y_, angle_, ignore_placement_);
-        }
-
-    private:
-        double &x_, &y_, &angle_;
-        bool ignore_placement_;
-    };
-
     markers_placement_finder(marker_placement_e placement_type,
                              Locator &locator,
                              Detector &detector,
                              markers_placement_params const& params)
-        : placement_(create(placement_type, locator, detector, params))
+        : placement_type_(placement_type)
     {
+        switch (placement_type)
+        {
+        default:
+        case MARKER_POINT_PLACEMENT:
+            construct(&point_, locator, detector, params);
+            break;
+        case MARKER_INTERIOR_PLACEMENT:
+            construct(&interior_, locator, detector, params);
+            break;
+        case MARKER_LINE_PLACEMENT:
+            construct(&line_, locator, detector, params);
+            break;
+        case MARKER_VERTEX_FIRST_PLACEMENT:
+            construct(&vertex_first_, locator, detector, params);
+            break;
+        case MARKER_VERTEX_LAST_PLACEMENT:
+            construct(&vertex_last_, locator, detector, params);
+            break;
+        }
     }
 
-    // Get next point where the marker should be placed. Returns true if a place is found, false if none is found.
-    bool get_point(double &x, double &y, double &angle, bool ignore_placement)
+    ~markers_placement_finder()
     {
-        return util::apply_visitor(get_point_visitor(x, y, angle, ignore_placement), placement_);
+        switch (placement_type_)
+        {
+        default:
+        case MARKER_POINT_PLACEMENT:
+            destroy(&point_);
+            break;
+        case MARKER_INTERIOR_PLACEMENT:
+            destroy(&interior_);
+            break;
+        case MARKER_LINE_PLACEMENT:
+            destroy(&line_);
+            break;
+        case MARKER_VERTEX_FIRST_PLACEMENT:
+            destroy(&vertex_first_);
+            break;
+        case MARKER_VERTEX_LAST_PLACEMENT:
+            destroy(&vertex_last_);
+            break;
+        }
     }
 
-private:
-    // Factory function for particular placement implementations.
-    static markers_placement create(marker_placement_e placement_type,
-                                    Locator &locator,
-                                    Detector &detector,
-                                    markers_placement_params const& params)
+    // Get next point where the marker should be placed. Returns true if a place is found, false if none is found.
+    bool get_point(double &x, double &y, double &angle, bool ignore_placement)
     {
-        switch (placement_type)
+        switch (placement_type_)
         {
+        default:
         case MARKER_POINT_PLACEMENT:
-            return markers_point_placement<Locator, Detector>(locator,detector,params);
+            return point_.get_point(x, y, angle, ignore_placement);
         case MARKER_INTERIOR_PLACEMENT:
-            return markers_interior_placement<Locator, Detector>(locator,detector,params);
+            return interior_.get_point(x, y, angle, ignore_placement);
         case MARKER_LINE_PLACEMENT:
-            return markers_line_placement<Locator, Detector>(locator,detector,params);
+            return line_.get_point(x, y, angle, ignore_placement);
         case MARKER_VERTEX_FIRST_PLACEMENT:
-            return markers_vertex_first_placement<Locator, Detector>(locator,detector,params);
+            return vertex_first_.get_point(x, y, angle, ignore_placement);
         case MARKER_VERTEX_LAST_PLACEMENT:
-            return markers_vertex_last_placement<Locator, Detector>(locator,detector,params);
-        default: // point
-            return markers_point_placement<Locator, Detector>(locator,detector,params);
+            return vertex_last_.get_point(x, y, angle, ignore_placement);
         }
     }
 
-    markers_placement placement_;
+private:
+    marker_placement_e const placement_type_;
+
+    union
+    {
+        markers_point_placement<Locator, Detector> point_;
+        markers_line_placement<Locator, Detector> line_;
+        markers_interior_placement<Locator, Detector> interior_;
+        markers_vertex_first_placement<Locator, Detector> vertex_first_;
+        markers_vertex_last_placement<Locator, Detector> vertex_last_;
+    };
+
+    template <typename T>
+    static T* construct(T* what, Locator & locator, Detector & detector,
+                        markers_placement_params const& params)
+    {
+        return new(what) T(locator, detector, params);
+    }
+
+    template <typename T>
+    static void destroy(T* what)
+    {
+        what->~T();
+    }
 };
 
 }
diff --git a/include/mapnik/markers_placements/basic.hpp b/include/mapnik/markers_placements/basic.hpp
new file mode 100644
index 0000000..abcef5e
--- /dev/null
+++ b/include/mapnik/markers_placements/basic.hpp
@@ -0,0 +1,104 @@
+/*****************************************************************************
+ *
+ * This file is part of Mapnik (c++ mapping toolkit)
+ *
+ * Copyright (C) 2016 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_MARKERS_PLACEMENTS_BASIC_HPP
+#define MAPNIK_MARKERS_PLACEMENTS_BASIC_HPP
+
+// mapnik
+#include <mapnik/box2d.hpp>
+#include <mapnik/symbolizer_enumerations.hpp>
+#include <mapnik/util/math.hpp>
+#include <mapnik/util/noncopyable.hpp>
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
+#include "agg_basics.h"
+#include "agg_trans_affine.h"
+#pragma GCC diagnostic pop
+
+namespace mapnik {
+
+struct markers_placement_params
+{
+    box2d<double> size;
+    agg::trans_affine tr;
+    double spacing;
+    double max_error;
+    bool allow_overlap;
+    bool avoid_edges;
+    direction_enum direction;
+};
+
+class markers_basic_placement : util::noncopyable
+{
+public:
+    markers_basic_placement(markers_placement_params const& params)
+        : params_(params)
+    {
+    }
+
+protected:
+    markers_placement_params const& params_;
+
+    // Rotates the size_ box and translates the position.
+    box2d<double> perform_transform(double angle, double dx, double dy) const
+    {
+        auto tr = params_.tr * agg::trans_affine_rotation(angle).translate(dx, dy);
+        return box2d<double>(params_.size, tr);
+    }
+
+    bool set_direction(double & angle) const
+    {
+        switch (params_.direction)
+        {
+            case DIRECTION_UP:
+                angle = 0;
+                return true;
+            case DIRECTION_DOWN:
+                angle = M_PI;
+                return true;
+            case DIRECTION_AUTO:
+                if (std::fabs(util::normalize_angle(angle)) > 0.5 * M_PI)
+                    angle += M_PI;
+                return true;
+            case DIRECTION_AUTO_DOWN:
+                if (std::fabs(util::normalize_angle(angle)) < 0.5 * M_PI)
+                    angle += M_PI;
+                return true;
+            case DIRECTION_LEFT:
+                angle += M_PI;
+                return true;
+            case DIRECTION_LEFT_ONLY:
+                angle += M_PI;
+                return std::fabs(util::normalize_angle(angle)) < 0.5 * M_PI;
+            case DIRECTION_RIGHT_ONLY:
+                return std::fabs(util::normalize_angle(angle)) < 0.5 * M_PI;
+            case DIRECTION_RIGHT:
+            default:
+                return true;
+        }
+    }
+};
+
+} // namespace mapnik
+
+#endif // MAPNIK_MARKERS_PLACEMENTS_BASIC_HPP
diff --git a/include/mapnik/markers_placements/interior.hpp b/include/mapnik/markers_placements/interior.hpp
index 93b5e34..6a2705e 100644
--- a/include/mapnik/markers_placements/interior.hpp
+++ b/include/mapnik/markers_placements/interior.hpp
@@ -33,14 +33,8 @@ template <typename Locator, typename Detector>
 class markers_interior_placement : public markers_point_placement<Locator, Detector>
 {
 public:
-    markers_interior_placement(Locator &locator, Detector &detector, markers_placement_params const& params)
-        : markers_point_placement<Locator, Detector>(locator, detector, params)
-    {
-    }
-
-    markers_interior_placement(markers_interior_placement && rhs)
-        : markers_point_placement<Locator, Detector>(std::move(rhs))
-    {}
+    using point_placement = markers_point_placement<Locator, Detector>;
+    using point_placement::point_placement;
 
     bool get_point(double &x, double &y, double &angle, bool ignore_placement)
     {
@@ -51,7 +45,7 @@ public:
 
         if (this->locator_.type() == geometry::geometry_types::Point)
         {
-            return markers_point_placement<Locator, Detector>::get_point(x, y, angle, ignore_placement);
+            return point_placement::get_point(x, y, angle, ignore_placement);
         }
 
         if (this->locator_.type() == geometry::geometry_types::LineString)
@@ -73,20 +67,10 @@ public:
 
         angle = 0;
 
-        box2d<double> box = this->perform_transform(angle, x, y);
-        if (this->params_.avoid_edges && !this->detector_.extent().contains(box))
+        if (!this->push_to_detector(x, y, angle, ignore_placement))
         {
             return false;
         }
-        if (!this->params_.allow_overlap && !this->detector_.has_placement(box))
-        {
-            return false;
-        }
-
-        if (!ignore_placement)
-        {
-            this->detector_.insert(box);
-        }
 
         this->done_ = true;
         return true;
diff --git a/include/mapnik/markers_placements/line.hpp b/include/mapnik/markers_placements/line.hpp
index fe2c2bd..bc99cc9 100644
--- a/include/mapnik/markers_placements/line.hpp
+++ b/include/mapnik/markers_placements/line.hpp
@@ -35,29 +35,23 @@ template <typename Locator, typename Detector>
 class markers_line_placement : public markers_point_placement<Locator, Detector>
 {
 public:
-    markers_line_placement(Locator &locator, Detector &detector, markers_placement_params const& params)
-        : markers_point_placement<Locator, Detector>(locator, detector, params),
+    using point_placement = markers_point_placement<Locator, Detector>;
+    using point_placement::point_placement;
+
+    markers_line_placement(Locator & locator, Detector & detector,
+                           markers_placement_params const& params)
+        : point_placement(locator, detector, params),
             first_point_(true),
             spacing_(0.0),
             marker_width_((params.size * params.tr).width()),
             path_(locator)
     {
         spacing_ = params.spacing < 1 ? 100 : params.spacing;
-        rewind();
     }
 
-    markers_line_placement(markers_line_placement && rhs)
-        : markers_point_placement<Locator, Detector>(std::move(rhs)),
-          first_point_(std::move(rhs.first_point_)),
-          spacing_(std::move(rhs.spacing_)),
-          marker_width_(std::move(rhs.marker_width_)),
-          path_(std::move(rhs.path_))
-    {}
-
     void rewind()
     {
-        this->locator_.rewind(0);
-        this->done_ = false;
+        point_placement::rewind();
         first_point_ = true;
     }
 
@@ -70,7 +64,7 @@ public:
 
         if (this->locator_.type() == geometry::geometry_types::Point)
         {
-            return markers_point_placement<Locator, Detector>::get_point(x, y, angle, ignore_placement);
+            return point_placement::get_point(x, y, angle, ignore_placement);
         }
 
         double move = spacing_;
@@ -102,16 +96,10 @@ public:
                     {
                         continue;
                     }
-                    box2d<double> box = this->perform_transform(angle, x, y);
-                    if ((this->params_.avoid_edges && !this->detector_.extent().contains(box))
-                        || (!this->params_.allow_overlap && !this->detector_.has_placement(box)))
+                    if (!this->push_to_detector(x, y, angle, ignore_placement))
                     {
                         continue;
                     }
-                    if (!ignore_placement)
-                    {
-                        this->detector_.insert(box);
-                    }
                     return true;
                 }
             }
diff --git a/include/mapnik/markers_placements/point.hpp b/include/mapnik/markers_placements/point.hpp
index 13f174d..6e2f1da 100644
--- a/include/mapnik/markers_placements/point.hpp
+++ b/include/mapnik/markers_placements/point.hpp
@@ -23,53 +23,26 @@
 #ifndef MAPNIK_MARKERS_PLACEMENTS_POINT_HPP
 #define MAPNIK_MARKERS_PLACEMENTS_POINT_HPP
 
-#include <mapnik/box2d.hpp>
 #include <mapnik/geom_util.hpp>
 #include <mapnik/geometry_types.hpp>
-#include <mapnik/util/math.hpp>
-#include <mapnik/label_collision_detector.hpp>
-#include <mapnik/symbolizer_enumerations.hpp>
-#include <mapnik/util/noncopyable.hpp>
-
-#include "agg_basics.h"
-#include "agg_trans_affine.h"
-
-#include <cmath>
+#include <mapnik/markers_placements/basic.hpp>
 
 namespace mapnik {
 
-struct markers_placement_params
-{
-    box2d<double> size;
-    agg::trans_affine tr;
-    double spacing;
-    double max_error;
-    bool allow_overlap;
-    bool avoid_edges;
-    direction_enum direction;
-};
-
 template <typename Locator, typename Detector>
-class markers_point_placement : util::noncopyable
+class markers_point_placement : public markers_basic_placement
 {
 public:
-    markers_point_placement(Locator &locator, Detector &detector, markers_placement_params const& params)
-        : locator_(locator),
+    markers_point_placement(Locator & locator, Detector & detector,
+                            markers_placement_params const& params)
+        : markers_basic_placement(params),
+          locator_(locator),
           detector_(detector),
-          params_(params),
           done_(false)
     {
-        rewind();
+        locator_.rewind(0);
     }
 
-    markers_point_placement(markers_point_placement && rhs)
-        : locator_(rhs.locator_),
-          detector_(rhs.detector_),
-          params_(rhs.params_),
-          done_(rhs.done_)
-    {}
-
-
     // Start again at first marker. Returns the same list of markers only works when they were NOT added to the detector.
     void rewind()
     {
@@ -80,90 +53,66 @@ public:
     // Get next point where the marker should be placed. Returns true if a place is found, false if none is found.
     bool get_point(double &x, double &y, double &angle, bool ignore_placement)
     {
-        if (done_)
+        if (this->done_)
         {
             return false;
         }
 
-        if (locator_.type() == geometry::geometry_types::LineString)
+        if (this->locator_.type() == geometry::geometry_types::LineString)
         {
-            if (!label::middle_point(locator_, x, y))
+            if (!label::middle_point(this->locator_, x, y))
             {
-                done_ = true;
+                this->done_ = true;
                 return false;
             }
         }
         else
         {
-            if (!label::centroid(locator_, x, y))
+            if (!label::centroid(this->locator_, x, y))
             {
-                done_ = true;
+                this->done_ = true;
                 return false;
             }
         }
 
         angle = 0;
-        box2d<double> box = perform_transform(angle, x, y);
 
-        if (params_.avoid_edges && !detector_.extent().contains(box))
-        {
-            return false;
-        }
-        if (!params_.allow_overlap && !detector_.has_placement(box))
+        if (!this->push_to_detector(x, y, angle, ignore_placement))
         {
             return false;
         }
 
-        if (!ignore_placement)
-        {
-            detector_.insert(box);
-        }
-
-        done_ = true;
+        this->done_ = true;
         return true;
     }
 
 protected:
-    Locator &locator_;
-    Detector &detector_;
-    markers_placement_params const& params_;
+    Locator & locator_;
+    Detector & detector_;
     bool done_;
 
-    // Rotates the size_ box and translates the position.
-    box2d<double> perform_transform(double angle, double dx, double dy)
-    {
-        agg::trans_affine tr = params_.tr * agg::trans_affine_rotation(angle).translate(dx, dy);
-        return box2d<double>(params_.size, tr);
-    }
-
-    bool set_direction(double & angle)
+    // Checks transformed box placement with collision detector.
+    // returns false if the box:
+    //  - a) isn't wholly inside extent and avoid_edges == true
+    //  - b) collides with something and allow_overlap == false
+    // otherwise returns true, and if ignore_placement == false,
+    //  also adds the box to collision detector
+    bool push_to_detector(double x, double y, double angle, bool ignore_placement)
     {
-        switch (params_.direction)
+        auto box = perform_transform(angle, x, y);
+        if (params_.avoid_edges && !detector_.extent().contains(box))
+        {
+            return false;
+        }
+        if (!params_.allow_overlap && !detector_.has_placement(box))
+        {
+            return false;
+        }
+        if (!ignore_placement)
         {
-            case DIRECTION_UP:
-                angle = .0;
-                return true;
-            case DIRECTION_DOWN:
-                angle = M_PI;
-                return true;
-            case DIRECTION_AUTO:
-                angle = (std::fabs(util::normalize_angle(angle)) > 0.5 * M_PI) ? (angle + M_PI) : angle;
-                return true;
-            case DIRECTION_AUTO_DOWN:
-                angle = (std::fabs(util::normalize_angle(angle)) < 0.5 * M_PI) ? (angle + M_PI) : angle;
-                return true;
-            case DIRECTION_LEFT:
-                angle += M_PI;
-                return true;
-            case DIRECTION_LEFT_ONLY:
-                angle += M_PI;
-                return std::fabs(util::normalize_angle(angle)) < 0.5 * M_PI;
-            case DIRECTION_RIGHT_ONLY:
-                return std::fabs(util::normalize_angle(angle)) < 0.5 * M_PI;
-            case DIRECTION_RIGHT:
-            default:
-                return true;
+            detector_.insert(box);
         }
+        return true;
     }
 };
 
diff --git a/include/mapnik/markers_placements/vertext_first.hpp b/include/mapnik/markers_placements/vertext_first.hpp
index bcdac2b..ce1b415 100644
--- a/include/mapnik/markers_placements/vertext_first.hpp
+++ b/include/mapnik/markers_placements/vertext_first.hpp
@@ -31,14 +31,8 @@ template <typename Locator, typename Detector>
 class markers_vertex_first_placement : public markers_point_placement<Locator, Detector>
 {
 public:
-    markers_vertex_first_placement(Locator &locator, Detector &detector, markers_placement_params const& params)
-        : markers_point_placement<Locator, Detector>(locator, detector, params)
-    {
-    }
-
-    markers_vertex_first_placement(markers_vertex_first_placement && rhs)
-        : markers_point_placement<Locator, Detector>(std::move(rhs))
-    {}
+    using point_placement = markers_point_placement<Locator, Detector>;
+    using point_placement::point_placement;
 
     bool get_point(double &x, double &y, double &angle, bool ignore_placement)
     {
@@ -49,7 +43,7 @@ public:
 
         if (this->locator_.type() == mapnik::geometry::geometry_types::Point)
         {
-            return markers_point_placement<Locator, Detector>::get_point(x, y, angle, ignore_placement);
+            return point_placement::get_point(x, y, angle, ignore_placement);
         }
 
         double x0, y0;
@@ -75,20 +69,10 @@ public:
             }
         }
 
-        box2d<double> box = this->perform_transform(angle, x, y);
-        if (this->params_.avoid_edges && !this->detector_.extent().contains(box))
+        if (!this->push_to_detector(x, y, angle, ignore_placement))
         {
             return false;
         }
-        if (!this->params_.allow_overlap && !this->detector_.has_placement(box))
-        {
-            return false;
-        }
-
-        if (!ignore_placement)
-        {
-            this->detector_.insert(box);
-        }
 
         this->done_ = true;
         return true;
diff --git a/include/mapnik/markers_placements/vertext_last.hpp b/include/mapnik/markers_placements/vertext_last.hpp
index 4d57130..62c94a6 100644
--- a/include/mapnik/markers_placements/vertext_last.hpp
+++ b/include/mapnik/markers_placements/vertext_last.hpp
@@ -31,13 +31,8 @@ template <typename Locator, typename Detector>
 class markers_vertex_last_placement : public markers_point_placement<Locator, Detector>
 {
 public:
-    markers_vertex_last_placement(Locator &locator, Detector &detector, markers_placement_params const& params)
-        : markers_point_placement<Locator, Detector>(locator, detector, params)
-    {}
-
-    markers_vertex_last_placement(markers_vertex_last_placement && rhs)
-        : markers_point_placement<Locator, Detector>(std::move(rhs))
-    {}
+    using point_placement = markers_point_placement<Locator, Detector>;
+    using point_placement::point_placement;
 
     bool get_point(double &x, double &y, double &angle, bool ignore_placement)
     {
@@ -80,21 +75,11 @@ public:
             }
         }
 
-        box2d<double> box = this->perform_transform(angle, x, y);
-        if (this->params_.avoid_edges && !this->detector_.extent().contains(box))
-        {
-            return false;
-        }
-        if (!this->params_.allow_overlap && !this->detector_.has_placement(box))
+        if (!this->push_to_detector(x, y, angle, ignore_placement))
         {
             return false;
         }
 
-        if (!ignore_placement)
-        {
-            this->detector_.insert(box);
-        }
-
         this->done_ = true;
         return true;
     }
diff --git a/include/mapnik/params.hpp b/include/mapnik/params.hpp
index a154cf7..a38fa54 100644
--- a/include/mapnik/params.hpp
+++ b/include/mapnik/params.hpp
@@ -27,8 +27,11 @@
 #include <mapnik/config.hpp>
 #include <mapnik/value_types.hpp>
 #include <mapnik/util/variant.hpp>
-// boost
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/optional.hpp>
+#pragma GCC diagnostic pop
 
 // stl
 #include <string>
diff --git a/include/mapnik/path_expression_grammar_impl.hpp b/include/mapnik/path_expression_grammar_impl.hpp
index bc2fcfb..22002bf 100644
--- a/include/mapnik/path_expression_grammar_impl.hpp
+++ b/include/mapnik/path_expression_grammar_impl.hpp
@@ -24,10 +24,13 @@
 #include <mapnik/path_expression_grammar.hpp>
 #include <mapnik/attribute.hpp>
 
-// boost
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/spirit/include/phoenix_core.hpp>
 #include <boost/spirit/include/phoenix_object.hpp>
 #include <boost/spirit/include/phoenix_stl.hpp>
+#pragma GCC diagnostic pop
 
 namespace mapnik
 {
diff --git a/include/mapnik/png_io.hpp b/include/mapnik/png_io.hpp
index f17f857..051ea6b 100644
--- a/include/mapnik/png_io.hpp
+++ b/include/mapnik/png_io.hpp
@@ -29,17 +29,19 @@
 #include <mapnik/hextree.hpp>
 #include <mapnik/image.hpp>
 
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
+
 // zlib
 #include <zlib.h>  // for Z_DEFAULT_COMPRESSION
 
-// boost
-
-
 extern "C"
 {
 #include <png.h>
 }
 
+#pragma GCC diagnostic pop
+
 #define MAX_OCTREE_LEVELS 4
 
 namespace mapnik {
@@ -99,10 +101,10 @@ void save_as_png(T1 & file,
     png_infop info_ptr = png_create_info_struct(png_ptr);
     if (!info_ptr)
     {
-        png_destroy_write_struct(&png_ptr,(png_infopp)0);
+        png_destroy_write_struct(&png_ptr,static_cast<png_infopp>(0));
         return;
     }
-    jmp_buf* jmp_context = (jmp_buf*) png_get_error_ptr(png_ptr);
+    jmp_buf* jmp_context = static_cast<jmp_buf*>(png_get_error_ptr(png_ptr));
     if (jmp_context)
     {
         png_destroy_write_struct(&png_ptr, &info_ptr);
@@ -120,7 +122,7 @@ void save_as_png(T1 & file,
     const std::unique_ptr<png_bytep[]> row_pointers(new png_bytep[image.height()]);
     for (unsigned int i = 0; i < image.height(); i++)
     {
-        row_pointers[i] = (png_bytep)image.get_row(i);
+        row_pointers[i] = const_cast<png_bytep>(reinterpret_cast<const unsigned char *>(image.get_row(i)));
     }
     png_set_rows(png_ptr, info_ptr, row_pointers.get());
     png_write_png(png_ptr, info_ptr, (opts.trans_mode == 0) ? PNG_TRANSFORM_STRIP_FILLER_AFTER : PNG_TRANSFORM_IDENTITY, nullptr);
@@ -161,7 +163,7 @@ void reduce_8(T const& in,
                     break;
                 }
             }
-            if (idx>=0 && idx<(int)alpha.size())
+            if (idx>=0 && idx < static_cast<int>(alpha.size()))
             {
                 alpha[idx]+=U2ALPHA(val);
                 alphaCount[idx]++;
@@ -212,7 +214,7 @@ void reduce_4(T const& in,
                     break;
                 }
             }
-            if (idx>=0 && idx<(int)alpha.size())
+            if (idx>=0 && idx < static_cast<int>(alpha.size()))
             {
                 alpha[idx]+=U2ALPHA(val);
                 alphaCount[idx]++;
@@ -273,10 +275,10 @@ void save_as_png(T & file, std::vector<mapnik::rgb> const& palette,
     png_infop info_ptr = png_create_info_struct(png_ptr);
     if (!info_ptr)
     {
-        png_destroy_write_struct(&png_ptr,(png_infopp)0);
+        png_destroy_write_struct(&png_ptr,static_cast<png_infopp>(0));
         return;
     }
-    jmp_buf* jmp_context = (jmp_buf*) png_get_error_ptr(png_ptr);
+    jmp_buf* jmp_context = static_cast<jmp_buf*>(png_get_error_ptr(png_ptr));
     if (jmp_context)
     {
         png_destroy_write_struct(&png_ptr, &info_ptr);
@@ -310,14 +312,14 @@ void save_as_png(T & file, std::vector<mapnik::rgb> const& palette,
         }
         if (alphaSize>0)
         {
-            png_set_tRNS(png_ptr, info_ptr, (png_bytep)&trans[0], alphaSize, 0);
+            png_set_tRNS(png_ptr, info_ptr, static_cast<png_bytep>(&trans[0]), alphaSize, 0);
         }
     }
 
     png_write_info(png_ptr, info_ptr);
     for (unsigned i=0;i<height;i++)
     {
-        png_write_row(png_ptr,(png_bytep)image.get_row(i));
+        png_write_row(png_ptr,const_cast<png_bytep>(image.get_row(i)));
     }
 
     png_write_end(png_ptr, info_ptr);
@@ -352,7 +354,7 @@ void save_as_png8_oct(T1 & file,
         {
             for (unsigned x = 0; x < width; ++x)
             {
-                unsigned val = U2ALPHA((unsigned)image.get_row(y)[x]);
+                unsigned val = U2ALPHA(static_cast<unsigned>(image.get_row(y)[x]));
                 alphaHist[val]++;
                 meanAlpha += val;
                 if (val>0 && val<255)
diff --git a/include/mapnik/projection.hpp b/include/mapnik/projection.hpp
index cb4284f..0869bb2 100644
--- a/include/mapnik/projection.hpp
+++ b/include/mapnik/projection.hpp
@@ -27,8 +27,10 @@
 #include <mapnik/config.hpp>
 #include <mapnik/well_known_srs.hpp>
 
-// boost
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/optional.hpp>
+#pragma GCC diagnostic pop
 
 // stl
 #include <string>
diff --git a/include/mapnik/ptree_helpers.hpp b/include/mapnik/ptree_helpers.hpp
index 3062d71..6a9c91e 100644
--- a/include/mapnik/ptree_helpers.hpp
+++ b/include/mapnik/ptree_helpers.hpp
@@ -26,8 +26,10 @@
 // stl
 #include <string>
 
-// boost
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/property_tree/ptree.hpp>
+#pragma GCC diagnostic pop
 
 namespace mapnik {
 
diff --git a/include/mapnik/quad_tree.hpp b/include/mapnik/quad_tree.hpp
index d60ee5d..c15f09f 100644
--- a/include/mapnik/quad_tree.hpp
+++ b/include/mapnik/quad_tree.hpp
@@ -36,26 +36,27 @@
 
 namespace mapnik
 {
-template <typename T>
+template <typename T0, typename T1 = box2d<double>>
 class quad_tree : util::noncopyable
 {
-    using value_type = T;
+    using value_type = T0;
+    using bbox_type = T1;
     struct node
     {
-        using cont_type = std::vector<T>;
+        using cont_type = std::vector<T0>;
         using iterator = typename cont_type::iterator;
         using const_iterator = typename cont_type::const_iterator;
-        box2d<double> extent_;
+        bbox_type extent_;
         cont_type cont_;
         node * children_[4];
 
-        explicit node(box2d<double> const& ext)
+        explicit node(bbox_type const& ext)
             : extent_(ext)
         {
             std::fill(children_, children_ + 4, nullptr);
         }
 
-        box2d<double> const& extent() const
+        bbox_type const& extent() const
         {
             return extent_;
         }
@@ -99,10 +100,10 @@ class quad_tree : util::noncopyable
 public:
     using iterator = typename nodes_type::iterator;
     using const_iterator = typename nodes_type::const_iterator;
-    using result_type = typename std::vector<std::reference_wrapper<T> >;
+    using result_type = typename std::vector<std::reference_wrapper<value_type> >;
     using query_iterator = typename result_type::iterator;
 
-    explicit quad_tree(box2d<double> const& ext,
+    explicit quad_tree(bbox_type const& ext,
                        unsigned int max_depth = 8,
                        double ratio = 0.55)
         : max_depth_(max_depth),
@@ -114,13 +115,13 @@ public:
         root_ = nodes_[0].get();
     }
 
-    void insert(T data, box2d<double> const& box)
+    void insert(value_type data, bbox_type const& box)
     {
-        unsigned int depth=0;
-        do_insert_data(data,box,root_,depth);
+        unsigned int depth = 0;
+        do_insert_data(data, box, root_, depth);
     }
 
-    query_iterator query_in_box(box2d<double> const& box)
+    query_iterator query_in_box(bbox_type const& box)
     {
         query_result_.clear();
         query_node(box, query_result_, root_);
@@ -145,13 +146,13 @@ public:
 
     void clear ()
     {
-        box2d<double> ext = root_->extent_;
+        bbox_type ext = root_->extent_;
         nodes_.clear();
         nodes_.push_back(std::make_unique<node>(ext));
         root_ = nodes_[0].get();
     }
 
-    box2d<double> const& extent() const
+    bbox_type const& extent() const
     {
         return root_->extent_;
     }
@@ -185,11 +186,11 @@ public:
     }
 private:
 
-    void query_node(box2d<double> const& box, result_type & result, node * node_) const
+    void query_node(bbox_type const& box, result_type & result, node * node_) const
     {
         if (node_)
         {
-            box2d<double> const& node_extent = node_->extent();
+            bbox_type const& node_extent = node_->extent();
             if (box.intersects(node_extent))
             {
                 for (auto & n : *node_)
@@ -204,7 +205,7 @@ private:
         }
     }
 
-    void do_insert_data(T data, box2d<double> const& box, node * n, unsigned int& depth)
+    void do_insert_data(value_type data, bbox_type const& box, node * n, unsigned int& depth)
     {
         if (++depth >= max_depth_)
         {
@@ -212,8 +213,8 @@ private:
         }
         else
         {
-            box2d<double> const& node_extent = n->extent();
-            box2d<double> ext[4];
+            bbox_type const& node_extent = n->extent();
+            bbox_type ext[4];
             split_box(node_extent,ext);
             for (int i = 0; i < 4; ++i)
             {
@@ -232,20 +233,19 @@ private:
         }
     }
 
-    void split_box(box2d<double> const& node_extent,box2d<double> * ext)
+    void split_box(bbox_type const& node_extent,bbox_type * ext)
     {
-        double width=node_extent.width();
-        double height=node_extent.height();
-
-        double lox=node_extent.minx();
-        double loy=node_extent.miny();
-        double hix=node_extent.maxx();
-        double hiy=node_extent.maxy();
-
-        ext[0]=box2d<double>(lox,loy,lox + width * ratio_,loy + height * ratio_);
-        ext[1]=box2d<double>(hix - width * ratio_,loy,hix,loy + height * ratio_);
-        ext[2]=box2d<double>(lox,hiy - height*ratio_,lox + width * ratio_,hiy);
-        ext[3]=box2d<double>(hix - width * ratio_,hiy - height*ratio_,hix,hiy);
+        typename bbox_type::value_type width = node_extent.width();
+        typename bbox_type::value_type height = node_extent.height();
+        typename bbox_type::value_type lox = node_extent.minx();
+        typename bbox_type::value_type loy = node_extent.miny();
+        typename bbox_type::value_type hix = node_extent.maxx();
+        typename bbox_type::value_type hiy = node_extent.maxy();
+
+        ext[0] = bbox_type(lox, loy, lox + width * ratio_, loy + height * ratio_);
+        ext[1] = bbox_type(hix - width * ratio_, loy, hix, loy + height * ratio_);
+        ext[2] = bbox_type(lox, hiy - height * ratio_, lox + width * ratio_, hiy);
+        ext[3] = bbox_type(hix - width * ratio_, hiy - height * ratio_, hix, hiy);
     }
 
     void trim_tree(node *& n)
@@ -304,7 +304,7 @@ private:
         {
             if (n->children_[i])
             {
-                offset +=sizeof(box2d<double>) + (n->children_[i]->cont_.size() * sizeof(value_type)) + 3 * sizeof(int);
+                offset +=sizeof(bbox_type) + (n->children_[i]->cont_.size() * sizeof(value_type)) + 3 * sizeof(int);
                 offset +=subnode_offset(n->children_[i]);
             }
         }
@@ -316,17 +316,17 @@ private:
     {
         if (n)
         {
-            int offset=subnode_offset(n);
-            int shape_count=n->cont_.size();
-            int recsize=sizeof(box2d<double>) + 3 * sizeof(int) + shape_count * sizeof(value_type);
+            int offset = subnode_offset(n);
+            int shape_count = n->cont_.size();
+            int recsize = sizeof(bbox_type) + 3 * sizeof(int) + shape_count * sizeof(value_type);
             std::unique_ptr<char[]> node_record(new char[recsize]);
             std::memset(node_record.get(), 0, recsize);
             std::memcpy(node_record.get(), &offset, 4);
-            std::memcpy(node_record.get() + 4, &n->extent_, sizeof(box2d<double>));
-            std::memcpy(node_record.get() + 36, &shape_count, 4);
+            std::memcpy(node_record.get() + 4, &n->extent_, sizeof(bbox_type));
+            std::memcpy(node_record.get() + 4 + sizeof(bbox_type), &shape_count, 4);
             for (int i=0; i < shape_count; ++i)
             {
-                memcpy(node_record.get() + 40 + i * sizeof(value_type), &(n->cont_[i]),sizeof(value_type));
+                memcpy(node_record.get() + 8 + sizeof(bbox_type) + i * sizeof(value_type), &(n->cont_[i]), sizeof(value_type));
             }
             int num_subnodes=0;
             for (int i = 0; i < 4; ++i)
@@ -336,7 +336,7 @@ private:
                     ++num_subnodes;
                 }
             }
-            std::memcpy(node_record.get() + 40 + shape_count * sizeof(value_type),&num_subnodes,4);
+            std::memcpy(node_record.get() + 8 + sizeof(bbox_type) + shape_count * sizeof(value_type), &num_subnodes, 4);
             out.write(node_record.get(),recsize);
             for (int i = 0; i < 4; ++i)
             {
diff --git a/include/mapnik/raster.hpp b/include/mapnik/raster.hpp
index 311c06c..02022d3 100644
--- a/include/mapnik/raster.hpp
+++ b/include/mapnik/raster.hpp
@@ -28,8 +28,11 @@
 #include <mapnik/image_any.hpp>
 #include <mapnik/util/noncopyable.hpp>
 #include <mapnik/util/variant.hpp>
- // boost
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/optional.hpp>
+#pragma GCC diagnostic pop
 
 namespace mapnik {
 
diff --git a/include/mapnik/raster_colorizer.hpp b/include/mapnik/raster_colorizer.hpp
index c1e83ab..86a85de 100644
--- a/include/mapnik/raster_colorizer.hpp
+++ b/include/mapnik/raster_colorizer.hpp
@@ -41,12 +41,13 @@
 #include <mapnik/color.hpp>
 #include <mapnik/enumeration.hpp>
 #include <mapnik/image.hpp>
- // boost
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/optional.hpp>
-// boost
-#include <memory>
+#pragma GCC diagnostic pop
 
-// stl
+#include <memory>
 #include <vector>
 
 namespace mapnik
@@ -164,7 +165,7 @@ public:
 
     void set_default_mode(colorizer_mode mode)
     {
-        default_mode_ = (mode == COLORIZER_INHERIT) ? COLORIZER_LINEAR:(colorizer_mode_enum)mode;
+        default_mode_ = (mode == COLORIZER_INHERIT) ? COLORIZER_LINEAR : static_cast<colorizer_mode_enum>(mode);
     }
 
     void set_default_mode_enum(colorizer_mode_enum mode) { set_default_mode(mode); }
diff --git a/include/mapnik/renderer_common/process_raster_symbolizer.hpp b/include/mapnik/renderer_common/process_raster_symbolizer.hpp
index f8ce32d..7ca90a0 100644
--- a/include/mapnik/renderer_common/process_raster_symbolizer.hpp
+++ b/include/mapnik/renderer_common/process_raster_symbolizer.hpp
@@ -32,13 +32,15 @@
 #include <mapnik/proj_transform.hpp>
 #include <mapnik/feature.hpp>
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_rendering_buffer.h"
 #include "agg_pixfmt_rgba.h"
 #include "agg_pixfmt_gray.h"
 #include "agg_rasterizer_scanline_aa.h"
 #include "agg_scanline_u.h"
 #include "agg_renderer_scanline.h"
+#pragma GCC diagnostic pop
 
 namespace mapnik {
 
diff --git a/include/mapnik/simplify.hpp b/include/mapnik/simplify.hpp
index 71b7711..dd75fcf 100644
--- a/include/mapnik/simplify.hpp
+++ b/include/mapnik/simplify.hpp
@@ -7,8 +7,10 @@
 // stl
 #include <string>
 
-// boost
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/optional.hpp>
+#pragma GCC diagnostic pop
 
 namespace mapnik
 {
diff --git a/include/mapnik/simplify_converter.hpp b/include/mapnik/simplify_converter.hpp
index 92f81b4..2488425 100644
--- a/include/mapnik/simplify_converter.hpp
+++ b/include/mapnik/simplify_converter.hpp
@@ -41,7 +41,7 @@ struct weighted_vertex : private util::noncopyable
         vertex2d const& A = prev->coord;
         vertex2d const& B = next->coord;
         vertex2d const& C = coord;
-        return std::abs((double)((A.x - C.x) * (B.y - A.y) - (A.x - B.x) * (C.y - A.y))) / 2.0;
+        return std::abs(static_cast<double>((A.x - C.x) * (B.y - A.y) - (A.x - B.x) * (C.y - A.y))) / 2.0;
     }
 
     struct ascending_sort
diff --git a/include/mapnik/span_image_filter.hpp b/include/mapnik/span_image_filter.hpp
index 972558c..c0a9adb 100644
--- a/include/mapnik/span_image_filter.hpp
+++ b/include/mapnik/span_image_filter.hpp
@@ -23,10 +23,18 @@
 #ifndef MAPNIK_SPAN_IMAGE_FILTER_INCLUDED
 #define MAPNIK_SPAN_IMAGE_FILTER_INCLUDED
 
-#include "agg_span_image_filter_gray.h"
-#include "agg_span_image_filter_rgba.h"
+#include <mapnik/safe_cast.hpp>
 
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/optional.hpp>
+#pragma GCC diagnostic pop
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
+#include "agg_span_image_filter_gray.h"
+#include "agg_span_image_filter_rgba.h"
+#pragma GCC diagnostic pop
 
 #include <limits>
 
@@ -79,16 +87,19 @@ public:
         {
             base_type::interpolator().coordinates(&x, &y);
 
-            int src_x = x >> agg::image_subpixel_shift;
-            int src_y = y >> agg::image_subpixel_shift;
-            const value_type* pix = reinterpret_cast<const value_type*>(base_type::source().span(src_x, src_y, 0));
-            if (nodata_value_ && *nodata_value_ == *pix)
+            if (nodata_value_)
             {
-                span->v = *nodata_value_;
-                span->a = base_mask;
-                ++span;
-                ++base_type::interpolator();
-                continue;
+                int src_x = x >> agg::image_subpixel_shift;
+                int src_y = y >> agg::image_subpixel_shift;
+                const value_type* pix = reinterpret_cast<const value_type*>(base_type::source().span(src_x, src_y, 1));
+                if (*nodata_value_ == *pix)
+                {
+                    span->v = *nodata_value_;
+                    span->a = base_mask;
+                    ++span;
+                    ++base_type::interpolator();
+                    continue;
+                }
             }
 
             x += base_type::filter_dx_int() - radius_x;
@@ -131,19 +142,15 @@ public:
                 fg_ptr = reinterpret_cast<const value_type*>(base_type::source().next_y());
             }
 
-            fg /= total_weight;
-            if (fg < std::numeric_limits<value_type>::min())
-            {
-                span->v = std::numeric_limits<value_type>::min();
-            }
-            else if (fg > std::numeric_limits<value_type>::max())
+            if (total_weight == 0)
             {
-                span->v = std::numeric_limits<value_type>::max();
+                span->v = *nodata_value_;
             }
             else
             {
-                span->v = static_cast<value_type>(fg);
+                span->v = safe_cast<value_type>(fg / total_weight);
             }
+
             span->a = base_mask;
 
             ++span;
diff --git a/include/mapnik/grid/grid_rendering_buffer.hpp b/include/mapnik/stringify_macro.hpp
similarity index 74%
copy from include/mapnik/grid/grid_rendering_buffer.hpp
copy to include/mapnik/stringify_macro.hpp
index 4282e3b..41f9474 100644
--- a/include/mapnik/grid/grid_rendering_buffer.hpp
+++ b/include/mapnik/stringify_macro.hpp
@@ -2,7 +2,7 @@
  *
  * This file is part of Mapnik (c++ mapping toolkit)
  *
- * Copyright (C) 2015 Artem Pavlenko
+ * Copyright (C) 2016 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,16 +20,7 @@
  *
  *****************************************************************************/
 
-#ifndef MAPNIK_GRID_RENDERING_BUFFER_HPP
-#define MAPNIK_GRID_RENDERING_BUFFER_HPP
-
-#include <mapnik/grid/grid.hpp>
-#include "agg_rendering_buffer.h"
-
-namespace mapnik {
-
-using grid_rendering_buffer = agg::row_ptr_cache<mapnik::grid::value_type>;
-
-}
-
-#endif //MAPNIK_AGG_RASTERIZER_HPP
+#ifndef MAPNIK_STRINGIFY
+#define MAPNIK_STRINGIFY(n) MAPNIK_STRINGIFY_HELPER(n)
+#define MAPNIK_STRINGIFY_HELPER(n) #n
+#endif
\ No newline at end of file
diff --git a/include/mapnik/svg/geometry_svg_generator.hpp b/include/mapnik/svg/geometry_svg_generator.hpp
index 11aa5c9..7594c26 100644
--- a/include/mapnik/svg/geometry_svg_generator.hpp
+++ b/include/mapnik/svg/geometry_svg_generator.hpp
@@ -36,15 +36,13 @@
 #pragma GCC diagnostic push
 #include <mapnik/warning_ignore.hpp>
 #include <boost/spirit/include/karma.hpp>
-#include <boost/spirit/include/phoenix_core.hpp>
-#include <boost/spirit/include/phoenix_operator.hpp>
-#include <boost/spirit/include/phoenix_fusion.hpp>
 #include <boost/spirit/include/phoenix_function.hpp>
-#include <boost/spirit/include/phoenix_statement.hpp>
+#include <boost/spirit/include/phoenix_operator.hpp>
 #include <boost/fusion/adapted/std_tuple.hpp>
 #include <boost/type_traits/remove_pointer.hpp>
 #pragma GCC diagnostic pop
 
+#include <tuple>
 
 // adapted to conform to the concepts
 // required by Karma to be recognized as a container of
diff --git a/include/mapnik/svg/output/svg_output_grammars.hpp b/include/mapnik/svg/output/svg_output_grammars.hpp
index 769671b..5657e26 100644
--- a/include/mapnik/svg/output/svg_output_grammars.hpp
+++ b/include/mapnik/svg/output/svg_output_grammars.hpp
@@ -40,53 +40,8 @@ namespace mapnik { namespace svg {
 #include <mapnik/warning_ignore.hpp>
 #include <boost/spirit/include/karma_nonterminal.hpp>
 #include <boost/spirit/include/karma_rule.hpp>
-#include <boost/fusion/adapted/struct.hpp>
 #pragma GCC diagnostic pop
 
-/*!
- * mapnik::svg::path_output_attributes is adapted as a fusion sequence
- * in order to be used directly by the svg_path_attributes_grammar (below).
- *
- * This adaptation is the primary reason why the attributes are stored in
- * this structure before being passed to the generate_path method.
- */
-BOOST_FUSION_ADAPT_STRUCT(
-    mapnik::svg::path_output_attributes,
-    (std::string, fill_color_)
-    (double, fill_opacity_)
-    (std::string, stroke_color_)
-    (double, stroke_opacity_)
-    (double, stroke_width_)
-    (std::string, stroke_linecap_)
-    (std::string, stroke_linejoin_)
-    (double, stroke_dashoffset_)
-    );
-
-/*!
- * mapnik::svg::rect_output_attributes is adapted as a fusion sequence
- * in order to be used directly by the svg_rect_attributes_grammar (below).
- */
-BOOST_FUSION_ADAPT_STRUCT(
-    mapnik::svg::rect_output_attributes,
-    (int, x_)
-    (int, y_)
-    (unsigned, width_)
-    (unsigned, height_)
-    (std::string, fill_color_)
-    );
-
-/*!
- * mapnik::svg::root_output_attributes is adapted as a fusion sequence
- * in order to be used directly by the svg_root_attributes_grammar (below).
- */
-BOOST_FUSION_ADAPT_STRUCT(
-    mapnik::svg::root_output_attributes,
-    (unsigned, width_)
-    (unsigned, height_)
-    (double, svg_version_)
-    (std::string, svg_namespace_url_)
-    );
-
 namespace mapnik { namespace svg {
 
     using namespace boost::spirit;
diff --git a/include/mapnik/svg/output/svg_output_grammars_impl.hpp b/include/mapnik/svg/output/svg_output_grammars_impl.hpp
index cbce919..ef856a0 100644
--- a/include/mapnik/svg/output/svg_output_grammars_impl.hpp
+++ b/include/mapnik/svg/output/svg_output_grammars_impl.hpp
@@ -30,8 +30,53 @@
 #include <mapnik/warning_ignore.hpp>
 #include <boost/spirit/include/karma.hpp>
 #include <boost/fusion/include/std_pair.hpp>
+#include <boost/fusion/adapted/struct.hpp>
 #pragma GCC diagnostic pop
 
+/*!
+ * mapnik::svg::path_output_attributes is adapted as a fusion sequence
+ * in order to be used directly by the svg_path_attributes_grammar (below).
+ *
+ * This adaptation is the primary reason why the attributes are stored in
+ * this structure before being passed to the generate_path method.
+ */
+BOOST_FUSION_ADAPT_STRUCT(
+    mapnik::svg::path_output_attributes,
+    (std::string, fill_color_)
+    (double, fill_opacity_)
+    (std::string, stroke_color_)
+    (double, stroke_opacity_)
+    (double, stroke_width_)
+    (std::string, stroke_linecap_)
+    (std::string, stroke_linejoin_)
+    (double, stroke_dashoffset_)
+    );
+
+/*!
+ * mapnik::svg::rect_output_attributes is adapted as a fusion sequence
+ * in order to be used directly by the svg_rect_attributes_grammar (below).
+ */
+BOOST_FUSION_ADAPT_STRUCT(
+    mapnik::svg::rect_output_attributes,
+    (int, x_)
+    (int, y_)
+    (unsigned, width_)
+    (unsigned, height_)
+    (std::string, fill_color_)
+    );
+
+/*!
+ * mapnik::svg::root_output_attributes is adapted as a fusion sequence
+ * in order to be used directly by the svg_root_attributes_grammar (below).
+ */
+BOOST_FUSION_ADAPT_STRUCT(
+    mapnik::svg::root_output_attributes,
+    (unsigned, width_)
+    (unsigned, height_)
+    (double, svg_version_)
+    (std::string, svg_namespace_url_)
+    );
+
 namespace mapnik { namespace svg {
 
 using namespace boost::spirit;
diff --git a/include/mapnik/svg/svg_converter.hpp b/include/mapnik/svg/svg_converter.hpp
index 50d7708..9cf3c9c 100644
--- a/include/mapnik/svg/svg_converter.hpp
+++ b/include/mapnik/svg/svg_converter.hpp
@@ -29,7 +29,8 @@
 #include <mapnik/util/noncopyable.hpp>
 #include <mapnik/safe_cast.hpp>
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_path_storage.h"
 #include "agg_conv_transform.h"
 #include "agg_conv_stroke.h"
@@ -37,6 +38,7 @@
 #include "agg_conv_curve.h"
 #include "agg_color_rgba.h"
 #include "agg_bounding_rect.h"
+#pragma GCC diagnostic pop
 
 // stl
 #include <stdexcept>
diff --git a/include/mapnik/svg/svg_path_adapter.hpp b/include/mapnik/svg/svg_path_adapter.hpp
index 3b09af4..8b4fb6b 100644
--- a/include/mapnik/svg/svg_path_adapter.hpp
+++ b/include/mapnik/svg/svg_path_adapter.hpp
@@ -28,10 +28,12 @@
 #include <mapnik/box2d.hpp>
 #include <mapnik/safe_cast.hpp>
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_math.h"
 #include "agg_array.h"
 #include "agg_bezier_arc.h"
+#pragma GCC diagnostic pop
 
 // stl
 #include <cmath>
diff --git a/include/mapnik/svg/svg_path_attributes.hpp b/include/mapnik/svg/svg_path_attributes.hpp
index d1b48aa..80bf463 100644
--- a/include/mapnik/svg/svg_path_attributes.hpp
+++ b/include/mapnik/svg/svg_path_attributes.hpp
@@ -23,15 +23,17 @@
 #ifndef MAPNIK_SVG_PATH_ATTRIBUTES_HPP
 #define MAPNIK_SVG_PATH_ATTRIBUTES_HPP
 
-// agg
-#include "agg_math_stroke.h"
-#include "agg_color_rgba.h"
-#include "agg_trans_affine.h"
-
 // mapnik
 #include <mapnik/gradient.hpp>
 #include <mapnik/symbolizer_base.hpp> // dash_array
 
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
+#include "agg_math_stroke.h"
+#include "agg_color_rgba.h"
+#include "agg_trans_affine.h"
+#pragma GCC diagnostic pop
+
 namespace mapnik {
 namespace svg {
 
diff --git a/include/mapnik/svg/svg_path_commands.hpp b/include/mapnik/svg/svg_path_commands.hpp
index cf69e13..7e7ab5f 100644
--- a/include/mapnik/svg/svg_path_commands.hpp
+++ b/include/mapnik/svg/svg_path_commands.hpp
@@ -29,241 +29,130 @@
 
 #pragma GCC diagnostic push
 #include <mapnik/warning_ignore.hpp>
-#include <boost/spirit/include/qi.hpp>
-#include <boost/spirit/include/phoenix_function.hpp>
-#include <boost/spirit/include/phoenix_core.hpp>
-#include <boost/spirit/include/phoenix_operator.hpp>
+#include <boost/fusion/sequence/intrinsic/at.hpp>
 #pragma GCC diagnostic pop
 
-namespace mapnik { namespace svg {
+namespace mapnik {
+namespace svg {
 
-using namespace boost::fusion;
 
 inline double deg2rad(double deg)
 {
-    return (M_PI * deg)/180.0;
+    return (M_PI * deg) / 180.0;
 }
 
-template <typename PathType>
 struct move_to
 {
+    using result_type = void;
 
-    template <typename T0>
-    struct result
-    {
-        using type = void;
-    };
-
-    explicit move_to(PathType & path)
-        : path_(path) {}
-
-    template  <typename T0, typename T1>
-    void operator() (T0 v, T1 rel) const
+    template <typename PathType, typename T0, typename T1>
+    void operator()(PathType& path, T0 v, T1 rel) const
     {
-        path_.move_to(at_c<0>(v),at_c<1>(v),rel); // impl
+        path.move_to(boost::fusion::at_c<0>(v), boost::fusion::at_c<1>(v), rel); // impl
     }
-
-    PathType & path_;
 };
 
-template <typename PathType>
 struct hline_to
 {
-    template <typename T0>
-    struct result
-    {
-        using type = void;
-    };
-
-    explicit hline_to(PathType & path)
-        : path_(path) {}
-
-    template  <typename T0, typename T1>
-    void operator() (T0 const& x, T1 rel) const
+    using result_type = void;
+    template <typename PathType, typename T0, typename T1>
+    void operator()(PathType& path, T0 const& x, T1 rel) const
     {
-        path_.hline_to(x,rel);
+        path.hline_to(x, rel);
     }
-
-    PathType & path_;
 };
 
-
-template <typename PathType>
 struct vline_to
 {
-    template <typename T0>
-    struct result
-    {
-        using type = void;
-    };
-
-    explicit vline_to(PathType & path)
-        : path_(path) {}
-
-    template  <typename T0, typename T1>
-    void operator() (T0 const& y, T1 rel) const
+    using result_type = void;
+    template <typename PathType, typename T0, typename T1>
+    void operator()(PathType& path, T0 const& y, T1 rel) const
     {
-        path_.vline_to(y,rel);
+        path.vline_to(y, rel);
     }
-
-    PathType & path_;
 };
 
-template <typename PathType>
 struct line_to
 {
-    template <typename T0>
-    struct result
-    {
-        using type = void;
-    };
-
-    explicit line_to(PathType & path)
-        : path_(path) {}
-
-    template  <typename T0, typename T1>
-    void operator() (T0 const& v, T1 rel) const
+    using result_type = void;
+    template <typename PathType, typename T0, typename T1>
+    void operator()(PathType& path, T0 const& v, T1 rel) const
     {
-        path_.line_to(at_c<0>(v),at_c<1>(v),rel); // impl
+        path.line_to(boost::fusion::at_c<0>(v), boost::fusion::at_c<1>(v), rel); // impl
     }
-
-    PathType & path_;
 };
 
-
-template <typename PathType>
 struct curve4
 {
-    template <typename T0>
-    struct result
-    {
-        using type = void;
-    };
-
-    explicit curve4(PathType & path)
-        : path_(path) {}
-
-    template  <typename T0, typename T1,typename T2, typename T3>
-    void operator() (T0 const& v0, T1 const& v1, T2 const& v2, T3 rel) const
+    using result_type = void;
+    template <typename PathType, typename T0, typename T1, typename T2, typename T3>
+    void operator()(PathType& path, 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
+        path.curve4(boost::fusion::at_c<0>(v0), boost::fusion::at_c<1>(v0),
+                    boost::fusion::at_c<0>(v1), boost::fusion::at_c<1>(v1),
+                    boost::fusion::at_c<0>(v2), boost::fusion::at_c<1>(v2),
+                    rel); // impl
     }
-
-    PathType & path_;
 };
 
-
-template <typename PathType>
 struct curve4_smooth
 {
-    template <typename T0>
-    struct result
-    {
-        using type = void;
-    };
-
-    explicit curve4_smooth(PathType & path)
-        : path_(path) {}
-
-    template  <typename T0, typename T1,typename T2>
-    void operator() (T0 const& v0, T1 const& v1, T2 rel) const
+    using result_type = void;
+    template <typename PathType, typename T0, typename T1, typename T2>
+    void operator()(PathType& path, 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
+        path.curve4(boost::fusion::at_c<0>(v0), boost::fusion::at_c<1>(v0),
+                    boost::fusion::at_c<0>(v1), boost::fusion::at_c<1>(v1),
+                    rel); // impl
     }
-    PathType & path_;
 };
 
-template <typename PathType>
 struct curve3
 {
-    template <typename T0>
-    struct result
-    {
-        using type = void;
-    };
-
-    explicit curve3(PathType & path)
-        : path_(path) {}
-
-    template  <typename T0, typename T1,typename T2>
-    void operator() (T0 const& v0, T1 const& v1, T2 rel) const
+    using result_type = void;
+    template <typename PathType, typename T0, typename T1, typename T2>
+    void operator()(PathType& path, 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
+        path.curve3(boost::fusion::at_c<0>(v0), boost::fusion::at_c<1>(v0),
+                    boost::fusion::at_c<0>(v1), boost::fusion::at_c<1>(v1),
+                    rel); // impl
     }
-
-    PathType & path_;
 };
 
-template <typename PathType>
 struct curve3_smooth
 {
-    template <typename T0>
-    struct result
-    {
-        using type = void;
-    };
-
-    explicit curve3_smooth(PathType & path)
-        : path_(path) {}
-
-    template  <typename T0, typename T1>
-    void operator() (T0 const& v0, T1 rel) const
+    using result_type = void;
+    template <typename PathType, typename T0, typename T1>
+    void operator()(PathType& path, T0 const& v0, T1 rel) const
     {
-        path_.curve3(at_c<0>(v0),at_c<1>(v0),
-                     rel); // impl
+        path.curve3(boost::fusion::at_c<0>(v0), boost::fusion::at_c<1>(v0),
+                    rel); // impl
     }
-
-    PathType & path_;
 };
 
-template <typename PathType>
 struct arc_to
 {
-    template <typename T0>
-    struct result
-    {
-        using type = void;
-    };
-
-    explicit arc_to(PathType & path)
-        : path_(path) {}
-
-    template  <typename T0, typename T1,typename T2, typename T3, typename T4, typename T5>
-    void operator() (T0 const& rv, T1 const& angle, T2 large_arc_flag, T3 sweep_flag, T4 const& v, T5 rel) const
+    using result_type = void;
+    template <typename PathType, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5>
+    void operator()(PathType& path, 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);
+        path.arc_to(boost::fusion::at_c<0>(rv), boost::fusion::at_c<1>(rv),
+                    deg2rad(angle), large_arc_flag, sweep_flag,
+                    boost::fusion::at_c<0>(v), boost::fusion::at_c<1>(v),
+                    rel);
     }
-
-    PathType & path_;
 };
 
-template <typename PathType>
 struct close
 {
     using result_type = void;
-
-    explicit close(PathType & path)
-        : path_(path) {}
-
-    void operator()() const
+    template <typename PathType>
+    void operator()(PathType& path) const
     {
-        path_.close_subpath();
+        path.close_subpath();
     }
-
-    PathType & path_;
 };
-
-}}
-
+} // namespace svg
+} // namespace mapnik
 
 #endif // MAPNIK_SVG_COMMANDS_HPP
diff --git a/include/mapnik/svg/svg_path_grammar.hpp b/include/mapnik/svg/svg_path_grammar.hpp
index 93d27f1..a65b272 100644
--- a/include/mapnik/svg/svg_path_grammar.hpp
+++ b/include/mapnik/svg/svg_path_grammar.hpp
@@ -2,7 +2,7 @@
  *
  * This file is part of Mapnik (c++ mapping toolkit)
  *
- * Copyright (C) 2015 Artem Pavlenko
+ * Copyright (C) 2016 Artem Pavlenko
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -23,116 +23,39 @@
 #ifndef MAPNIK_SVG_PATH_GRAMMAR_HPP
 #define MAPNIK_SVG_PATH_GRAMMAR_HPP
 
-// mapnik
-#include <mapnik/svg/svg_path_commands.hpp>
-
 // spirit
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/spirit/include/qi.hpp>
-#include <boost/spirit/include/phoenix_function.hpp>
-#include <boost/spirit/include/phoenix_core.hpp>
-#include <boost/spirit/include/phoenix_operator.hpp>
+#pragma GCC diagnostic pop
 
 namespace mapnik { namespace svg {
 
-    using namespace boost::spirit;
-    using namespace boost::phoenix;
-
-    template <typename Iterator, typename SkipType, typename PathType>
-    struct svg_path_grammar : qi::grammar<Iterator,SkipType>
-    {
-        explicit svg_path_grammar(PathType & path)
-            : svg_path_grammar::base_type(start),
-              move_to_(move_to<PathType>(path)),
-              hline_to_(hline_to<PathType>(path)),
-              vline_to_(vline_to<PathType>(path)),
-              line_to_(line_to<PathType>(path)),
-              curve4_(curve4<PathType>(path)),
-              curve4_smooth_(curve4_smooth<PathType>(path)),
-              curve3_(curve3<PathType>(path)),
-              curve3_smooth_(curve3_smooth<PathType>(path)),
-              arc_to_(arc_to<PathType>(path)),
-              close_(close<PathType>(path))
-        {
-            qi::_1_type _1;
-            qi::_2_type _2;
-            qi::_3_type _3;
-            qi::_4_type _4;
-            qi::_5_type _5;
-            qi::_a_type _a;
-            qi::lit_type lit;
-            qi::double_type double_;
-            qi::int_type int_;
-            qi::no_case_type no_case;
-
-            start = +cmd;
-            cmd = M  >> *drawto_cmd;
-            drawto_cmd =  L | H | V | C | S | Q | T | A | Z;
-
-            M = (lit('M')[_a = false] | lit('m')[_a = true] )
-                >> coord[move_to_(_1,_a)] // move_to
-                >> *(-lit(',') >> coord [ line_to_(_1,_a) ] ); // *line_to
-
-            H = (lit('H')[_a = false] | lit('h')[_a = true])
-                >> (double_[ hline_to_(_1,_a) ] % -lit(',')) ; // +hline_to
-
-            V = (lit('V')[_a = false] | lit('v')[_a = true])
-                >> (double_ [ vline_to_(_1,_a) ] % -lit(',')); // +vline_to
-
-            L = (lit('L')[_a = false] | lit('l')[_a = true])
-                >> (coord [ line_to_(_1,_a) ] % -lit(',')); // +line_to
-
-            C = (lit('C')[_a = false] | lit('c')[_a = true])
-                >> ((coord >> -lit(',') >> coord >> -lit(',') >> coord) [ curve4_(_1,_2,_3,_a) ] % -lit(',')); // +curve4
-
-            S = (lit('S')[_a = false] | lit('s')[_a = true])
-                >> ((coord >> -lit(',') >> coord) [ curve4_smooth_(_1,_2,_a) ] % -lit(',')); // +curve4_smooth (smooth curveto)
-
-            Q = (lit('Q')[_a = false] | lit('q')[_a = true])
-                >> ((coord >> -lit(',') >> coord) [ curve3_(_1,_2,_a) ] % -lit(',')); // +curve3 (quadratic-bezier-curveto)
-
-            T = (lit('T')[_a = false] | lit('t')[_a = true])
-                >> ((coord ) [ curve3_smooth_(_1,_a) ] % -lit(',')); // +curve3_smooth (smooth-quadratic-bezier-curveto)
-
-            A = (lit('A')[_a = false] | lit('a')[_a = true])
-                >> ((coord >> -lit(',') >> double_ >> -lit(',')
-                     >> int_ >> -lit(',') >> int_ >> -lit(',') >> coord) [arc_to_(_1,_2,_3,_4,_5,_a)] % -lit(',')); // arc_to;
-
-            Z = no_case[lit('z')] [close_()]; // close path
-
-            coord = double_ >> -lit(',') >> double_;
-        }
-
-        // rules
-        qi::rule<Iterator,SkipType> start;
-        qi::rule<Iterator,SkipType> cmd;
-        qi::rule<Iterator,SkipType> drawto_cmd;
-        qi::rule<Iterator,qi::locals<bool>,SkipType> M; // M,m
-        qi::rule<Iterator,qi::locals<bool>,SkipType> L; // L,l
-        qi::rule<Iterator,qi::locals<bool>,SkipType> H; // H,h
-        qi::rule<Iterator,qi::locals<bool>,SkipType> V; // V,v
-        qi::rule<Iterator,qi::locals<bool>,SkipType> C; // C,c
-        qi::rule<Iterator,qi::locals<bool>,SkipType> S; // S,s
-        qi::rule<Iterator,qi::locals<bool>,SkipType> Q; // Q,q
-        qi::rule<Iterator,qi::locals<bool>,SkipType> T; // T,t
-        qi::rule<Iterator,qi::locals<bool>,SkipType> A; // A,a
-        qi::rule<Iterator,SkipType> Z;                  // Z,z
-
-        qi::rule<Iterator,boost::fusion::vector2<double,double>(),SkipType> coord;
-
-        // commands
-        function<move_to<PathType> > move_to_;
-        function<hline_to<PathType> > hline_to_;
-        function<vline_to<PathType> > vline_to_;
-        function<line_to<PathType> > line_to_;
-        function<curve4<PathType> > curve4_;
-        function<curve4_smooth<PathType> > curve4_smooth_;
-        function<curve3<PathType> > curve3_;
-        function<curve3_smooth<PathType> > curve3_smooth_;
-        function<arc_to<PathType> > arc_to_;
-        function<close<PathType> > close_;
-    };
-
-    }}
+using namespace boost::spirit;
+
+template <typename Iterator, typename PathType, typename SkipType>
+struct svg_path_grammar : qi::grammar<Iterator, void(PathType&), SkipType>
+{
+    // ctor
+    svg_path_grammar();
+    // rules
+    qi::rule<Iterator, void(PathType&), SkipType> start;
+    qi::rule<Iterator, void(PathType&), SkipType> cmd;
+    qi::rule<Iterator, void(PathType&), SkipType> drawto_cmd;
+    qi::rule<Iterator, qi::locals<bool>, void(PathType&), SkipType> M; // M,m
+    qi::rule<Iterator, qi::locals<bool>, void(PathType&), SkipType> L; // L,l
+    qi::rule<Iterator, qi::locals<bool>, void(PathType&), SkipType> H; // H,h
+    qi::rule<Iterator, qi::locals<bool>, void(PathType&), SkipType> V; // V,v
+    qi::rule<Iterator, qi::locals<bool>, void(PathType&), SkipType> C; // C,c
+    qi::rule<Iterator, qi::locals<bool>, void(PathType&), SkipType> S; // S,s
+    qi::rule<Iterator, qi::locals<bool>, void(PathType&), SkipType> Q; // Q,q
+    qi::rule<Iterator, qi::locals<bool>, void(PathType&), SkipType> T; // T,t
+    qi::rule<Iterator, qi::locals<bool>, void(PathType&), SkipType> A; // A,a
+    qi::rule<Iterator, void(PathType&), SkipType> Z;                   // Z,z
+    qi::rule<Iterator, boost::fusion::vector2<double, double>(), SkipType> coord;
+};
+
+}}
 
 
 #endif // MAPNIK_SVG_PATH_GRAMMAR_HPP
diff --git a/include/mapnik/svg/svg_path_grammar_impl.hpp b/include/mapnik/svg/svg_path_grammar_impl.hpp
new file mode 100644
index 0000000..5d5fd1a
--- /dev/null
+++ b/include/mapnik/svg/svg_path_grammar_impl.hpp
@@ -0,0 +1,112 @@
+/*****************************************************************************
+ *
+ * This file is part of Mapnik (c++ mapping toolkit)
+ *
+ * Copyright (C) 2016 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
+ *
+ *****************************************************************************/
+
+// NOTE: This is an implementation header file and is only meant to be included
+//    from implementation files. It therefore doesn't have an include guard.
+
+// mapnik
+#include <mapnik/svg/svg_path_grammar.hpp>
+#include <mapnik/svg/svg_path_commands.hpp>
+
+// spirit
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
+#include <boost/spirit/include/phoenix_function.hpp>
+#include <boost/spirit/include/phoenix_core.hpp>
+#include <boost/spirit/include/phoenix_operator.hpp>
+#pragma GCC diagnostic pop
+
+namespace mapnik { namespace svg {
+
+using namespace boost::spirit;
+using namespace boost::phoenix;
+
+
+template <typename Iterator, typename PathType, typename SkipType>
+svg_path_grammar<Iterator, PathType, SkipType>::svg_path_grammar()
+    : svg_path_grammar::base_type(start)
+{
+    qi::_1_type _1;
+    qi::_2_type _2;
+    qi::_3_type _3;
+    qi::_4_type _4;
+    qi::_5_type _5;
+    qi::_a_type _a;
+    qi::lit_type lit;
+    qi::_r1_type _r1;
+    qi::double_type double_;
+    qi::int_type int_;
+    qi::no_case_type no_case;
+
+    // commands
+    function<move_to> move_to_;
+    function<hline_to> hline_to_;
+    function<vline_to> vline_to_;
+    function<line_to> line_to_;
+    function<curve4> curve4_;
+    function<curve4_smooth> curve4_smooth_;
+    function<curve3> curve3_;
+    function<curve3_smooth> curve3_smooth_;
+    function<arc_to> arc_to_;
+    function<close> close_;
+    //
+    start = +cmd(_r1);
+
+    cmd = M(_r1) >> *drawto_cmd(_r1);
+
+    drawto_cmd = L(_r1) | H(_r1) | V(_r1) | C(_r1) | S(_r1) | Q(_r1) | T(_r1) | A(_r1) | Z(_r1);
+
+    M = (lit('M')[_a = false] | lit('m')[_a = true]) >> coord[move_to_(_r1, _1, _a)] // move_to
+        >> *(-lit(',') >> coord[line_to_(_r1, _1, _a)]);                             // *line_to
+
+    H = (lit('H')[_a = false] | lit('h')[_a = true])
+        >> (double_[ hline_to_(_r1, _1,_a) ] % -lit(',')) ; // +hline_to
+
+    V = (lit('V')[_a = false] | lit('v')[_a = true])
+        >> (double_ [ vline_to_(_r1, _1,_a) ] % -lit(',')); // +vline_to
+
+    L = (lit('L')[_a = false] | lit('l')[_a = true])
+        >> (coord [ line_to_(_r1, _1, _a) ] % -lit(',')); // +line_to
+
+    C = (lit('C')[_a = false] | lit('c')[_a = true])
+        >> ((coord >> -lit(',') >> coord >> -lit(',') >> coord)[curve4_(_r1, _1, _2, _3, _a)] % -lit(',')); // +curve4
+
+    S = (lit('S')[_a = false] | lit('s')[_a = true])
+        >> ((coord >> -lit(',') >> coord) [ curve4_smooth_(_r1, _1,_2,_a) ] % -lit(',')); // +curve4_smooth (smooth curveto)
+
+    Q = (lit('Q')[_a = false] | lit('q')[_a = true])
+        >> ((coord >> -lit(',') >> coord) [ curve3_(_r1, _1,_2,_a) ] % -lit(',')); // +curve3 (quadratic-bezier-curveto)
+
+    T = (lit('T')[_a = false] | lit('t')[_a = true])
+        >> ((coord ) [ curve3_smooth_(_r1, _1,_a) ] % -lit(',')); // +curve3_smooth (smooth-quadratic-bezier-curveto)
+
+    A = (lit('A')[_a = false] | lit('a')[_a = true])
+        >> ((coord >> -lit(',') >> double_ >> -lit(',') >> int_ >> -lit(',') >> int_ >> -lit(',') >> coord)
+            [arc_to_(_r1, _1, _2, _3, _4, _5, _a)] % -lit(',')); // arc_to;
+
+    Z = no_case[lit('z')] [close_(_r1)]; // close path
+
+    coord = double_ >> -lit(',') >> double_;
+}
+
+} // namespace svg
+} // namespace mapnik
diff --git a/include/mapnik/svg/svg_path_parser.hpp b/include/mapnik/svg/svg_path_parser.hpp
index 35303f9..5633b2e 100644
--- a/include/mapnik/svg/svg_path_parser.hpp
+++ b/include/mapnik/svg/svg_path_parser.hpp
@@ -23,20 +23,32 @@
 #ifndef MAPNIK_SVG_PATH_PARSER_HPP
 #define MAPNIK_SVG_PATH_PARSER_HPP
 
+// mapnik
 #include <mapnik/config.hpp>
+#include <mapnik/svg/svg_converter.hpp>
+#include <mapnik/svg/svg_path_attributes.hpp>
+// stl
 #include <string>
 
-namespace mapnik { namespace svg {
+namespace mapnik {
+namespace svg {
 
-    template <typename PathType>
-    bool parse_path(const char * wkt, PathType & p);
+template <typename PathType>
+bool parse_path(const char* wkt, PathType& p);
 
-    template <typename PathType>
-    bool parse_points(const char * wkt, PathType & p);
+template <typename PathType>
+bool parse_points(const char* wkt, PathType& p);
+
+template <typename TransformType>
+bool MAPNIK_DECL parse_svg_transform(const char* wkt, TransformType& tr);
+
+//
+extern template bool MAPNIK_DECL parse_path<svg_converter_type>(const char*, svg_converter_type&);
+extern template bool MAPNIK_DECL parse_points<svg_converter_type>(const char*, svg_converter_type&);
+extern template bool MAPNIK_DECL parse_svg_transform<svg_converter_type>(const char*, svg_converter_type&);
+}
+}
 
-    template <typename TransformType>
-    bool MAPNIK_DECL parse_svg_transform(const char * wkt, TransformType & tr);
 
-}}
 
 #endif // MAPNIK_SVG_PATH_PARSER_HPP
diff --git a/include/mapnik/svg/svg_points_grammar.hpp b/include/mapnik/svg/svg_points_grammar.hpp
index 94602cc..afbe7ee 100644
--- a/include/mapnik/svg/svg_points_grammar.hpp
+++ b/include/mapnik/svg/svg_points_grammar.hpp
@@ -29,46 +29,22 @@
 #pragma GCC diagnostic push
 #include <mapnik/warning_ignore.hpp>
 #include <boost/spirit/include/qi.hpp>
-#include <boost/spirit/include/phoenix_function.hpp>
-#include <boost/spirit/include/phoenix_core.hpp>
-#include <boost/spirit/include/phoenix_operator.hpp>
 #pragma GCC diagnostic pop
 
 namespace mapnik { namespace svg {
 
-    using namespace boost::spirit;
-    using namespace boost::phoenix;
-
-    template <typename Iterator, typename SkipType, typename PathType>
-    struct svg_points_grammar : qi::grammar<Iterator,SkipType>
-    {
-        explicit svg_points_grammar(PathType & path)
-            : svg_points_grammar::base_type(start),
-              move_to_(move_to<PathType>(path)),
-              line_to_(line_to<PathType>(path)),
-              close_(close<PathType>(path))
-        {
-            qi::_1_type _1;
-            qi::lit_type lit;
-            qi::double_type double_;
-
-            start = coord[move_to_(_1,false)] // move_to
-                >> *(-lit(',') >> coord [ line_to_(_1,false) ] ); // *line_to
-
-            coord = double_ >> -lit(',') >> double_;
-        }
-
-        // rules
-        qi::rule<Iterator,SkipType> start;
-        qi::rule<Iterator,boost::fusion::vector2<double,double>(),SkipType> coord;
-
-        // commands
-        function<move_to<PathType> > move_to_;
-        function<line_to<PathType> > line_to_;
-        function<close<PathType> > close_;
-    };
-
-    }}
-
+using namespace boost::spirit;
+using namespace boost::phoenix;
+
+template <typename Iterator, typename PathType, typename SkipType>
+struct svg_points_grammar : qi::grammar<Iterator, void(PathType&), SkipType>
+{
+    // ctor
+    svg_points_grammar();
+    // rules
+    qi::rule<Iterator, void(PathType&), SkipType> start;
+    qi::rule<Iterator, boost::fusion::vector2<double, double>(), SkipType> coord;
+};
+}}
 
 #endif // SVG_POINTS_GRAMMAR_HPP
diff --git a/include/mapnik/svg/svg_points_grammar.hpp b/include/mapnik/svg/svg_points_grammar_impl.hpp
similarity index 54%
copy from include/mapnik/svg/svg_points_grammar.hpp
copy to include/mapnik/svg/svg_points_grammar_impl.hpp
index 94602cc..5d56f7e 100644
--- a/include/mapnik/svg/svg_points_grammar.hpp
+++ b/include/mapnik/svg/svg_points_grammar_impl.hpp
@@ -20,10 +20,10 @@
  *
  *****************************************************************************/
 
-#ifndef SVG_POINTS_GRAMMAR_HPP
-#define SVG_POINTS_GRAMMAR_HPP
-
+// NOTE: This is an implementation header file and is only meant to be included
+//    from implementation files. It therefore doesn't have an include guard.
 // mapnik
+#include <mapnik/svg/svg_points_grammar.hpp>
 #include <mapnik/svg/svg_path_commands.hpp>
 
 #pragma GCC diagnostic push
@@ -36,39 +36,26 @@
 
 namespace mapnik { namespace svg {
 
-    using namespace boost::spirit;
-    using namespace boost::phoenix;
-
-    template <typename Iterator, typename SkipType, typename PathType>
-    struct svg_points_grammar : qi::grammar<Iterator,SkipType>
-    {
-        explicit svg_points_grammar(PathType & path)
-            : svg_points_grammar::base_type(start),
-              move_to_(move_to<PathType>(path)),
-              line_to_(line_to<PathType>(path)),
-              close_(close<PathType>(path))
-        {
-            qi::_1_type _1;
-            qi::lit_type lit;
-            qi::double_type double_;
-
-            start = coord[move_to_(_1,false)] // move_to
-                >> *(-lit(',') >> coord [ line_to_(_1,false) ] ); // *line_to
-
-            coord = double_ >> -lit(',') >> double_;
-        }
-
-        // rules
-        qi::rule<Iterator,SkipType> start;
-        qi::rule<Iterator,boost::fusion::vector2<double,double>(),SkipType> coord;
-
-        // commands
-        function<move_to<PathType> > move_to_;
-        function<line_to<PathType> > line_to_;
-        function<close<PathType> > close_;
-    };
-
-    }}
-
-
-#endif // SVG_POINTS_GRAMMAR_HPP
+using namespace boost::spirit;
+using namespace boost::phoenix;
+
+template <typename Iterator, typename PathType, typename SkipType>
+svg_points_grammar<Iterator, PathType,SkipType>::svg_points_grammar()
+    : svg_points_grammar::base_type(start)
+{
+    qi::_1_type _1;
+    qi::_r1_type _r1;
+    qi::lit_type lit;
+    qi::double_type double_;
+    // commands
+    function<move_to> move_to_;
+    function<line_to> line_to_;
+    function<close> close_;
+
+    start = coord[move_to_(_r1, _1, false)] // move_to
+        >> *(-lit(',') >> coord [ line_to_(_r1, _1,false) ] ); // *line_to
+
+    coord = double_ >> -lit(',') >> double_;
+}
+
+}}
diff --git a/include/mapnik/svg/svg_renderer_agg.hpp b/include/mapnik/svg/svg_renderer_agg.hpp
index 3c714cd..d99575b 100644
--- a/include/mapnik/svg/svg_renderer_agg.hpp
+++ b/include/mapnik/svg/svg_renderer_agg.hpp
@@ -37,7 +37,8 @@
 #pragma GCC diagnostic pop
 #endif
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_path_storage.h"
 #include "agg_conv_transform.h"
 #include "agg_conv_stroke.h"
@@ -57,6 +58,7 @@
 #include "agg_gradient_lut.h"
 #include "agg_gamma_lut.h"
 #include "agg_span_interpolator_linear.h"
+#pragma GCC diagnostic pop
 
 namespace mapnik  {
 namespace svg {
diff --git a/include/mapnik/svg/svg_transform_grammar.hpp b/include/mapnik/svg/svg_transform_grammar.hpp
index 1465f3a..895112d 100644
--- a/include/mapnik/svg/svg_transform_grammar.hpp
+++ b/include/mapnik/svg/svg_transform_grammar.hpp
@@ -26,240 +26,31 @@
 // mapnik
 #include <mapnik/global.hpp>
 
-// agg
-#include <agg_trans_affine.h>
-
 #pragma GCC diagnostic push
 #include <mapnik/warning_ignore.hpp>
 #include <boost/spirit/include/qi.hpp>
-#include <boost/spirit/include/phoenix_function.hpp>
-#include <boost/spirit/include/phoenix_core.hpp>
-#include <boost/spirit/include/phoenix_operator.hpp>
-#include <boost/spirit/include/phoenix_object.hpp>
 #pragma GCC diagnostic pop
 
 namespace mapnik { namespace svg {
 
-    using namespace boost::spirit;
-    using namespace boost::fusion;
-    using namespace boost::phoenix;
-
-    inline double deg2rad(double d)
-    {
-        return M_PI * d / 180.0;
-    }
-
-    template <typename TransformType>
-    struct process_matrix
-    {
-        template <typename T0>
-        struct result
-        {
-            using type = void;
-        };
-
-        explicit process_matrix( TransformType & tr)
-            :tr_(tr) {}
-
-        void operator () (double a, double b, double c, double d, double e, double f) const
-        {
-            tr_ = agg::trans_affine(a,b,c,d,e,f) * tr_;
-        }
-
-        TransformType & tr_;
-    };
-
-    template <typename TransformType>
-    struct process_rotate
-    {
-        template <typename T0>
-        struct result
-        {
-            using type = void;
-        };
-
-        explicit process_rotate( TransformType & tr)
-            :tr_(tr) {}
-
-        template <typename T0,typename T1,typename T2>
-        void operator () (T0 a, T1 cx, T2 cy) const
-        {
-            if (cx == 0.0 && cy == 0.0)
-            {
-                tr_ = agg::trans_affine_rotation(deg2rad(a)) * tr_;
-            }
-            else
-            {
-                agg::trans_affine t = agg::trans_affine_translation(-cx,-cy);
-                t *= agg::trans_affine_rotation(deg2rad(a));
-                t *= agg::trans_affine_translation(cx, cy);
-                tr_ = t * tr_;
-            }
-        }
-
-        TransformType & tr_;
-    };
-
-    template <typename TransformType>
-    struct process_translate
-    {
-        template <typename T0>
-        struct result
-        {
-            using type = void;
-        };
-
-        explicit process_translate( TransformType & tr)
-            :tr_(tr) {}
-
-        template <typename T0,typename T1>
-        void operator () (T0 tx, T1 ty) const
-        {
-            if (ty) tr_ = agg::trans_affine_translation(tx,*ty) * tr_;
-            else tr_ = agg::trans_affine_translation(tx,0.0) * tr_;
-        }
-
-        TransformType & tr_;
-    };
-
-    template <typename TransformType>
-    struct process_scale
-    {
-        template <typename T0>
-        struct result
-        {
-            using type = void;
-        };
-
-        explicit process_scale( TransformType & tr)
-            :tr_(tr) {}
-
-        template <typename T0,typename T1>
-        void operator () (T0 sx, T1 sy) const
-        {
-            if (sy) tr_ = agg::trans_affine_scaling(sx,*sy) * tr_;
-            else tr_ = agg::trans_affine_scaling(sx,sx) * tr_;
-        }
-
-        TransformType & tr_;
-    };
-
-
-    template <typename TransformType>
-    struct process_skew
-    {
-        template <typename T0>
-        struct result
-        {
-            using type = void;
-        };
-
-        explicit process_skew( TransformType & tr)
-            :tr_(tr) {}
-
-        template <typename T0,typename T1>
-        void operator () (T0 skew_x, T1 skew_y) const
-        {
-            tr_ = agg::trans_affine_skewing(deg2rad(skew_x),deg2rad(skew_y)) * tr_;
-        }
-
-        TransformType & tr_;
-    };
-
-    // commented as this does not appear used and crashes clang when used with pch
-    /*
-      struct print_action
-      {
-      template <typename T>
-      void operator()(T const& c, qi::unused_type, qi::unused_type) const
-      {
-        MAPNIK_LOG_DEBUG(svg) << typeid(c).name();
-      }
-      };
-    */
-
-    template <typename Iterator, typename SkipType, typename TransformType>
-    struct svg_transform_grammar : qi::grammar<Iterator,SkipType>
-    {
-        explicit svg_transform_grammar(TransformType & tr)
-            : svg_transform_grammar::base_type(start),
-              matrix_action(process_matrix<TransformType>(tr)),
-              rotate_action(process_rotate<TransformType>(tr)),
-              translate_action(process_translate<TransformType>(tr)),
-              scale_action(process_scale<TransformType>(tr)),
-              skew_action(process_skew<TransformType>(tr))
-        {
-            qi::_1_type _1;
-            qi::_2_type _2;
-            qi::_3_type _3;
-            qi::_4_type _4;
-            qi::_5_type _5;
-            qi::_6_type _6;
-            qi::_a_type _a;
-            qi::_b_type _b;
-            qi::_c_type _c;
-            qi::lit_type lit;
-            qi::double_type double_;
-            qi::no_case_type no_case;
-
-            start =  +transform_ ;
-
-            transform_ = matrix | rotate | translate | scale | rotate | skewX | skewY ;
-
-            matrix = no_case[lit("matrix")]
-                >> lit('(')
-                >> (
-                    double_ >> -lit(',')
-                    >> double_ >> -lit(',')
-                    >> double_ >> -lit(',')
-                    >> double_ >> -lit(',')
-                    >> double_ >> -lit(',')
-                    >> double_) [ matrix_action(_1,_2,_3,_4,_5,_6) ]
-                >>  lit(')')
-                ;
-
-            translate = no_case[lit("translate")]
-                >> lit('(')
-                >> (double_ >> -lit(',')
-                    >> -double_) [ translate_action(_1,_2) ]
-                >> lit(')');
-
-            scale = no_case[lit("scale")]
-                >> lit('(')
-                >> (double_ >> -lit(',')
-                    >> -double_ )[ scale_action(_1,_2)]
-                >>  lit(')');
-
-            rotate = no_case[lit("rotate")]
-                >> lit('(')
-                >> double_[_a = _1] >> -lit(',')
-                >> -(double_ [_b = _1] >> -lit(',') >> double_[_c = _1])
-                >> lit(')') [ rotate_action(_a,_b,_c)];
-
-            skewX = no_case[lit("skewX")] >> lit('(') >> double_ [ skew_action(_1, 0.0)] >> lit(')');
-
-            skewY = no_case[lit("skewY")] >> lit('(') >> double_ [ skew_action(0.0, _1)] >> lit(')');
-
-        }
-
-        // rules
-        qi::rule<Iterator,SkipType> start;
-        qi::rule<Iterator,SkipType> transform_;
-        qi::rule<Iterator,SkipType> matrix;
-        qi::rule<Iterator,SkipType> translate;
-        qi::rule<Iterator,SkipType> scale;
-        qi::rule<Iterator,qi::locals<double,double,double>, SkipType> rotate;
-        qi::rule<Iterator,SkipType> skewX;
-        qi::rule<Iterator,SkipType> skewY;
-
-        // actions
-        function<process_matrix<TransformType> > matrix_action;
-        function<process_rotate<TransformType> > rotate_action;
-        function<process_translate<TransformType> > translate_action;
-        function<process_scale<TransformType> > scale_action;
-        function<process_skew<TransformType> > skew_action;
-    };
-
-    }}
+using namespace boost::spirit;
+
+template <typename Iterator, typename TransformType, typename SkipType>
+struct svg_transform_grammar : qi::grammar<Iterator, void(TransformType&), SkipType>
+{
+    // ctor
+    svg_transform_grammar();
+    // rules
+    qi::rule<Iterator, void(TransformType&), SkipType> start;
+    qi::rule<Iterator, void(TransformType&), SkipType> transform_;
+    qi::rule<Iterator, void(TransformType&), SkipType> matrix;
+    qi::rule<Iterator, void(TransformType&), SkipType> translate;
+    qi::rule<Iterator, void(TransformType&), SkipType> scale;
+    qi::rule<Iterator, qi::locals<double, double, double>, void(TransformType&), SkipType> rotate;
+    qi::rule<Iterator, void(TransformType&), SkipType> skewX;
+    qi::rule<Iterator, void(TransformType&), SkipType> skewY;
+};
+
+}}
 
 #endif // MAPNIK_SVG_TRANSFORM_GRAMMAR_HPP
diff --git a/include/mapnik/svg/svg_transform_grammar_impl.hpp b/include/mapnik/svg/svg_transform_grammar_impl.hpp
new file mode 100644
index 0000000..65c05ab
--- /dev/null
+++ b/include/mapnik/svg/svg_transform_grammar_impl.hpp
@@ -0,0 +1,172 @@
+/*****************************************************************************
+ *
+ * This file is part of Mapnik (c++ mapping toolkit)
+ *
+ * Copyright (C) 2015 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
+ *
+ *****************************************************************************/
+
+// NOTE: This is an implementation header file and is only meant to be included
+//    from implementation files. It therefore doesn't have an include guard.
+// mapnik
+#include <mapnik/svg/svg_transform_grammar.hpp>
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
+#include <boost/spirit/include/phoenix_function.hpp>
+#include <boost/spirit/include/phoenix_core.hpp>
+#include <boost/spirit/include/phoenix_operator.hpp>
+#include <boost/spirit/include/phoenix_object.hpp>
+#pragma GCC diagnostic pop
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
+#include <agg_trans_affine.h>
+#pragma GCC diagnostic pop
+
+namespace mapnik { namespace svg {
+
+using namespace boost::spirit;
+using namespace boost::fusion;
+using namespace boost::phoenix;
+
+inline double deg2rad(double d)
+{
+    return M_PI * d / 180.0;
+}
+
+struct process_matrix
+{
+    using result_type = void;
+    template <typename TransformType>
+    void operator () (TransformType & tr, double a, double b, double c, double d, double e, double f) const
+    {
+        tr = agg::trans_affine(a,b,c,d,e,f) * tr;
+    }
+};
+
+struct process_rotate
+{
+    using result_type = void;
+
+    template <typename TransformType, typename T0,typename T1,typename T2>
+    void operator () (TransformType & tr, T0 a, T1 cx, T2 cy) const
+    {
+        if (cx == 0.0 && cy == 0.0)
+        {
+            tr = agg::trans_affine_rotation(deg2rad(a)) * tr;
+        }
+        else
+        {
+            agg::trans_affine t = agg::trans_affine_translation(-cx,-cy);
+            t *= agg::trans_affine_rotation(deg2rad(a));
+            t *= agg::trans_affine_translation(cx, cy);
+            tr = t * tr;
+        }
+    }
+};
+
+struct process_translate
+{
+    using result_type = void;
+    template <typename TransformType, typename T0,typename T1>
+    void operator () (TransformType & tr, T0 tx, T1 ty) const
+    {
+        if (ty) tr = agg::trans_affine_translation(tx,*ty) * tr;
+        else tr = agg::trans_affine_translation(tx,0.0) * tr;
+    }
+};
+
+struct process_scale
+{
+    using result_type = void;
+    template <typename TransformType, typename T0,typename T1>
+    void operator () (TransformType & tr, T0 sx, T1 sy) const
+    {
+        if (sy) tr = agg::trans_affine_scaling(sx,*sy) * tr;
+        else tr = agg::trans_affine_scaling(sx,sx) * tr;
+    }
+};
+
+
+struct process_skew
+{
+    using result_type = void;
+
+    template <typename TransformType, typename T0,typename T1>
+    void operator () (TransformType & tr, T0 skew_x, T1 skew_y) const
+    {
+        tr = agg::trans_affine_skewing(deg2rad(skew_x),deg2rad(skew_y)) * tr;
+    }
+};
+
+template <typename Iterator, typename TransformType, typename SkipType>
+svg_transform_grammar<Iterator, TransformType, SkipType>::svg_transform_grammar()
+    : svg_transform_grammar::base_type(start)
+{
+    qi::_1_type _1;
+    qi::_2_type _2;
+    qi::_3_type _3;
+    qi::_4_type _4;
+    qi::_5_type _5;
+    qi::_6_type _6;
+    qi::_a_type _a;
+    qi::_b_type _b;
+    qi::_c_type _c;
+    qi::_r1_type _r1;
+    qi::lit_type lit;
+    qi::double_type double_;
+    qi::no_case_type no_case;
+
+    // actions
+    function<process_matrix> matrix_action;
+    function<process_rotate> rotate_action;
+    function<process_translate> translate_action;
+    function<process_scale> scale_action;
+    function<process_skew> skew_action;
+
+    start =  +transform_(_r1) ;
+
+    transform_ = matrix(_r1) | rotate(_r1) | translate(_r1) | scale(_r1) | rotate(_r1) | skewX(_r1) | skewY (_r1) ;
+
+    matrix = no_case[lit("matrix")] >> lit('(')
+                                    >> (double_ >> -lit(',')
+                                        >> double_ >> -lit(',')
+                                        >> double_ >> -lit(',')
+                                        >> double_ >> -lit(',')
+                                        >> double_ >> -lit(',')
+                                        >> double_)[matrix_action(_r1, _1, _2, _3, _4, _5, _6)] >> lit(')');
+
+    translate = no_case[lit("translate")]
+        >> lit('(') >> (double_ >> -lit(',') >> -double_)[translate_action(_r1, _1, _2)] >> lit(')');
+
+    scale = no_case[lit("scale")]
+        >> lit('(') >> (double_ >> -lit(',') >> -double_)[scale_action(_r1, _1, _2)] >> lit(')');
+
+    rotate = no_case[lit("rotate")]
+        >> lit('(')
+        >> double_[_a = _1] >> -lit(',')
+        >> -(double_ [_b = _1] >> -lit(',') >> double_[_c = _1])
+        >> lit(')') [ rotate_action(_r1, _a,_b,_c)];
+
+    skewX = no_case[lit("skewX")] >> lit('(') >> double_ [ skew_action(_r1, _1, 0.0)] >> lit(')');
+
+    skewY = no_case[lit("skewY")] >> lit('(') >> double_ [ skew_action(_r1, 0.0, _1)] >> lit(')');
+
+}
+
+}}
diff --git a/include/mapnik/symbolizer.hpp b/include/mapnik/symbolizer.hpp
index 39d650d..9308ecd 100644
--- a/include/mapnik/symbolizer.hpp
+++ b/include/mapnik/symbolizer.hpp
@@ -51,8 +51,10 @@
 #include <map>
 #include <tuple>
 
-// boost
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/optional.hpp>
+#pragma GCC diagnostic pop
 
 namespace mapnik
 {
diff --git a/include/mapnik/text/face.hpp b/include/mapnik/text/face.hpp
index 87692ca..3d797a1 100644
--- a/include/mapnik/text/face.hpp
+++ b/include/mapnik/text/face.hpp
@@ -27,7 +27,9 @@
 #include <mapnik/text/glyph_info.hpp>
 #include <mapnik/util/noncopyable.hpp>
 
-// freetype2
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
+
 extern "C"
 {
 #include <ft2build.h>
@@ -35,6 +37,8 @@ extern "C"
 #include FT_STROKER_H
 }
 
+#pragma GCC diagnostic pop
+
 //stl
 #include <memory>
 #include <string>
diff --git a/include/mapnik/text/font_feature_settings.hpp b/include/mapnik/text/font_feature_settings.hpp
index 9d945fb..8bc3e33 100644
--- a/include/mapnik/text/font_feature_settings.hpp
+++ b/include/mapnik/text/font_feature_settings.hpp
@@ -31,8 +31,11 @@
 #include <memory>
 #include <limits>
 #include <ostream>
-// harfbuzz
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <harfbuzz/hb.h>
+#pragma GCC diagnostic pop
 
 // EqualityComparable
 inline bool operator==(hb_feature_t const& lhs, hb_feature_t const& rhs)
@@ -86,7 +89,10 @@ inline bool operator==(font_feature_settings const& lhs, font_feature_settings c
 constexpr unsigned int font_feature_range_global_start = 0u;
 static const unsigned int font_feature_range_global_end = std::numeric_limits<unsigned int>::max();
 
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 constexpr hb_feature_t font_feature_liga_off = { HB_TAG('l', 'i', 'g', 'a'), 0, font_feature_range_global_start, font_feature_range_global_end };
+#pragma GCC diagnostic pop
 
 } // mapnik namespace
 
diff --git a/include/mapnik/text/formatting/layout.hpp b/include/mapnik/text/formatting/layout.hpp
index dd7f4b0..6892ce7 100644
--- a/include/mapnik/text/formatting/layout.hpp
+++ b/include/mapnik/text/formatting/layout.hpp
@@ -26,7 +26,10 @@
 #include <mapnik/text/formatting/base.hpp>
 #include <mapnik/text/text_properties.hpp>
 
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/optional.hpp>
+#pragma GCC diagnostic pop
 
 namespace mapnik { namespace formatting {
 
diff --git a/include/mapnik/text/glyph_positions.hpp b/include/mapnik/text/glyph_positions.hpp
index 72314c3..aa08e33 100644
--- a/include/mapnik/text/glyph_positions.hpp
+++ b/include/mapnik/text/glyph_positions.hpp
@@ -30,8 +30,10 @@
 #include <mapnik/marker_cache.hpp>
 #include <mapnik/text/glyph_info.hpp>
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_trans_affine.h"
+#pragma GCC diagnostic pop
 
 //stl
 #include <vector>
diff --git a/include/mapnik/text/harfbuzz_shaper.hpp b/include/mapnik/text/harfbuzz_shaper.hpp
index 0f23bc8..8b574b0 100644
--- a/include/mapnik/text/harfbuzz_shaper.hpp
+++ b/include/mapnik/text/harfbuzz_shaper.hpp
@@ -36,12 +36,12 @@
 #include <list>
 #include <type_traits>
 
-// harfbuzz
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <harfbuzz/hb.h>
 #include <harfbuzz/hb-ft.h>
-
-// icu
 #include <unicode/uscript.h>
+#pragma GCC diagnostic pop
 
 namespace mapnik
 {
diff --git a/include/mapnik/text/icu_shaper.hpp b/include/mapnik/text/icu_shaper.hpp
index bcd822b..39bc590 100644
--- a/include/mapnik/text/icu_shaper.hpp
+++ b/include/mapnik/text/icu_shaper.hpp
@@ -36,11 +36,12 @@
 // stl
 #include <list>
 
-// icu
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <unicode/unistr.h>
 #include <unicode/ushape.h>
 #include <unicode/schriter.h>
-
+#pragma GCC diagnostic pop
 
 namespace mapnik
 {
diff --git a/include/mapnik/text/itemizer.hpp b/include/mapnik/text/itemizer.hpp
index b858944..5087ce0 100644
--- a/include/mapnik/text/itemizer.hpp
+++ b/include/mapnik/text/itemizer.hpp
@@ -34,10 +34,12 @@
 #include <list>
 #include <vector>
 
-// ICU
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <unicode/unistr.h>
 #include <unicode/uscript.h>
 #include <unicode/ubidi.h>
+#pragma GCC diagnostic pop
 
 namespace mapnik
 {
diff --git a/include/mapnik/text/properties_util.hpp b/include/mapnik/text/properties_util.hpp
index 0fff84e..5b92ed3 100644
--- a/include/mapnik/text/properties_util.hpp
+++ b/include/mapnik/text/properties_util.hpp
@@ -26,11 +26,14 @@
 #include <mapnik/symbolizer_base.hpp>
 #include <mapnik/xml_node.hpp>
 #include <mapnik/config_error.hpp>
-#include <boost/optional.hpp>
+
 #include <string>
 
-// boost
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
+#include <boost/optional.hpp>
 #include <boost/property_tree/ptree_fwd.hpp>
+#pragma GCC diagnostic pop
 
 namespace mapnik { namespace detail {
 
diff --git a/include/mapnik/text/renderer.hpp b/include/mapnik/text/renderer.hpp
index a4cd76e..692ada3 100644
--- a/include/mapnik/text/renderer.hpp
+++ b/include/mapnik/text/renderer.hpp
@@ -28,7 +28,10 @@
 #include <mapnik/image_compositing.hpp>
 #include <mapnik/symbolizer_enumerations.hpp>
 #include <mapnik/util/noncopyable.hpp>
-// agg
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
+
 #include <agg_trans_affine.h>
 
 // freetype2
@@ -39,6 +42,8 @@ extern "C"
 #include FT_STROKER_H
 }
 
+#pragma GCC diagnostic pop
+
 namespace mapnik
 {
 
diff --git a/include/mapnik/text/scrptrun.hpp b/include/mapnik/text/scrptrun.hpp
index 67942b0..7c8063b 100644
--- a/include/mapnik/text/scrptrun.hpp
+++ b/include/mapnik/text/scrptrun.hpp
@@ -17,9 +17,12 @@
 #ifndef __SCRPTRUN_H
 #define __SCRPTRUN_H
 
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <unicode/utypes.h>
 #include <unicode/uobject.h>
 #include <unicode/uscript.h>
+#pragma GCC diagnostic pop
 
 struct ScriptRecord
 {
diff --git a/include/mapnik/text/symbolizer_helpers.hpp b/include/mapnik/text/symbolizer_helpers.hpp
index 8a44bdd..6d6fbdc 100644
--- a/include/mapnik/text/symbolizer_helpers.hpp
+++ b/include/mapnik/text/symbolizer_helpers.hpp
@@ -59,7 +59,7 @@ struct placement_finder_adapter
 
 };
 
-using vertex_converter_type = vertex_converter<clip_line_tag , transform_tag, affine_transform_tag, simplify_tag, smooth_tag>;
+using vertex_converter_type = vertex_converter<clip_line_tag, transform_tag, affine_transform_tag, simplify_tag, smooth_tag>;
 
 class base_symbolizer_helper
 {
diff --git a/include/mapnik/text/text_properties.hpp b/include/mapnik/text/text_properties.hpp
index 654921e..511ba3a 100644
--- a/include/mapnik/text/text_properties.hpp
+++ b/include/mapnik/text/text_properties.hpp
@@ -36,9 +36,11 @@
 // stl
 #include <map>
 
-// boost
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/optional.hpp>
 #include <boost/property_tree/ptree_fwd.hpp>
+#pragma GCC diagnostic pop
 
 namespace mapnik {
 
diff --git a/include/mapnik/tiff_io.hpp b/include/mapnik/tiff_io.hpp
index df2b25a..b801429 100644
--- a/include/mapnik/tiff_io.hpp
+++ b/include/mapnik/tiff_io.hpp
@@ -28,6 +28,9 @@
 #include <mapnik/image_any.hpp>
 #include <mapnik/util/variant.hpp>
 
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
+
 extern "C"
 {
 #include <tiffio.h>
@@ -35,6 +38,9 @@ extern "C"
 #define RealTIFFClose TIFFClose
 }
 
+#pragma GCC diagnostic pop
+
+
 //std
 #include <memory>
 
diff --git a/include/mapnik/transform_expression.hpp b/include/mapnik/transform_expression.hpp
index 9714b1e..b43f691 100644
--- a/include/mapnik/transform_expression.hpp
+++ b/include/mapnik/transform_expression.hpp
@@ -30,11 +30,13 @@
 #include <mapnik/expression_node_types.hpp>
 #include <mapnik/expression_node.hpp>
 #include <mapnik/util/variant.hpp>
-// boost
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/optional.hpp>
-// fusion
 #include <boost/fusion/include/at.hpp>
 #include <boost/fusion/include/vector.hpp>
+#pragma GCC diagnostic pop
 
 // stl
 #include <vector>
diff --git a/include/mapnik/transform_processor.hpp b/include/mapnik/transform_processor.hpp
index 2e4bfa3..b1d8eab 100644
--- a/include/mapnik/transform_processor.hpp
+++ b/include/mapnik/transform_processor.hpp
@@ -29,8 +29,11 @@
 #include <mapnik/transform_expression.hpp>
 #include <mapnik/expression_evaluator.hpp>
 #include <mapnik/util/variant.hpp>
-// agg
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include <agg_trans_affine.h>
+#pragma GCC diagnostic pop
 
 // stl
 #include <cmath>
diff --git a/include/mapnik/unicode.hpp b/include/mapnik/unicode.hpp
index 59401ab..f3b270c 100644
--- a/include/mapnik/unicode.hpp
+++ b/include/mapnik/unicode.hpp
@@ -45,6 +45,10 @@ public:
 private:
     UConverter * conv_;
 };
+
+// convinience method
+void MAPNIK_DECL to_utf8(mapnik::value_unicode_string const& input, std::string & target);
+
 }
 
 #endif // MAPNIK_UNICODE_HPP
diff --git a/include/mapnik/util/const_rendering_buffer.hpp b/include/mapnik/util/const_rendering_buffer.hpp
index 360eea5..97b98ca 100644
--- a/include/mapnik/util/const_rendering_buffer.hpp
+++ b/include/mapnik/util/const_rendering_buffer.hpp
@@ -25,7 +25,10 @@
 
 #include <mapnik/safe_cast.hpp>
 
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_basics.h"
+#pragma GCC diagnostic pop
 
 #include <cstdint>
 
diff --git a/include/mapnik/util/file_io.hpp b/include/mapnik/util/file_io.hpp
index d3ffe90..b8bc22f 100644
--- a/include/mapnik/util/file_io.hpp
+++ b/include/mapnik/util/file_io.hpp
@@ -58,11 +58,16 @@ public:
         }
      }
 
-    inline bool open() const
+    inline bool is_open() const
     {
         return file_ ? true : false;
     }
 
+    explicit operator bool() const
+    {
+        return this->is_open();
+    }
+
     inline std::FILE * get() const
     {
         return file_.get();
diff --git a/include/mapnik/util/geometry_to_ds_type.hpp b/include/mapnik/util/geometry_to_ds_type.hpp
index 58fc89d..e09808f 100644
--- a/include/mapnik/util/geometry_to_ds_type.hpp
+++ b/include/mapnik/util/geometry_to_ds_type.hpp
@@ -28,8 +28,13 @@
 #include <mapnik/geometry.hpp>
 #include <mapnik/datasource_geometry_type.hpp>
 #include <mapnik/util/variant.hpp>
-// boost
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/optional.hpp>
+#include <boost/fusion/include/at.hpp>
+#include <boost/fusion/include/vector.hpp>
+#pragma GCC diagnostic pop
 
 namespace mapnik { namespace util {
 
diff --git a/include/mapnik/util/geometry_to_geojson.hpp b/include/mapnik/util/geometry_to_geojson.hpp
index 5cccb09..71c867e 100644
--- a/include/mapnik/util/geometry_to_geojson.hpp
+++ b/include/mapnik/util/geometry_to_geojson.hpp
@@ -24,18 +24,13 @@
 #define MAPNIK_GEOMETRY_TO_GEOJSON_HPP
 
 // mapnik
+#include <mapnik/geometry.hpp>
 
-#include <mapnik/json/geometry_generator_grammar.hpp>
+#include <string>
 
 namespace mapnik { namespace util {
 
-inline bool to_geojson(std::string & json, mapnik::geometry::geometry<double> const& geom)
-{
-    using sink_type = std::back_insert_iterator<std::string>;
-    static const mapnik::json::geometry_generator_grammar<sink_type, mapnik::geometry::geometry<double> > grammar;
-    sink_type sink(json);
-    return boost::spirit::karma::generate(sink, grammar, geom);
-}
+bool to_geojson(std::string & json, mapnik::geometry::geometry<double> const& geom);
 
 }}
 
diff --git a/include/mapnik/util/path_iterator.hpp b/include/mapnik/util/path_iterator.hpp
index 319c346..19b69ce 100644
--- a/include/mapnik/util/path_iterator.hpp
+++ b/include/mapnik/util/path_iterator.hpp
@@ -26,8 +26,11 @@
 // mapnik
 #include <mapnik/global.hpp>
 #include <mapnik/path.hpp>
-// boost
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/iterator/iterator_facade.hpp>
+#pragma GCC diagnostic pop
 
 // stl
 #include <tuple>
diff --git a/include/mapnik/util/spatial_index.hpp b/include/mapnik/util/spatial_index.hpp
index d207dba..7206677 100644
--- a/include/mapnik/util/spatial_index.hpp
+++ b/include/mapnik/util/spatial_index.hpp
@@ -47,12 +47,13 @@ bool check_spatial_index(InputStream& in)
     return (std::strncmp(header, "mapnik-index",12) == 0);
 }
 
-template <typename Value, typename Filter, typename InputStream>
+template <typename Value, typename Filter, typename InputStream, typename BBox = box2d<double> >
 class spatial_index
 {
+    using bbox_type = BBox;
 public:
     static void query(Filter const& filter, InputStream& in,std::vector<Value>& pos);
-    static box2d<double> bounding_box( InputStream& in );
+    static bbox_type bounding_box( InputStream& in );
     static void query_first_n(Filter const& filter, InputStream & in, std::vector<Value>& pos, std::size_t count);
 private:
     spatial_index();
@@ -60,25 +61,25 @@ private:
     spatial_index(spatial_index const&);
     spatial_index& operator=(spatial_index const&);
     static int read_ndr_integer(InputStream& in);
-    static void read_envelope(InputStream& in, box2d<double>& envelope);
+    static void read_envelope(InputStream& in, bbox_type& envelope);
     static void query_node(Filter const& filter, InputStream& in, std::vector<Value> & results);
     static void query_first_n_impl(Filter const& filter, InputStream& in, std::vector<Value> & results, std::size_t count);
 };
 
-template <typename Value, typename Filter, typename InputStream>
-box2d<double> spatial_index<Value, Filter, InputStream>::bounding_box(InputStream& in)
+template <typename Value, typename Filter, typename InputStream, typename BBox>
+BBox spatial_index<Value, Filter, InputStream, BBox>::bounding_box(InputStream& in)
 {
     static_assert(std::is_standard_layout<Value>::value, "Values stored in quad-tree must be standard layout type");
     if (!check_spatial_index(in)) throw std::runtime_error("Invalid index file (regenerate with shapeindex)");
     in.seekg(16 + 4, std::ios::beg);
-    box2d<double> box;
+    typename spatial_index<Value, Filter, InputStream, BBox>::bbox_type box;
     read_envelope(in, box);
     in.seekg(0, std::ios::beg);
     return box;
 }
 
-template <typename Value, typename Filter, typename InputStream>
-void spatial_index<Value, Filter, InputStream>::query(Filter const& filter, InputStream& in, std::vector<Value>& results)
+template <typename Value, typename Filter, typename InputStream, typename BBox>
+void spatial_index<Value, Filter, InputStream, BBox>::query(Filter const& filter, InputStream& in, std::vector<Value>& results)
 {
     static_assert(std::is_standard_layout<Value>::value, "Values stored in quad-tree must be standard layout type");
     if (!check_spatial_index(in)) throw std::runtime_error("Invalid index file (regenerate with shapeindex)");
@@ -86,11 +87,11 @@ void spatial_index<Value, Filter, InputStream>::query(Filter const& filter, Inpu
     query_node(filter, in, results);
 }
 
-template <typename Value, typename Filter, typename InputStream>
-void spatial_index<Value, Filter, InputStream>::query_node(Filter const& filter, InputStream& in, std::vector<Value>& results)
+template <typename Value, typename Filter, typename InputStream, typename BBox>
+void spatial_index<Value, Filter, InputStream, BBox>::query_node(Filter const& filter, InputStream& in, std::vector<Value>& results)
 {
     int offset = read_ndr_integer(in);
-    box2d<double> node_ext;
+    typename spatial_index<Value, Filter, InputStream, BBox>::bbox_type node_ext;
     read_envelope(in, node_ext);
     int num_shapes = read_ndr_integer(in);
     if (!filter.pass(node_ext))
@@ -113,8 +114,8 @@ void spatial_index<Value, Filter, InputStream>::query_node(Filter const& filter,
     }
 }
 
-template <typename Value, typename Filter, typename InputStream>
-void spatial_index<Value, Filter, InputStream>::query_first_n(Filter const& filter, InputStream& in, std::vector<Value>& results, std::size_t count)
+template <typename Value, typename Filter, typename InputStream, typename BBox>
+void spatial_index<Value, Filter, InputStream, BBox>::query_first_n(Filter const& filter, InputStream& in, std::vector<Value>& results, std::size_t count)
 {
     static_assert(std::is_standard_layout<Value>::value, "Values stored in quad-tree must be standard layout type");
     if (!check_spatial_index(in)) throw std::runtime_error("Invalid index file (regenerate with shapeindex)");
@@ -122,12 +123,12 @@ void spatial_index<Value, Filter, InputStream>::query_first_n(Filter const& filt
     query_first_n_impl(filter, in, results, count);
 }
 
-template <typename Value, typename Filter, typename InputStream>
-void spatial_index<Value, Filter, InputStream>::query_first_n_impl(Filter const& filter, InputStream& in, std::vector<Value>& results, std::size_t count)
+template <typename Value, typename Filter, typename InputStream, typename BBox>
+void spatial_index<Value, Filter, InputStream, BBox>::query_first_n_impl(Filter const& filter, InputStream& in, std::vector<Value>& results, std::size_t count)
 {
     if (results.size() == count) return;
     int offset = read_ndr_integer(in);
-    box2d<double> node_ext;
+    typename spatial_index<Value, Filter, InputStream, BBox>::bbox_type node_ext;
     read_envelope(in, node_ext);
     int num_shapes = read_ndr_integer(in);
     if (!filter.pass(node_ext))
@@ -149,16 +150,16 @@ void spatial_index<Value, Filter, InputStream>::query_first_n_impl(Filter const&
     }
 }
 
-template <typename Value, typename Filter, typename InputStream>
-int spatial_index<Value, Filter, InputStream>::read_ndr_integer(InputStream& in)
+template <typename Value, typename Filter, typename InputStream, typename BBox>
+int spatial_index<Value, Filter, InputStream, BBox>::read_ndr_integer(InputStream& in)
 {
     char b[4];
     in.read(b, 4);
     return (b[0] & 0xff) | (b[1] & 0xff) << 8 | (b[2] & 0xff) << 16 | (b[3] & 0xff) << 24;
 }
 
-template <typename Value, typename Filter, typename InputStream>
-void spatial_index<Value, Filter, InputStream>::read_envelope(InputStream& in, box2d<double>& envelope)
+template <typename Value, typename Filter, typename InputStream, typename BBox>
+void spatial_index<Value, Filter, InputStream, BBox>::read_envelope(InputStream& in, BBox& envelope)
 {
     in.read(reinterpret_cast<char*>(&envelope), sizeof(envelope));
 }
diff --git a/include/mapnik/util/variant.hpp b/include/mapnik/util/variant.hpp
index 61832a0..05dddec 100644
--- a/include/mapnik/util/variant.hpp
+++ b/include/mapnik/util/variant.hpp
@@ -24,9 +24,13 @@
 #define MAPNIK_UTIL_VARIANT_HPP
 
 #include <mapnik/config.hpp>
-#include <boost/mpl/vector.hpp> // spirit support
 #include <mapbox/variant/variant.hpp>
 
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
+#include <boost/mpl/vector.hpp> // spirit support
+#pragma GCC diagnostic pop
+
 namespace mapnik { namespace util {
 
 template <typename T>
diff --git a/include/mapnik/value.hpp b/include/mapnik/value.hpp
index c6a95d3..3bd59b4 100644
--- a/include/mapnik/value.hpp
+++ b/include/mapnik/value.hpp
@@ -24,805 +24,25 @@
 #define MAPNIK_VALUE_HPP
 
 // mapnik
+#include <mapnik/config.hpp>
 #include <mapnik/value_types.hpp>
 #include <mapnik/value_hash.hpp>
-#include <mapnik/util/conversions.hpp>
 #include <mapnik/util/variant.hpp>
 
-// stl
-#include <string>
-#include <cmath>
-#include <memory>
-
-#include <iosfwd>
-#include <cstddef>
-#include <new>
-#include <type_traits>
-
-// icu
-#include <unicode/unistr.h>
-#include <unicode/ustring.h>
 
 namespace mapnik {
 
 using value_base = util::variant<value_null, value_bool, value_integer,value_double, value_unicode_string>;
 
-inline void to_utf8(mapnik::value_unicode_string const& input, std::string & target)
-{
-    target.clear(); // mimic previous target.assign(...) semantics
-    input.toUTF8String(target); // this appends to target
-}
-
-namespace detail {
-
-namespace {
-template <typename T, typename U>
-struct both_arithmetic : std::integral_constant<bool,
-                                             std::is_arithmetic<T>::value &&
-                                             std::is_arithmetic<U>::value > {};
-
-struct equals
-{
-    static bool apply(value_null, value_unicode_string const& rhs)
-    {
-        return false;
-    }
-
-    template <typename T>
-    static auto apply(T const& lhs, T const& rhs)
-        -> decltype(lhs == rhs)
-    {
-        return lhs == rhs;
-    }
-};
-
-struct not_equal
-{
-    // back compatibility shim to equate empty string with null for != test
-    // https://github.com/mapnik/mapnik/issues/1859
-    // TODO - consider removing entire specialization at Mapnik 3.1.x
-    static bool apply(value_null, value_unicode_string const& rhs)
-    {
-        if (rhs.isEmpty()) return false;
-        return true;
-    }
-
-    template <typename T>
-    static auto apply(T const& lhs, T const& rhs)
-        ->decltype(lhs != rhs)
-    {
-        return lhs != rhs;
-    }
-};
-
-struct greater_than
-{
-    static bool apply(value_null, value_unicode_string const& rhs)
-    {
-        return false;
-    }
-
-    template <typename T>
-    static auto  apply(T const& lhs, T const& rhs)
-        ->decltype(lhs > rhs)
-    {
-        return lhs > rhs;
-    }
-};
-
-struct greater_or_equal
-{
-    static bool apply(value_null, value_unicode_string const& rhs)
-    {
-        return false;
-    }
-
-    template <typename T>
-    static auto apply(T const& lhs, T const& rhs)
-        ->decltype(lhs >= rhs)
-    {
-        return lhs >= rhs;
-    }
-};
-
-struct less_than
-{
-    static bool apply(value_null, value_unicode_string const& rhs)
-    {
-        return false;
-    }
-
-    template <typename T>
-    static auto apply(T const& lhs, T const& rhs)
-         ->decltype(lhs < rhs)
-    {
-        return lhs < rhs;
-    }
-};
-
-struct less_or_equal
-{
-    static bool apply(value_null, value_unicode_string const& rhs)
-    {
-        return false;
-    }
-
-    template <typename T>
-    static auto apply(T const& lhs, T const& rhs)
-        ->decltype(lhs <= rhs)
-    {
-        return lhs <= rhs;
-    }
-};
-
-}
-
-template <typename Op, bool default_result>
-struct comparison
-{
-    // special case for unicode_strings (fixes MSVC C4800)
-    bool operator() (value_unicode_string const& lhs,
-                     value_unicode_string const& rhs) const
-    {
-        return Op::apply(lhs, rhs) ? true : false;
-    }
-
-    //////////////////////////////////////////////////////////////////////////
-    // special case for unicode_string and value_null
-    //////////////////////////////////////////////////////////////////////////
-
-    bool operator() (value_null const& lhs, value_unicode_string const& rhs) const
-    {
-        return Op::apply(lhs, rhs);
-    }
-    //////////////////////////////////////////////////////////////////////////
-
-
-    // same types
-    template <typename T>
-    bool operator() (T lhs, T rhs) const
-    {
-        return Op::apply(lhs, rhs);
-    }
-
-    // both types are arithmetic - promote to the common type
-    template <typename T, typename U, typename std::enable_if<both_arithmetic<T,U>::value, int>::type = 0>
-    bool operator() (T const& lhs, U const& rhs) const
-    {
-        using common_type = typename std::common_type<T,U>::type;
-        return Op::apply(static_cast<common_type>(lhs),static_cast<common_type>(rhs));
-    }
-
-    //
-    template <typename T, typename U, typename std::enable_if<!both_arithmetic<T,U>::value, int>::type = 0>
-    bool operator() (T const& lhs, U const& rhs) const
-    {
-        return default_result;
-    }
-};
-
-template <typename V>
-struct add
-{
-    using value_type = V;
-    value_type operator() (value_unicode_string const& lhs ,
-                           value_unicode_string const& rhs ) const
-    {
-        return lhs + rhs;
-    }
-
-    value_type operator() (value_null const& lhs ,
-                           value_null const& rhs) const
-    {
-        return lhs;
-    }
-
-    value_type operator() (value_unicode_string const& lhs, value_null) const
-    {
-        return lhs;
-    }
-
-    value_type operator() (value_null, value_unicode_string const& rhs) const
-    {
-        return rhs;
-    }
-
-    template <typename L>
-    value_type operator() (L const& lhs, value_null const&) const
-    {
-        return lhs;
-    }
-
-    template <typename R>
-    value_type operator() (value_null const&, R const& rhs) const
-    {
-        return rhs;
-    }
-
-    template <typename L>
-    value_type operator() (L const& lhs , value_unicode_string const& rhs) const
-    {
-        std::string val;
-        if (util::to_string(val,lhs))
-            return value_unicode_string(val.c_str()) + rhs;
-        return rhs;
-    }
-
-    template <typename R>
-    value_type operator() (value_unicode_string const& lhs, R const& rhs) const
-    {
-        std::string val;
-        if (util::to_string(val,rhs))
-            return lhs + value_unicode_string(val.c_str());
-        return lhs;
-    }
-
-    template <typename T1, typename T2>
-    value_type operator() (T1 const& lhs, T2 const& rhs) const
-    {
-        return typename std::common_type<T1,T2>::type{ lhs + rhs };
-    }
-
-    value_type operator() (value_bool lhs, value_bool rhs) const
-    {
-        return value_integer(lhs + rhs);
-    }
-};
-
-template <typename V>
-struct sub
-{
-    using value_type = V;
-
-    value_type operator() (value_null const& lhs ,
-                           value_null const& rhs) const
-    {
-        return lhs;
-    }
-
-    value_type operator() (value_null, value_unicode_string const& rhs) const
-    {
-        return rhs;
-    }
-    value_type operator() (value_unicode_string const& lhs, value_null) const
-    {
-        return lhs;
-    }
-
-    template <typename R>
-    value_type operator() (value_unicode_string const& lhs, R const&) const
-    {
-        return lhs;
-    }
-
-    template <typename L>
-    value_type operator() (L const&, value_unicode_string const& rhs) const
-    {
-        return rhs;
-    }
-
-    template <typename L>
-    value_type operator() (L const& lhs, value_null const&) const
-    {
-        return lhs;
-    }
-
-    template <typename R>
-    value_type operator() (value_null const&, R const& rhs) const
-    {
-        return rhs;
-    }
-
-    template <typename T>
-    value_type operator() (T lhs, T rhs) const
-    {
-        return lhs - rhs ;
-    }
-
-    value_type operator() (value_unicode_string const&,
-                           value_unicode_string const&) const
-    {
-        return value_type();
-    }
-
-    template <typename T1, typename T2>
-    value_type operator() (T1 const& lhs, T2 const& rhs) const
-    {
-        return typename std::common_type<T1,T2>::type{ lhs - rhs };
-    }
-
-
-    value_type operator() (value_bool lhs, value_bool rhs) const
-    {
-        return value_integer(lhs - rhs);
-    }
-};
-
-template <typename V>
-struct mult
-{
-    using value_type = V;
-
-    value_type operator() (value_null const& lhs ,
-                           value_null const& rhs) const
-    {
-        return lhs;
-    }
-
-    value_type operator() (value_unicode_string const& lhs, value_null) const
-    {
-        return lhs;
-    }
-
-    value_type operator() (value_null, value_unicode_string const& rhs) const
-    {
-        return rhs;
-    }
-
-    template <typename L>
-    value_type operator() (L const& lhs, value_null const&) const
-    {
-        return lhs;
-    }
-
-    template <typename R>
-    value_type operator() (value_null const&, R const& rhs) const
-    {
-        return rhs;
-    }
-
-    template <typename R>
-    value_type operator() (value_unicode_string const& lhs, R const&) const
-    {
-        return lhs;
-    }
-
-    template <typename L>
-    value_type operator() (L const&, value_unicode_string const& rhs) const
-    {
-        return rhs;
-    }
-
-    template <typename T>
-    value_type operator() (T lhs, T rhs) const
-    {
-        return lhs * rhs;
-    }
-
-    value_type operator() (value_unicode_string const&,
-                           value_unicode_string const&) const
-    {
-        return value_type();
-    }
-
-    template <typename T1, typename T2>
-    value_type operator() (T1 const& lhs, T2 const& rhs) const
-    {
-        return typename std::common_type<T1,T2>::type{ lhs * rhs };
-    }
-
-    value_type operator() (value_bool lhs, value_bool rhs) const
-    {
-        return value_integer(lhs * rhs);
-    }
-};
-
-template <typename V>
-struct div
-{
-    using value_type = V;
-
-    value_type operator() (value_null const& lhs ,
-                           value_null const& rhs) const
-    {
-        return lhs;
-    }
-
-    value_type operator() (value_unicode_string const& lhs, value_null) const
-    {
-        return lhs;
-    }
-
-    value_type operator() (value_null, value_unicode_string const& rhs) const
-    {
-        return rhs;
-    }
-
-    template <typename L>
-    value_type operator() (L const& lhs, value_null const&) const
-    {
-        return lhs;
-    }
-
-    template <typename R>
-    value_type operator() (value_null const&, R const& rhs) const
-    {
-        return rhs;
-    }
-
-    template <typename T>
-    value_type operator() (T lhs, T rhs) const
-    {
-        if (rhs == 0) return value_type();
-        return lhs / rhs;
-    }
-
-    value_type operator() (value_bool lhs, value_bool rhs) const
-    {
-        if (rhs == 0) return lhs;
-        return value_integer(lhs) / value_integer(rhs);
-    }
-
-    value_type operator() (value_unicode_string const&,
-                           value_unicode_string const&) const
-    {
-        return value_type();
-    }
-
-    template <typename R>
-    value_type operator() (value_unicode_string const& lhs, R const&) const
-    {
-        return lhs;
-    }
-
-    template <typename L>
-    value_type operator() (L const&, value_unicode_string const& rhs) const
-    {
-        return rhs;
-    }
-
-    template <typename T1, typename T2>
-    value_type operator() (T1 const& lhs, T2 const& rhs) const
-    {
-        if (rhs == 0) return value_type();
-        using common_type = typename std::common_type<T1,T2>::type;
-        return common_type(lhs)/common_type(rhs);
-    }
-};
-
-template <typename V>
-struct mod
-{
-    using value_type = V;
-
-    template <typename T1, typename T2>
-    value_type operator() (T1 const& lhs, T2 const&) const
-    {
-       return lhs;
-    }
-
-    template <typename T>
-    value_type operator() (T lhs, T rhs) const
-    {
-        return lhs % rhs;
-    }
-
-    value_type operator() (value_unicode_string const&,
-                           value_unicode_string const&) const
-    {
-        return value_type();
-    }
-
-    value_type operator() (value_bool,
-                           value_bool) const
-    {
-        return false;
-    }
-
-    value_type operator() (value_double lhs, value_integer rhs) const
-    {
-        return std::fmod(lhs, static_cast<value_double>(rhs));
-    }
-
-    value_type operator() (value_integer lhs, value_double rhs) const
-    {
-        return std::fmod(static_cast<value_double>(lhs), rhs);
-    }
-
-    value_type operator() (value_double lhs, value_double rhs) const
-    {
-        return std::fmod(lhs, rhs);
-    }
-};
-
-template <typename V>
-struct negate
-{
-    using value_type = V;
-
-    template <typename T>
-    value_type operator() (T val) const
-    {
-        return -val;
-    }
-
-    value_type operator() (value_null val) const
-    {
-        return val;
-    }
-
-    value_type operator() (value_bool val) const
-    {
-        return val ? value_integer(-1) : value_integer(0);
-    }
-
-    value_type operator() (value_unicode_string const&) const
-    {
-        return value_type();
-    }
-};
-
-// converters
-template <typename T>
-struct convert {};
-
-template <>
-struct convert<value_bool>
-{
-    value_bool operator() (value_bool val) const
-    {
-        return val;
-    }
-
-    value_bool operator() (value_unicode_string const& ustr) const
-    {
-        return !ustr.isEmpty();
-    }
-
-    value_bool operator() (value_null const&) const
-    {
-        return false;
-    }
-
-    template <typename T>
-    value_bool operator() (T val) const
-    {
-        return val > 0 ? true : false;
-    }
-};
-
-template <>
-struct convert<value_double>
-{
-    value_double operator() (value_double val) const
-    {
-        return val;
-    }
-
-    value_double operator() (value_integer val) const
-    {
-        return static_cast<value_double>(val);
-    }
-
-    value_double operator() (value_bool val) const
-    {
-        return static_cast<value_double>(val);
-    }
-
-    value_double operator() (std::string const& val) const
-    {
-        value_double result;
-        if (util::string2double(val,result))
-            return result;
-        return 0;
-    }
-
-    value_double operator() (value_unicode_string const& val) const
-    {
-        std::string utf8;
-        val.toUTF8String(utf8);
-        return operator()(utf8);
-    }
-
-    value_double operator() (value_null const&) const
-    {
-        return 0.0;
-    }
-};
-
-template <>
-struct convert<value_integer>
-{
-    value_integer operator() (value_integer val) const
-    {
-        return val;
-    }
-
-    value_integer operator() (value_double val) const
-    {
-        return static_cast<value_integer>(rint(val));
-    }
-
-    value_integer operator() (value_bool val) const
-    {
-        return static_cast<value_integer>(val);
-    }
-
-    value_integer operator() (std::string const& val) const
-    {
-        value_integer result;
-        if (util::string2int(val,result))
-            return result;
-        return value_integer(0);
-    }
-
-    value_integer operator() (value_unicode_string const& val) const
-    {
-        std::string utf8;
-        val.toUTF8String(utf8);
-        return operator()(utf8);
-    }
-
-    value_integer operator() (value_null const&) const
-    {
-        return value_integer(0);
-    }
-};
-
-template <>
-struct convert<std::string>
-{
-    template <typename T>
-    std::string operator() (T val) const
-    {
-        std::string str;
-        util::to_string(str, val);
-        return str;
-    }
-
-    // specializations
-    std::string operator() (value_unicode_string const& val) const
-    {
-        std::string utf8;
-        val.toUTF8String(utf8);
-        return utf8;
-    }
-
-    std::string operator() (value_double val) const
-    {
-        std::string str;
-        util::to_string(str, val); // TODO set precision(16)
-        return str;
-    }
-
-    std::string operator() (value_bool val) const
-    {
-        return val ? "true": "false";
-    }
-
-    std::string operator() (value_null const&) const
-    {
-        return std::string();
-    }
-};
-
-struct to_unicode_impl
-{
-
-    template <typename T>
-    value_unicode_string operator() (T val) const
-    {
-        std::string str;
-        util::to_string(str,val);
-        return value_unicode_string(str.c_str());
-    }
-
-    // specializations
-    value_unicode_string const& operator() (value_unicode_string const& val) const
-    {
-        return val;
-    }
-
-    value_unicode_string operator() (value_double val) const
-    {
-        std::string str;
-        util::to_string(str,val);
-        return value_unicode_string(str.c_str());
-    }
-
-    value_unicode_string operator() (value_bool val) const
-    {
-        return value_unicode_string(val ? "true" : "false");
-    }
-
-    value_unicode_string operator() (value_null const&) const
-    {
-        return value_unicode_string();
-    }
-};
-
-struct to_expression_string_impl
-{
-    struct EscapingByteSink : U_NAMESPACE_QUALIFIER ByteSink
-    {
-        std::string dest_;
-        char quote_;
-
-        explicit EscapingByteSink(char quote)
-            : quote_(quote)
-        {}
-
-        virtual void Append(const char* data, int32_t n)
-        {
-            // reserve enough room to hold the appended chunk and quotes;
-            // if another chunk follows, or any character needs escaping,
-            // the string will grow naturally
-            if (dest_.empty())
-            {
-                dest_.reserve(2 + static_cast<std::size_t>(n));
-                dest_.append(1, quote_);
-            }
-            else
-            {
-                dest_.reserve(dest_.size() + n + 1);
-            }
-
-            for (auto end = data + n; data < end; ++data)
-            {
-                if (*data == '\\' || *data == quote_)
-                    dest_.append(1, '\\');
-                dest_.append(1, *data);
-            }
-        }
-
-        virtual void Flush()
-        {
-            if (dest_.empty())
-                dest_.append(2, quote_);
-            else
-                dest_.append(1, quote_);
-        }
-    };
-
-    explicit to_expression_string_impl(char quote = '\'')
-        : quote_(quote) {}
-
-    std::string operator() (value_unicode_string const& val) const
-    {
-        EscapingByteSink sink(quote_);
-        val.toUTF8(sink);
-        return sink.dest_;
-    }
-
-    std::string operator() (value_integer val) const
-    {
-        std::string output;
-        util::to_string(output,val);
-        return output;
-    }
-
-    std::string operator() (value_double val) const
-    {
-        std::string output;
-        util::to_string(output,val); // TODO precision(16)
-        return output;
-    }
-
-    std::string operator() (value_bool val) const
-    {
-        return val ? "true" : "false";
-    }
-
-    std::string operator() (value_null const&) const
-    {
-        return "null";
-    }
-
-    const char quote_;
-};
-
-
-} // namespace detail
-
 namespace value_adl_barrier {
 
-class value : public value_base
+class MAPNIK_DECL value : public value_base
 {
-    friend const value operator+(value const&,value const&);
-    friend const value operator-(value const&,value const&);
-    friend const value operator*(value const&,value const&);
-    friend const value operator/(value const&,value const&);
-    friend const value operator%(value const&,value const&);
+    friend MAPNIK_DECL value operator+(value const&,value const&);
+    friend MAPNIK_DECL value operator-(value const&,value const&);
+    friend MAPNIK_DECL value operator*(value const&,value const&);
+    friend MAPNIK_DECL value operator/(value const&,value const&);
+    friend MAPNIK_DECL value operator%(value const&,value const&);
 
 public:
     value() = default;
@@ -856,104 +76,32 @@ public:
         return *this;
     }
 
-    bool operator==(value const& other) const
-    {
-        return util::apply_visitor(detail::comparison<detail::equals, false>(), *this, other);
-    }
+    bool operator==(value const& other) const;
+    bool operator!=(value const& other) const;
+    bool operator>(value const& other) const;
+    bool operator>=(value const& other) const;
+    bool operator<(value const& other) const;
+    bool operator<=(value const& other) const;
 
-    bool operator!=(value const& other) const
-    {
-        return util::apply_visitor(detail::comparison<detail::not_equal, true>(), *this, other);
-    }
-
-    bool operator>(value const& other) const
-    {
-        return util::apply_visitor(detail::comparison<detail::greater_than, false>(), *this, other);
-    }
-
-    bool operator>=(value const& other) const
-    {
-        return util::apply_visitor(detail::comparison<detail::greater_or_equal, false>(), *this, other);
-    }
-
-    bool operator<(value const& other) const
-    {
-        return util::apply_visitor(detail::comparison<detail::less_than, false>(), *this, other);
-    }
-
-    bool operator<=(value const& other) const
-    {
-        return util::apply_visitor(detail::comparison<detail::less_or_equal, false>(), *this, other);
-    }
-
-    value operator- () const
-    {
-        return util::apply_visitor(detail::negate<value>(), *this);
-    }
+    value operator-() const;
 
     bool is_null() const;
 
-    template <typename T>
-    T convert() const
-    {
-        return util::apply_visitor(detail::convert<T>(),*this);
-    }
-
-    value_bool to_bool() const
-    {
-        return util::apply_visitor(detail::convert<value_bool>(),*this);
-    }
-
-    std::string to_expression_string(char quote = '\'') const
-    {
-        return util::apply_visitor(detail::to_expression_string_impl(quote),*this);
-    }
-
-    std::string to_string() const
-    {
-        return util::apply_visitor(detail::convert<std::string>(),*this);
-    }
+    template <typename T> T convert() const;
 
-    value_unicode_string to_unicode() const
-    {
-        return util::apply_visitor(detail::to_unicode_impl(),*this);
-    }
-
-    value_double to_double() const
-    {
-        return util::apply_visitor(detail::convert<value_double>(),*this);
-    }
-
-    value_integer to_int() const
-    {
-        return util::apply_visitor(detail::convert<value_integer>(),*this);
-    }
+    value_bool to_bool() const;
+    std::string to_expression_string(char quote = '\'') const;
+    std::string to_string() const;
+    value_unicode_string to_unicode() const;
+    value_double to_double() const;
+    value_integer to_int() const;
 };
 
-inline const value operator+(value const& p1,value const& p2)
-{
-    return value(util::apply_visitor(detail::add<value>(),p1, p2));
-}
-
-inline const value operator-(value const& p1,value const& p2)
-{
-    return value(util::apply_visitor(detail::sub<value>(),p1, p2));
-}
-
-inline const value operator*(value const& p1,value const& p2)
-{
-    return value(util::apply_visitor(detail::mult<value>(),p1, p2));
-}
-
-inline const value operator/(value const& p1,value const& p2)
-{
-    return value(util::apply_visitor(detail::div<value>(),p1, p2));
-}
-
-inline const value operator%(value const& p1,value const& p2)
-{
-    return value(util::apply_visitor(detail::mod<value>(),p1, p2));
-}
+MAPNIK_DECL value operator+(value const& p1,value const& p2);
+MAPNIK_DECL value operator-(value const& p1,value const& p2);
+MAPNIK_DECL value operator*(value const& p1,value const& p2);
+MAPNIK_DECL value operator/(value const& p1,value const& p2);
+MAPNIK_DECL value operator%(value const& p1,value const& p2);
 
 template <typename charT, typename traits>
 inline std::basic_ostream<charT,traits>&
@@ -972,36 +120,28 @@ inline std::size_t hash_value(value const& val)
 
 } // namespace value_adl_barrier
 
-using value_adl_barrier::value;
+using value = value_adl_barrier::value;
 
 namespace detail {
-
 struct is_null_visitor
 {
-    bool operator() (value const& val) const
+    bool operator()(value const& val) const
     {
         return val.is_null();
     }
 
-    bool operator() (value_null const&) const
+    bool operator()(value_null const&) const
     {
         return true;
     }
 
     template <typename T>
-    bool operator() (T const&) const
+    bool operator()(T const&) const
     {
         return false;
     }
 };
-
 } // namespace detail
-
-inline bool value::is_null() const
-{
-    return util::apply_visitor(mapnik::detail::is_null_visitor(), *this);
-}
-
 } // namespace mapnik
 
 // support for std::unordered_xxx
diff --git a/include/mapnik/value_hash.hpp b/include/mapnik/value_hash.hpp
index c1f1d60..b050e37 100644
--- a/include/mapnik/value_hash.hpp
+++ b/include/mapnik/value_hash.hpp
@@ -30,8 +30,10 @@
 // stl
 #include <functional>
 
-// icu
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <unicode/unistr.h>
+#pragma GCC diagnostic pop
 
 namespace mapnik { namespace detail {
 
diff --git a/include/mapnik/value_types.hpp b/include/mapnik/value_types.hpp
index 85a015b..235133a 100644
--- a/include/mapnik/value_types.hpp
+++ b/include/mapnik/value_types.hpp
@@ -27,8 +27,11 @@
 #include <mapnik/config.hpp>
 #include <mapnik/pixel_types.hpp>
 
-// icu
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <unicode/uversion.h> // for U_NAMESPACE_QUALIFIER
+#pragma GCC diagnostic pop
 
 // stl
 #include <type_traits>
diff --git a/include/mapnik/version.hpp b/include/mapnik/version.hpp
index a105bec..e1a367b 100644
--- a/include/mapnik/version.hpp
+++ b/include/mapnik/version.hpp
@@ -23,17 +23,14 @@
 #ifndef MAPNIK_VERSION_HPP
 #define MAPNIK_VERSION_HPP
 
+#include <mapnik/stringify_macro.hpp>
+
 #define MAPNIK_MAJOR_VERSION 3
 #define MAPNIK_MINOR_VERSION 0
-#define MAPNIK_PATCH_VERSION 10
+#define MAPNIK_PATCH_VERSION 11
 
 #define MAPNIK_VERSION (MAPNIK_MAJOR_VERSION*100000) + (MAPNIK_MINOR_VERSION*100) + (MAPNIK_PATCH_VERSION)
 
-#ifndef MAPNIK_STRINGIFY
-#define MAPNIK_STRINGIFY(n) MAPNIK_STRINGIFY_HELPER(n)
-#define MAPNIK_STRINGIFY_HELPER(n) #n
-#endif
-
 #define MAPNIK_VERSION_STRING   MAPNIK_STRINGIFY(MAPNIK_MAJOR_VERSION) "." \
                                 MAPNIK_STRINGIFY(MAPNIK_MINOR_VERSION) "." \
                                 MAPNIK_STRINGIFY(MAPNIK_PATCH_VERSION)
diff --git a/include/mapnik/vertex_adapters.hpp b/include/mapnik/vertex_adapters.hpp
index ae5f0d4..3a41bee 100644
--- a/include/mapnik/vertex_adapters.hpp
+++ b/include/mapnik/vertex_adapters.hpp
@@ -34,32 +34,10 @@ struct point_vertex_adapter
 {
     using value_type = typename point<T>::value_type;
 
-    point_vertex_adapter(point<T> const& pt)
-        : pt_(pt),
-          first_(true) {}
-
-    unsigned vertex(value_type * x, value_type * y) const
-    {
-        if (first_)
-        {
-            *x = pt_.x;
-            *y = pt_.y;
-            first_ = false;
-            return mapnik::SEG_MOVETO;
-        }
-        return mapnik::SEG_END;
-    }
-
-    void rewind(unsigned) const
-    {
-        first_ = true;
-    }
-
-    inline geometry_types type () const
-    {
-        return geometry_types::Point;
-    }
-
+    point_vertex_adapter(point<T> const& pt);
+    unsigned vertex(value_type * x, value_type * y) const;
+    void rewind(unsigned) const;
+    geometry_types type () const;
     point<T> const& pt_;
     mutable bool first_;
 };
@@ -68,110 +46,23 @@ template <typename T>
 struct line_string_vertex_adapter
 {
     using value_type = typename point<T>::value_type;
-    line_string_vertex_adapter(line_string<T> const& line)
-        : line_(line),
-          current_index_(0),
-          end_index_(line.size())
-    {}
-
-    unsigned vertex(value_type * x, value_type * y) const
-    {
-        if (current_index_ != end_index_)
-        {
-            point<T> const& coord = line_[current_index_++];
-            *x = coord.x;
-            *y = coord.y;
-            if (current_index_ == 1)
-            {
-                return mapnik::SEG_MOVETO;
-            }
-            else
-            {
-                return mapnik::SEG_LINETO;
-            }
-        }
-        return mapnik::SEG_END;
-    }
-
-    void rewind(unsigned) const
-    {
-        current_index_ = 0;
-    }
-
-    inline geometry_types type () const
-    {
-        return geometry_types::LineString;
-    }
-
+    line_string_vertex_adapter(line_string<T> const& line);
+    unsigned vertex(value_type * x, value_type * y) const;
+    void rewind(unsigned) const;
+    geometry_types type () const;
     line_string<T> const& line_;
     mutable std::size_t current_index_;
-    const std::size_t end_index_;
-
+   const std::size_t end_index_;
 };
 
 template <typename T>
 struct polygon_vertex_adapter
 {
     using value_type = typename point<T>::value_type;
-    polygon_vertex_adapter(polygon<T> const& poly)
-        : poly_(poly),
-          rings_itr_(0),
-          rings_end_(poly_.interior_rings.size() + 1),
-          current_index_(0),
-          end_index_((rings_itr_ < rings_end_) ? poly_.exterior_ring.size() : 0),
-          start_loop_(true) {}
-
-    void rewind(unsigned) const
-    {
-        rings_itr_ = 0;
-        rings_end_ = poly_.interior_rings.size() + 1;
-        current_index_ = 0;
-        end_index_ = (rings_itr_ < rings_end_) ? poly_.exterior_ring.size() : 0;
-        start_loop_ = true;
-    }
-
-    unsigned vertex(value_type * x, value_type * y) const
-    {
-        if (rings_itr_ == rings_end_)
-        {
-            return mapnik::SEG_END;
-        }
-        if (current_index_ < end_index_)
-        {
-            point<T> const& coord = (rings_itr_ == 0) ?
-                poly_.exterior_ring[current_index_++] : poly_.interior_rings[rings_itr_- 1][current_index_++];
-            *x = coord.x;
-            *y = coord.y;
-            if (start_loop_)
-            {
-                start_loop_= false;
-                return mapnik::SEG_MOVETO;
-            }
-            if (current_index_ == end_index_)
-            {
-                *x = 0;
-                *y = 0;
-                return mapnik::SEG_CLOSE;
-            }
-            return mapnik::SEG_LINETO;
-        }
-        else if (++rings_itr_ != rings_end_)
-        {
-            current_index_ = 0;
-            end_index_ = poly_.interior_rings[rings_itr_ - 1].size();
-            point<T> const& coord = poly_.interior_rings[rings_itr_ - 1][current_index_++];
-            *x = coord.x;
-            *y = coord.y;
-            return mapnik::SEG_MOVETO;
-        }
-        return mapnik::SEG_END;
-    }
-
-    inline geometry_types type () const
-    {
-        return geometry_types::Polygon;
-    }
-
+    polygon_vertex_adapter(polygon<T> const& poly);
+    void rewind(unsigned) const;
+    unsigned vertex(value_type * x, value_type * y) const;
+    geometry_types type () const;
 private:
     polygon<T> const& poly_;
     mutable std::size_t rings_itr_;
@@ -185,47 +76,10 @@ template <typename T>
 struct ring_vertex_adapter
 {
     using value_type = typename point<T>::value_type;
-    ring_vertex_adapter(linear_ring<T> const& ring)
-        : ring_(ring),
-          current_index_(0),
-          end_index_(ring_.size()),
-          start_loop_(true) {}
-
-    void rewind(unsigned) const
-    {
-        current_index_ = 0;
-        end_index_ = ring_.size();
-        start_loop_ = true;
-    }
-
-    unsigned vertex(value_type * x, value_type * y) const
-    {
-        if (current_index_ < end_index_)
-        {
-            auto const& coord = ring_[current_index_++];
-            *x = coord.x;
-            *y = coord.y;
-            if (start_loop_)
-            {
-                start_loop_= false;
-                return mapnik::SEG_MOVETO;
-            }
-            if (current_index_ == end_index_)
-            {
-                *x = 0;
-                *y = 0;
-                return mapnik::SEG_CLOSE;
-            }
-            return mapnik::SEG_LINETO;
-        }
-        return mapnik::SEG_END;
-    }
-
-    inline geometry_types type () const
-    {
-        return geometry_types::Polygon;
-    }
-
+    ring_vertex_adapter(linear_ring<T> const& ring);
+    void rewind(unsigned) const;
+    unsigned vertex(value_type * x, value_type * y) const;
+    geometry_types type () const;
 private:
     linear_ring<T> const& ring_;
     mutable std::size_t current_index_;
@@ -233,6 +87,11 @@ private:
     mutable bool start_loop_;
 };
 
+extern template struct MAPNIK_DECL point_vertex_adapter<double>;
+extern template struct MAPNIK_DECL line_string_vertex_adapter<double>;
+extern template struct MAPNIK_DECL polygon_vertex_adapter<double>;
+extern template struct MAPNIK_DECL ring_vertex_adapter<double>;
+
 template <typename T>
 struct vertex_adapter_traits {};
 
diff --git a/include/mapnik/vertex_cache.hpp b/include/mapnik/vertex_cache.hpp
index a0a32e9..9df786e 100644
--- a/include/mapnik/vertex_cache.hpp
+++ b/include/mapnik/vertex_cache.hpp
@@ -28,8 +28,10 @@
 #include <mapnik/config.hpp>
 #include <mapnik/util/noncopyable.hpp>
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_basics.h"
+#pragma GCC diagnostic pop
 
 // stl
 #include <vector>
diff --git a/include/mapnik/vertex_converters.hpp b/include/mapnik/vertex_converters.hpp
index f10f720..ba18294 100644
--- a/include/mapnik/vertex_converters.hpp
+++ b/include/mapnik/vertex_converters.hpp
@@ -37,7 +37,8 @@
 #include <mapnik/symbolizer_keys.hpp>
 #include <mapnik/symbolizer.hpp>
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_math_stroke.h"
 #include "agg_trans_affine.h"
 #include "agg_conv_clip_polygon.h"
@@ -46,6 +47,7 @@
 #include "agg_conv_stroke.h"
 #include "agg_conv_dash.h"
 #include "agg_conv_transform.h"
+#pragma GCC diagnostic pop
 
 // stl
 #include <type_traits>
@@ -275,7 +277,7 @@ template <typename Dispatcher, typename... ConverterTypes>
 struct converters_helper;
 
 template <typename Dispatcher, typename Current, typename... ConverterTypes>
-struct converters_helper<Dispatcher,Current,ConverterTypes...>
+struct converters_helper<Dispatcher, Current, ConverterTypes...>
 {
     template <typename Converter>
     static void set(Dispatcher & disp, std::size_t state)
diff --git a/include/mapnik/warning_ignore.hpp b/include/mapnik/warning_ignore.hpp
index a9856b9..62b7899 100644
--- a/include/mapnik/warning_ignore.hpp
+++ b/include/mapnik/warning_ignore.hpp
@@ -32,4 +32,25 @@
 #pragma GCC diagnostic ignored "-Wc++11-narrowing"
 #pragma GCC diagnostic ignored "-Wsign-conversion"
 #pragma GCC diagnostic ignored "-Wsign-compare"
-#pragma GCC diagnostic ignored "-Wconversion"
\ No newline at end of file
+#pragma GCC diagnostic ignored "-Wconversion"
+#pragma GCC diagnostic ignored "-Wc++98-compat-pedantic"
+#pragma GCC diagnostic ignored "-Wdisabled-macro-expansion"
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+#pragma GCC diagnostic ignored "-Wdocumentation"
+#pragma GCC diagnostic ignored "-Wdocumentation-unknown-command"
+#pragma GCC diagnostic ignored "-Wundef"
+#pragma GCC diagnostic ignored "-Wdeprecated"
+#pragma GCC diagnostic ignored "-Wpadded"
+#pragma GCC diagnostic ignored "-Wc++98-compat"
+#pragma GCC diagnostic ignored "-Wreserved-id-macro"
+#pragma GCC diagnostic ignored "-Wweak-vtables"
+#pragma GCC diagnostic ignored "-Wextra-semi"
+#pragma GCC diagnostic ignored "-Wc++98-compat-pedantic"
+#pragma GCC diagnostic ignored "-Wglobal-constructors"
+#pragma GCC diagnostic ignored "-Wheader-hygiene"
+#pragma GCC diagnostic ignored "-Wexit-time-destructors"
+#pragma GCC diagnostic ignored "-Wswitch-enum"
+#pragma GCC diagnostic ignored "-Wmissing-noreturn"
+#pragma GCC diagnostic ignored "-Wcovered-switch-default"
+#pragma GCC diagnostic ignored "-Wfloat-equal"
+
diff --git a/include/mapnik/warning_ignore.hpp b/include/mapnik/warning_ignore_agg.hpp
similarity index 77%
copy from include/mapnik/warning_ignore.hpp
copy to include/mapnik/warning_ignore_agg.hpp
index a9856b9..2f44c5c 100644
--- a/include/mapnik/warning_ignore.hpp
+++ b/include/mapnik/warning_ignore_agg.hpp
@@ -23,13 +23,10 @@
 
 #pragma GCC diagnostic ignored "-Wunknown-pragmas" // clang+gcc
 #pragma GCC diagnostic ignored "-Wpragmas" // gcc
-#pragma GCC diagnostic ignored "-Wunsequenced"
-#pragma GCC diagnostic ignored "-Wunused-function"
-#pragma GCC diagnostic ignored "-Wunused-parameter"
-#pragma GCC diagnostic ignored "-Wredeclared-class-member"
-#pragma GCC diagnostic ignored "-Wunused-local-typedef" 
-#pragma GCC diagnostic ignored "-Wshadow"
-#pragma GCC diagnostic ignored "-Wc++11-narrowing"
 #pragma GCC diagnostic ignored "-Wsign-conversion"
 #pragma GCC diagnostic ignored "-Wsign-compare"
-#pragma GCC diagnostic ignored "-Wconversion"
\ No newline at end of file
+#pragma GCC diagnostic ignored "-Wconversion"
+#pragma GCC diagnostic ignored "-Wpadded"
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+#pragma GCC diagnostic ignored "-Wshadow"
+
diff --git a/include/mapnik/well_known_srs.hpp b/include/mapnik/well_known_srs.hpp
index eeb478e..e8349e7 100644
--- a/include/mapnik/well_known_srs.hpp
+++ b/include/mapnik/well_known_srs.hpp
@@ -28,8 +28,10 @@
 #include <mapnik/enumeration.hpp>
 #include <mapnik/geometry.hpp>
 
-// boost
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/optional.hpp>
+#pragma GCC diagnostic pop
 
 // stl
 #include <cmath>
@@ -63,7 +65,8 @@ boost::optional<bool> is_known_geographic(std::string const& srs);
 
 static inline bool lonlat2merc(double * x, double * y , int point_count)
 {
-    for(int i=0; i<point_count; i++) {
+    for(int i=0; i<point_count; ++i)
+    {
         if (x[i] > 180) x[i] = 180;
         else if (x[i] < -180) x[i] = -180;
         if (y[i] > MAX_LATITUDE) y[i] = MAX_LATITUDE;
diff --git a/include/mapnik/wkb.hpp b/include/mapnik/wkb.hpp
index 53f1e85..98b3d30 100644
--- a/include/mapnik/wkb.hpp
+++ b/include/mapnik/wkb.hpp
@@ -60,9 +60,11 @@ class MAPNIK_DECL geometry_utils : private util::noncopyable
 {
 public:
 
-    static mapnik::geometry::geometry<double> from_wkb(const char* wkb,
-                                                       std::size_t size,
-                                                       wkbFormat format = wkbGeneric);
+    static geometry::geometry<double> from_wkb(char const* wkb,
+                                               std::size_t size,
+                                               wkbFormat format = wkbGeneric);
+
+    static geometry::geometry<double> from_twkb(char const* twkb, std::size_t size);
 };
 
 }
diff --git a/include/mapnik/wkt/wkt_generator_grammar.hpp b/include/mapnik/wkt/wkt_generator_grammar.hpp
index 0c89601..892e551 100644
--- a/include/mapnik/wkt/wkt_generator_grammar.hpp
+++ b/include/mapnik/wkt/wkt_generator_grammar.hpp
@@ -27,7 +27,6 @@
 #include <mapnik/global.hpp>
 #include <mapnik/geometry.hpp>
 #include <mapnik/geometry_type.hpp>
-#include <mapnik/geometry_fusion_adapted.hpp>
 
 #pragma GCC diagnostic push
 #include <mapnik/warning_ignore.hpp>
diff --git a/include/mapnik/wkt/wkt_generator_grammar_impl.hpp b/include/mapnik/wkt/wkt_generator_grammar_impl.hpp
index 7205db6..8d950ed 100644
--- a/include/mapnik/wkt/wkt_generator_grammar_impl.hpp
+++ b/include/mapnik/wkt/wkt_generator_grammar_impl.hpp
@@ -20,11 +20,15 @@
  *
  *****************************************************************************/
 
-#include <mapnik/geometry.hpp>
+// mapnik
 #include <mapnik/wkt/wkt_generator_grammar.hpp>
 #include <mapnik/util/spirit_transform_attribute.hpp>
-// boost
+#include <mapnik/geometry_fusion_adapted.hpp>
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/spirit/include/phoenix.hpp>
+#pragma GCC diagnostic pop
 
 namespace mapnik { namespace wkt {
 
diff --git a/include/mapnik/wkt/wkt_grammar.hpp b/include/mapnik/wkt/wkt_grammar.hpp
index a91f436..9d23f81 100644
--- a/include/mapnik/wkt/wkt_grammar.hpp
+++ b/include/mapnik/wkt/wkt_grammar.hpp
@@ -24,9 +24,8 @@
 #define MAPNIK_WKT_GRAMMAR_HPP
 
 // mapnik
+#include <mapnik/config.hpp>
 #include <mapnik/geometry.hpp>
-#include <mapnik/geometry_fusion_adapted.hpp>
-
 #pragma GCC diagnostic push
 #include <mapnik/warning_ignore.hpp>
 #include <boost/assert.hpp>
diff --git a/include/mapnik/wkt/wkt_grammar_impl.hpp b/include/mapnik/wkt/wkt_grammar_impl.hpp
index 85a9274..d244413 100644
--- a/include/mapnik/wkt/wkt_grammar_impl.hpp
+++ b/include/mapnik/wkt/wkt_grammar_impl.hpp
@@ -20,14 +20,18 @@
  *
  *****************************************************************************/
 
-#include <mapnik/config.hpp>
 #include <mapnik/wkt/wkt_grammar.hpp>
+#include <mapnik/geometry_fusion_adapted.hpp>
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/spirit/include/phoenix.hpp>
 #include <boost/spirit/include/phoenix_core.hpp>
 #include <boost/spirit/include/phoenix_fusion.hpp>
 #include <boost/spirit/include/phoenix_object.hpp>
 #include <boost/spirit/include/phoenix_stl.hpp>
 #include <boost/phoenix/object/construct.hpp>
+#pragma GCC diagnostic pop
 
 namespace mapnik { namespace wkt {
 
diff --git a/include/mapnik/xml_node.hpp b/include/mapnik/xml_node.hpp
index 1c36021..bf7130c 100644
--- a/include/mapnik/xml_node.hpp
+++ b/include/mapnik/xml_node.hpp
@@ -26,8 +26,10 @@
 //mapnik
 #include <mapnik/config.hpp> // for MAPNIK_DECL
 
-//boost
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/optional.hpp>
+#pragma GCC diagnostic pop
 
 //stl
 #include <list>
diff --git a/mason_latest.sh b/mason_latest.sh
index 62a0c94..7b3e02a 100755
--- a/mason_latest.sh
+++ b/mason_latest.sh
@@ -1,5 +1,7 @@
 #!/usr/bin/env bash
 
+set -eu
+
 MASON_NAME=mapnik
 MASON_VERSION=latest
 MASON_LIB_FILE=lib/libmapnik-wkt.a
@@ -13,21 +15,38 @@ function mason_load_source {
 function mason_compile {
     HERE=$(pwd)
     make install
-    if [[ `uname` == 'Darwin' ]]; then
-        install_name_tool -id @loader_path/libmapnik.dylib ${MASON_PREFIX}"/lib/libmapnik.dylib";
+    # this is to adapt to when mapnik is not installed in MASON_PREFIX
+    # originally (to make it easier to publish locally as a stopgap)
+    MAPNIK_PREFIX=$(mapnik-config --prefix)
+    if [[ ${MAPNIK_PREFIX} != ${MASON_PREFIX} ]]; then
+        mkdir -p ${MASON_PREFIX}/lib
+        mkdir -p ${MASON_PREFIX}/include
+        mkdir -p ${MASON_PREFIX}/bin
+        cp -r ${MAPNIK_PREFIX}/lib/*mapnik* ${MASON_PREFIX}/lib/
+        cp -r ${MAPNIK_PREFIX}/include/mapnik ${MASON_PREFIX}/include/
+        cp -r ${MAPNIK_PREFIX}/bin/mapnik* ${MASON_PREFIX}/bin/
+        cp -r ${MAPNIK_PREFIX}/bin/shapeindex ${MASON_PREFIX}/bin/
+    fi
+    if [[ $(uname -s) == 'Darwin' ]]; then
+        install_name_tool -id @loader_path/lib/libmapnik.dylib ${MASON_PREFIX}"/lib/libmapnik.dylib";
         PLUGINDIR=${MASON_PREFIX}"/lib/mapnik/input/*.input";
         for f in $PLUGINDIR; do
             echo $f;
-            echo `basename $f`;
-            install_name_tool -id plugins/input/`basename $f` $f;
-            install_name_tool -change ${MASON_PREFIX}"/lib/libmapnik.dylib" @loader_path/../../libmapnik.dylib $f;
+            echo $(basename $f);
+            install_name_tool -id plugins/input/$(basename $f) $f;
+            install_name_tool -change "${MAPNIK_PREFIX}/lib/libmapnik.dylib" @loader_path/../../lib/libmapnik.dylib $f;
+        done;
+        BINDIR=${MASON_PREFIX}"/bin/*";
+        for f in $BINDIR; do
+            echo $f;
+            echo $(basename $f);
+            if [[ $(file $f) =~ 'Mach-O' ]]; then
+                install_name_tool -id bin/$(basename $f) $f;
+                install_name_tool -change "${MAPNIK_PREFIX}/lib/libmapnik.dylib" @loader_path/../lib/libmapnik.dylib $f;
+            fi
         done;
     fi;
     python -c "data=open('$MASON_PREFIX/bin/mapnik-config','r').read();open('$MASON_PREFIX/bin/mapnik-config','w').write(data.replace('$HERE','.'))"
-    mkdir -p ${MASON_PREFIX}/share/icu
-    cp -r $GDAL_DATA ${MASON_PREFIX}/share/
-    cp -r $PROJ_LIB ${MASON_PREFIX}/share/
-    cp -r $ICU_DATA/*dat ${MASON_PREFIX}/share/icu/
     find ${MASON_PREFIX} -name "*.pyc" -exec rm {} \;
 }
 
diff --git a/plugins/input/csv/build.py b/plugins/input/csv/build.py
index edc3ae0..91675a1 100644
--- a/plugins/input/csv/build.py
+++ b/plugins/input/csv/build.py
@@ -39,6 +39,7 @@ else:
 
     plugin_sources = Split(
         """
+        %(PLUGIN_NAME)s_utils.cpp
         %(PLUGIN_NAME)s_datasource.cpp
         %(PLUGIN_NAME)s_featureset.cpp
         %(PLUGIN_NAME)s_inline_featureset.cpp
diff --git a/plugins/input/csv/csv_datasource.cpp b/plugins/input/csv/csv_datasource.cpp
index 19aa16c..6c1ff10 100644
--- a/plugins/input/csv/csv_datasource.cpp
+++ b/plugins/input/csv/csv_datasource.cpp
@@ -21,6 +21,7 @@
  *****************************************************************************/
 
 #include "csv_utils.hpp"
+#include "csv_getline.hpp"
 #include "csv_datasource.hpp"
 #include "csv_featureset.hpp"
 #include "csv_inline_featureset.hpp"
@@ -36,9 +37,12 @@
 #include <mapnik/memory_featureset.hpp>
 #include <mapnik/boolean.hpp>
 #include <mapnik/util/trim.hpp>
+#include <mapnik/geometry.hpp>
+#include <mapnik/geometry_adapters.hpp>
 #include <mapnik/util/geometry_to_ds_type.hpp>
 #include <mapnik/value_types.hpp>
 #include <mapnik/util/fs.hpp>
+#include <mapnik/make_unique.hpp>
 #include <mapnik/util/spatial_index.hpp>
 #include <mapnik/geom_util.hpp>
 #if defined(MAPNIK_MEMORY_MAPPED_FILE)
@@ -65,21 +69,13 @@ DATASOURCE_PLUGIN(csv_datasource)
 csv_datasource::csv_datasource(parameters const& params)
 : datasource(params),
     desc_(csv_datasource::name(), *params.get<std::string>("encoding", "utf-8")),
-    extent_(),
-    filename_(),
-    row_limit_(*params.get<mapnik::value_integer>("row_limit", 0)),
-    inline_string_(),
-    separator_(0),
-    quote_(0),
-    headers_(),
-    manual_headers_(mapnik::util::trim_copy(*params.get<std::string>("headers", ""))),
-    strict_(*params.get<mapnik::boolean_type>("strict", false)),
     ctx_(std::make_shared<mapnik::context_type>()),
-    extent_initialized_(false),
-    tree_(nullptr),
-    locator_(),
-    has_disk_index_(false)
+    tree_(nullptr)
 {
+    row_limit_ = *params.get<mapnik::value_integer>("row_limit", 0);
+    manual_headers_ = mapnik::util::trim_copy(*params.get<std::string>("headers", ""));
+    strict_ = *params.get<mapnik::boolean_type>("strict", false);
+
     auto quote_param = params.get<std::string>("quote");
     if (quote_param)
     {
@@ -170,297 +166,89 @@ csv_datasource::csv_datasource(parameters const& params)
 
 csv_datasource::~csv_datasource() {}
 
-template <typename T>
-void csv_datasource::parse_csv(T & stream)
+void csv_datasource::parse_csv(std::istream & csv_file)
 {
-    auto file_length = detail::file_length(stream);
-    // set back to start
-    stream.seekg(0, std::ios::beg);
-    char newline;
-    bool has_newline;
-    char detected_quote;
-    char detected_separator;
-    std::tie(newline, has_newline, detected_separator, detected_quote) = detail::autodect_csv_flavour(stream, file_length);
-    if (quote_ == 0) quote_ = detected_quote;
-    if (separator_ == 0) separator_ = detected_separator;
-
-    // set back to start
-    MAPNIK_LOG_DEBUG(csv) << "csv_datasource: separator: '" << separator_
-                          << "' quote: '" << quote_ << "'";
-
-    // rewind stream
-    stream.seekg(0, std::ios::beg);
-    //
-    std::string csv_line;
-    csv_utils::getline_csv(stream, csv_line, newline, quote_);
-    stream.seekg(0, std::ios::beg);
-    int line_number = 0;
-    if (!manual_headers_.empty())
-    {
-        std::size_t index = 0;
-        auto headers = csv_utils::parse_line(manual_headers_, separator_, quote_);
-        for (auto const& header : headers)
-        {
-            detail::locate_geometry_column(header, index++, locator_);
-            headers_.push_back(header);
-        }
-    }
-    else // parse first line as headers
-    {
-        while (csv_utils::getline_csv(stream, csv_line, newline, quote_))
-        {
-            try
-            {
-                auto headers = csv_utils::parse_line(csv_line, separator_, quote_);
-                // skip blank lines
-                std::string val;
-                if (headers.size() > 0 && headers[0].empty()) ++line_number;
-                else
-                {
-                    std::size_t index = 0;
-                    for (auto const& header : headers)
-                    {
-                        val = mapnik::util::trim_copy(header);
-                        if (val.empty())
-                        {
-                            if (strict_)
-                            {
-                                std::ostringstream s;
-                                s << "CSV Plugin: expected a column header at line ";
-                                s << line_number << ", column " << index;
-                                s << " - ensure this row contains valid header fields: '";
-                                s << csv_line;
-                                throw mapnik::datasource_exception(s.str());
-                            }
-                            else
-                            {
-                                // create a placeholder for the empty header
-                                std::ostringstream s;
-                                s << "_" << index;
-                                headers_.push_back(s.str());
-                            }
-                        }
-                        else
-                        {
-                            detail::locate_geometry_column(val, index, locator_);
-                            headers_.push_back(val);
-                        }
-                        ++index;
-                    }
-                    ++line_number;
-                    break;
-                }
-            }
-            catch (std::exception const& ex)
-            {
-                std::string s("CSV Plugin: error parsing headers: ");
-                s += ex.what();
-                throw mapnik::datasource_exception(s);
-            }
-        }
-    }
-
-    std::size_t num_headers = headers_.size();
-    if (!detail::valid(locator_, num_headers))
-    {
-        std::string str("CSV Plugin: could not detect column(s) with the name(s) of wkt, geojson, x/y, or ");
-        str += "latitude/longitude in:\n";
-        str += csv_line;
-        str += "\n - this is required for reading geometry data";
-        throw mapnik::datasource_exception(str);
-    }
-
-    mapnik::value_integer feature_count = 0;
-    bool extent_started = false;
+    std::vector<item_type> boxes;
+    csv_utils::csv_file_parser::parse_csv_and_boxes(csv_file, boxes);
 
     std::for_each(headers_.begin(), headers_.end(),
                   [ & ](std::string const& header){ ctx_->push(header); });
 
-    mapnik::transcoder tr(desc_.get_encoding());
-
-    auto pos = stream.tellg();
-    // handle rare case of a single line of data and user-provided headers
-    // where a lack of a newline will mean that csv_utils::getline_csv returns false
-    bool is_first_row = false;
-
-    if (!has_newline)
+    if (!has_disk_index_)
     {
-        stream.setstate(std::ios::failbit);
-        pos = 0;
-        if (!csv_line.empty())
-        {
-            is_first_row = true;
-        }
+        // bulk insert initialise r-tree
+        tree_ = std::make_unique<spatial_index_type>(boxes);
     }
+}
 
-    std::vector<item_type> boxes;
-    while (is_first_row || csv_utils::getline_csv(stream, csv_line, newline, quote_))
-    {
-        ++line_number;
-        if ((row_limit_ > 0) && (line_number > row_limit_))
-        {
-            MAPNIK_LOG_DEBUG(csv) << "csv_datasource: row limit hit, exiting at feature: " << feature_count;
-            break;
-        }
-        auto record_offset = pos;
-        auto record_size = csv_line.length();
-        pos = stream.tellg();
-        is_first_row = false;
+void csv_datasource::add_feature(mapnik::value_integer index,
+                                 mapnik::csv_line const & values)
+{
+    if (index != 1) return;
 
-        // skip blank lines
-        if (record_size <= 10)
+    for (std::size_t i = 0; i < values.size(); ++i)
+    {
+        std::string const& header = headers_.at(i);
+        std::string value = mapnik::util::trim_copy(values[i]);
+        int value_length = value.length();
+        if (locator_.index == i && (locator_.type == csv_utils::geometry_column_locator::WKT
+                                    || locator_.type == csv_utils::geometry_column_locator::GEOJSON)) continue;
+
+        // First we detect likely strings,
+        // then try parsing likely numbers,
+        // then try converting to bool,
+        // finally falling back to string type.
+
+        // An empty string or a string of "null" will be parsed
+        // as a string rather than a true null value.
+        // Likely strings are either empty values, very long values
+        // or values with leading zeros like 001 (which are not safe
+        // to assume are numbers)
+
+        bool matched = false;
+        bool has_dot = value.find(".") != std::string::npos;
+        if (value.empty() || (value_length > 20) || (value_length > 1 && !has_dot && value[0] == '0'))
         {
-            std::string trimmed = csv_line;
-            boost::trim_if(trimmed,boost::algorithm::is_any_of("\",'\r\n "));
-            if (trimmed.empty())
-            {
-                MAPNIK_LOG_DEBUG(csv) << "csv_datasource: empty row encountered at line: " << line_number;
-                continue;
-            }
+            matched = true;
+            desc_.add_descriptor(mapnik::attribute_descriptor(header, mapnik::String));
         }
-
-        try
+        else if (csv_utils::is_likely_number(value))
         {
-            auto const* line_start = csv_line.data();
-            auto const* line_end = line_start + csv_line.size();
-            auto values = csv_utils::parse_line(line_start, line_end, separator_, quote_, num_headers);
-            unsigned num_fields = values.size();
-            if (num_fields != num_headers)
+            bool has_e = value.find("e") != std::string::npos;
+            if (has_dot || has_e)
             {
-                std::ostringstream s;
-                s << "CSV Plugin: # of columns(" << num_fields << ")";
-                if (num_fields > num_headers)
+                double float_val = 0.0;
+                if (mapnik::util::string2double(value,float_val))
                 {
-                    s << " > ";
+                    matched = true;
+                    desc_.add_descriptor(mapnik::attribute_descriptor(header,mapnik::Double));
                 }
-                else
-                {
-                    s << " < ";
-                }
-                s << "# of headers(" << num_headers << ") parsed";
-                throw mapnik::datasource_exception(s.str());
             }
-
-            auto geom = detail::extract_geometry(values, locator_);
-            if (!geom.is<mapnik::geometry::geometry_empty>())
+            else
             {
-                auto box = mapnik::geometry::envelope(geom);
-                boxes.emplace_back(std::move(box), make_pair(record_offset, record_size));
-                if (!extent_initialized_)
+                mapnik::value_integer int_val = 0;
+                if (mapnik::util::string2int(value,int_val))
                 {
-                    if (!extent_started)
-                    {
-                        extent_started = true;
-                        extent_ = mapnik::geometry::envelope(geom);
-                    }
-                    else
-                    {
-                        extent_.expand_to_include(mapnik::geometry::envelope(geom));
-                    }
-                }
-                if (++feature_count != 1) continue;
-                auto beg = values.begin();
-                for (std::size_t i = 0; i < num_headers; ++i)
-                {
-                    std::string const& header = headers_.at(i);
-                    std::string value = mapnik::util::trim_copy(*beg++);
-                    int value_length = value.length();
-                    if (locator_.index == i && (locator_.type == detail::geometry_column_locator::WKT
-                                                || locator_.type == detail::geometry_column_locator::GEOJSON)) continue;
-
-                    // First we detect likely strings,
-                    // then try parsing likely numbers,
-                    // then try converting to bool,
-                    // finally falling back to string type.
-
-                    // An empty string or a string of "null" will be parsed
-                    // as a string rather than a true null value.
-                    // Likely strings are either empty values, very long values
-                    // or values with leading zeros like 001 (which are not safe
-                    // to assume are numbers)
-
-                    bool matched = false;
-                    bool has_dot = value.find(".") != std::string::npos;
-                    if (value.empty() || (value_length > 20) || (value_length > 1 && !has_dot && value[0] == '0'))
-                    {
-                        matched = true;
-                        desc_.add_descriptor(mapnik::attribute_descriptor(header, mapnik::String));
-                    }
-                    else if (csv_utils::is_likely_number(value))
-                    {
-                        bool has_e = value.find("e") != std::string::npos;
-                        if (has_dot || has_e)
-                        {
-                            double float_val = 0.0;
-                            if (mapnik::util::string2double(value,float_val))
-                            {
-                                matched = true;
-                                desc_.add_descriptor(mapnik::attribute_descriptor(header,mapnik::Double));
-                            }
-                        }
-                        else
-                        {
-                            mapnik::value_integer int_val = 0;
-                            if (mapnik::util::string2int(value,int_val))
-                            {
-                                matched = true;
-                                desc_.add_descriptor(mapnik::attribute_descriptor(header,mapnik::Integer));
-                            }
-                        }
-                    }
-                    if (!matched)
-                    {
-                        // NOTE: we don't use mapnik::util::string2bool
-                        // here because we don't want to treat 'on' and 'off'
-                        // as booleans, only 'true' and 'false'
-                        if (csv_utils::ignore_case_equal(value, "true") || csv_utils::ignore_case_equal(value, "false"))
-                        {
-                            desc_.add_descriptor(mapnik::attribute_descriptor(header, mapnik::Boolean));
-                        }
-                        else // fallback to normal string
-                        {
-                            desc_.add_descriptor(mapnik::attribute_descriptor(header, mapnik::String));
-                        }
-                    }
+                    matched = true;
+                    desc_.add_descriptor(mapnik::attribute_descriptor(header,mapnik::Integer));
                 }
             }
-            else
-            {
-                std::ostringstream s;
-                s << "CSV Plugin: expected geometry column: could not parse row "
-                  << line_number << " "
-                  << values.at(locator_.index) << "'";
-                throw mapnik::datasource_exception(s.str());
-            }
-        }
-        catch (mapnik::datasource_exception const& ex )
-        {
-            if (strict_) throw ex;
-            else
-            {
-                MAPNIK_LOG_ERROR(csv) << ex.what() << " at line: " << line_number;
-            }
         }
-        catch (std::exception const& ex)
+        if (!matched)
         {
-            std::ostringstream s;
-            s << "CSV Plugin: unexpected error parsing line: " << line_number
-              << " - found " << headers_.size() << " with values like: " << csv_line << "\n"
-              << " and got error like: " << ex.what();
-            if (strict_)
+            // NOTE: we don't use mapnik::util::string2bool
+            // here because we don't want to treat 'on' and 'off'
+            // as booleans, only 'true' and 'false'
+            if (csv_utils::ignore_case_equal(value, "true") || csv_utils::ignore_case_equal(value, "false"))
             {
-                throw mapnik::datasource_exception(s.str());
+                desc_.add_descriptor(mapnik::attribute_descriptor(header, mapnik::Boolean));
             }
-            else
+            else // fallback to normal string
             {
-                MAPNIK_LOG_ERROR(csv) << s.str();
+                desc_.add_descriptor(mapnik::attribute_descriptor(header, mapnik::String));
             }
         }
-        // return early if *.index is present
-        if (has_disk_index_) return;
     }
-    // bulk insert initialise r-tree
-    tree_ = std::make_unique<spatial_index_type>(boxes);
 }
 
 const char * csv_datasource::name()
@@ -483,8 +271,8 @@ mapnik::layer_descriptor csv_datasource::get_descriptor() const
     return desc_;
 }
 
-template <typename T>
-boost::optional<mapnik::datasource_geometry_t> csv_datasource::get_geometry_type_impl(T & stream) const
+boost::optional<mapnik::datasource_geometry_t>
+csv_datasource::get_geometry_type_impl(std::istream & stream) const
 {
     boost::optional<mapnik::datasource_geometry_t> result;
     if (tree_)
@@ -505,7 +293,7 @@ boost::optional<mapnik::datasource_geometry_t> csv_datasource::get_geometry_type
             try
             {
                 auto values = csv_utils::parse_line(str, separator_, quote_);
-                auto geom = detail::extract_geometry(values, locator_);
+                auto geom = csv_utils::extract_geometry(values, locator_);
                 result = mapnik::util::to_ds_type(geom);
                 if (result)
                 {
@@ -548,7 +336,7 @@ boost::optional<mapnik::datasource_geometry_t> csv_datasource::get_geometry_type
             try
             {
                 auto values = csv_utils::parse_line(str, separator_, quote_);
-                auto geom = detail::extract_geometry(values, locator_);
+                auto geom = csv_utils::extract_geometry(values, locator_);
                 result = mapnik::util::to_ds_type(geom);
                 if (result)
                 {
diff --git a/plugins/input/csv/csv_datasource.hpp b/plugins/input/csv/csv_datasource.hpp
index ac2482f..71cf2ea 100644
--- a/plugins/input/csv/csv_datasource.hpp
+++ b/plugins/input/csv/csv_datasource.hpp
@@ -32,6 +32,7 @@
 #include <mapnik/coord.hpp>
 #include <mapnik/feature_layer_desc.hpp>
 #include <mapnik/value_types.hpp>
+#include "csv_utils.hpp"
 
 #pragma GCC diagnostic push
 #include <mapnik/warning_ignore.hpp>
@@ -41,8 +42,8 @@
 #pragma GCC diagnostic pop
 
 // stl
+#include <iosfwd>
 #include <vector>
-#include <deque>
 #include <string>
 
 template <std::size_t Max, std::size_t Min>
@@ -67,7 +68,8 @@ struct options_type<csv_linear<Max,Min> >
 };
 }}}}}
 
-class csv_datasource : public mapnik::datasource
+class csv_datasource : public mapnik::datasource,
+                       private csv_utils::csv_file_parser
 {
 public:
     using box_type = mapnik::box2d<double>;
@@ -84,26 +86,15 @@ public:
     mapnik::layer_descriptor get_descriptor() const;
     boost::optional<mapnik::datasource_geometry_t> get_geometry_type() const;
 private:
-    template <typename T>
-    void parse_csv(T & stream);
-    template <typename T>
-    boost::optional<mapnik::datasource_geometry_t> get_geometry_type_impl(T & stream) const;
+    void parse_csv(std::istream & );
+    virtual void add_feature(mapnik::value_integer index, mapnik::csv_line const & values);
+    boost::optional<mapnik::datasource_geometry_t> get_geometry_type_impl(std::istream & ) const;
 
     mapnik::layer_descriptor desc_;
-    mapnik::box2d<double> extent_;
     std::string filename_;
-    mapnik::value_integer row_limit_;
     std::string inline_string_;
-    char separator_;
-    char quote_;
-    std::vector<std::string> headers_;
-    std::string manual_headers_;
-    bool strict_;
     mapnik::context_ptr ctx_;
-    bool extent_initialized_;
     std::unique_ptr<spatial_index_type> tree_;
-    detail::geometry_column_locator locator_;
-    bool has_disk_index_;
 };
 
 #endif // MAPNIK_CSV_DATASOURCE_HPP
diff --git a/plugins/input/csv/csv_featureset.cpp b/plugins/input/csv/csv_featureset.cpp
index 5017c82..1518112 100644
--- a/plugins/input/csv/csv_featureset.cpp
+++ b/plugins/input/csv/csv_featureset.cpp
@@ -31,7 +31,7 @@
 #include <vector>
 #include <deque>
 
-csv_featureset::csv_featureset(std::string const& filename, detail::geometry_column_locator const& locator, char separator, char quote,
+csv_featureset::csv_featureset(std::string const& filename, locator_type const& locator, char separator, char quote,
                                std::vector<std::string> const& headers, mapnik::context_ptr const& ctx, array_type && index_array)
     :
 #if defined(MAPNIK_MEMORY_MAPPED_FILE)
@@ -72,12 +72,12 @@ csv_featureset::~csv_featureset() {}
 mapnik::feature_ptr csv_featureset::parse_feature(char const* beg, char const* end)
 {
     auto values = csv_utils::parse_line(beg, end, separator_, quote_, headers_.size());
-    auto geom = detail::extract_geometry(values, locator_);
+    auto geom = csv_utils::extract_geometry(values, locator_);
     if (!geom.is<mapnik::geometry::geometry_empty>())
     {
         mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_, ++feature_id_));
         feature->set_geometry(std::move(geom));
-        detail::process_properties(*feature, headers_, values, locator_, tr_);
+        csv_utils::process_properties(*feature, headers_, values, locator_, tr_);
         return feature;
     }
     return mapnik::feature_ptr();
diff --git a/plugins/input/csv/csv_featureset.hpp b/plugins/input/csv/csv_featureset.hpp
index 8fbf77b..8828fa4 100644
--- a/plugins/input/csv/csv_featureset.hpp
+++ b/plugins/input/csv/csv_featureset.hpp
@@ -28,7 +28,6 @@
 #include "csv_utils.hpp"
 #include "csv_datasource.hpp"
 #include <deque>
-#include <cstdio>
 
 #if defined(MAPNIK_MEMORY_MAPPED_FILE)
 #pragma GCC diagnostic push
@@ -41,7 +40,7 @@
 
 class csv_featureset : public mapnik::Featureset
 {
-    using locator_type = detail::geometry_column_locator;
+    using locator_type = csv_utils::geometry_column_locator;
 public:
     using array_type = std::deque<csv_datasource::item_type>;
     csv_featureset(std::string const& filename,
@@ -70,7 +69,7 @@ private:
     array_type::const_iterator index_end_;
     mapnik::context_ptr ctx_;
     mapnik::value_integer feature_id_ = 0;
-    detail::geometry_column_locator const& locator_;
+    locator_type const& locator_;
     mapnik::transcoder tr_;
 };
 
diff --git a/plugins/input/csv/csv_getline.hpp b/plugins/input/csv/csv_getline.hpp
new file mode 100644
index 0000000..9dfe5de
--- /dev/null
+++ b/plugins/input/csv/csv_getline.hpp
@@ -0,0 +1,72 @@
+/*****************************************************************************
+ *
+ * This file is part of Mapnik (c++ mapping toolkit)
+ *
+ * Copyright (C) 2015 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_CSV_GETLINE_HPP
+#define MAPNIK_CSV_GETLINE_HPP
+
+#include <string>
+#include <istream>
+#include <streambuf>
+
+namespace csv_utils
+{
+
+template <class CharT, class Traits, class Allocator>
+std::basic_istream<CharT, Traits>& getline_csv(std::istream& is, std::basic_string<CharT,Traits,Allocator>& s, CharT delim, CharT quote)
+{
+    typename std::basic_string<CharT,Traits,Allocator>::size_type nread = 0;
+    typename std::basic_istream<CharT, Traits>::sentry sentry(is, true);
+    if (sentry)
+    {
+        std::basic_streambuf<CharT, Traits>* buf = is.rdbuf();
+        s.clear();
+        bool has_quote = false;
+        while (nread < s.max_size())
+        {
+            int c1 = buf->sbumpc();
+            if (Traits::eq_int_type(c1, Traits::eof()))
+            {
+                is.setstate(std::ios_base::eofbit);
+                break;
+            }
+            else
+            {
+                ++nread;
+                CharT c = Traits::to_char_type(c1);
+                if (Traits::eq(c, quote))
+                    has_quote = !has_quote;
+                if (!Traits::eq(c, delim) || has_quote)
+                    s.push_back(c);
+                else
+                    break;// Character is extracted but not appended.
+            }
+        }
+    }
+    if (nread == 0 || nread >= s.max_size())
+        is.setstate(std::ios_base::failbit);
+
+    return is;
+}
+
+}
+
+#endif // MAPNIK_CSV_GETLINE_HPP
diff --git a/plugins/input/csv/csv_index_featureset.cpp b/plugins/input/csv/csv_index_featureset.cpp
index c064579..e94f41b 100644
--- a/plugins/input/csv/csv_index_featureset.cpp
+++ b/plugins/input/csv/csv_index_featureset.cpp
@@ -37,7 +37,7 @@
 
 csv_index_featureset::csv_index_featureset(std::string const& filename,
                                            mapnik::filter_in_box const& filter,
-                                           detail::geometry_column_locator const& locator,
+                                           locator_type const& locator,
                                            char separator,
                                            char quote,
                                            std::vector<std::string> const& headers,
@@ -89,12 +89,12 @@ csv_index_featureset::~csv_index_featureset() {}
 mapnik::feature_ptr csv_index_featureset::parse_feature(char const* beg, char const* end)
 {
     auto values = csv_utils::parse_line(beg, end, separator_, quote_, headers_.size());
-    auto geom = detail::extract_geometry(values, locator_);
+    auto geom = csv_utils::extract_geometry(values, locator_);
     if (!geom.is<mapnik::geometry::geometry_empty>())
     {
         mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_, ++feature_id_));
         feature->set_geometry(std::move(geom));
-        detail::process_properties(*feature, headers_, values, locator_, tr_);
+        csv_utils::process_properties(*feature, headers_, values, locator_, tr_);
         return feature;
     }
     return mapnik::feature_ptr();
diff --git a/plugins/input/csv/csv_index_featureset.hpp b/plugins/input/csv/csv_index_featureset.hpp
index 1a2c637..e57a356 100644
--- a/plugins/input/csv/csv_index_featureset.hpp
+++ b/plugins/input/csv/csv_index_featureset.hpp
@@ -41,7 +41,7 @@
 class csv_index_featureset : public mapnik::Featureset
 {
     using value_type = std::pair<std::size_t, std::size_t>;
-    using locator_type = detail::geometry_column_locator;
+    using locator_type = csv_utils::geometry_column_locator;
 public:
 
     csv_index_featureset(std::string const& filename,
@@ -60,7 +60,7 @@ private:
     std::vector<std::string> headers_;
     mapnik::context_ptr ctx_;
     mapnik::value_integer feature_id_ = 0;
-    detail::geometry_column_locator const& locator_;
+    locator_type const& locator_;
     mapnik::transcoder tr_;
 #if defined (MAPNIK_MEMORY_MAPPED_FILE)
     using file_source_type = boost::interprocess::ibufferstream;
diff --git a/plugins/input/csv/csv_inline_featureset.cpp b/plugins/input/csv/csv_inline_featureset.cpp
index 195574b..2d91efc 100644
--- a/plugins/input/csv/csv_inline_featureset.cpp
+++ b/plugins/input/csv/csv_inline_featureset.cpp
@@ -33,7 +33,7 @@
 #include <deque>
 
 csv_inline_featureset::csv_inline_featureset(std::string const& inline_string,
-                                             detail::geometry_column_locator const& locator,
+                                             locator_type const& locator,
                                              char separator,
                                              char quote,
                                              std::vector<std::string> const& headers,
@@ -57,12 +57,12 @@ mapnik::feature_ptr csv_inline_featureset::parse_feature(std::string const& str)
     auto const* start = str.data();
     auto const* end = start + str.size();
     auto values = csv_utils::parse_line(start, end, separator_, quote_, headers_.size());
-    auto geom = detail::extract_geometry(values, locator_);
+    auto geom = csv_utils::extract_geometry(values, locator_);
     if (!geom.is<mapnik::geometry::geometry_empty>())
     {
         mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_, ++feature_id_));
         feature->set_geometry(std::move(geom));
-        detail::process_properties(*feature, headers_, values, locator_, tr_);
+        csv_utils::process_properties(*feature, headers_, values, locator_, tr_);
         return feature;
     }
     return mapnik::feature_ptr();
diff --git a/plugins/input/csv/csv_inline_featureset.hpp b/plugins/input/csv/csv_inline_featureset.hpp
index 3da9f63..4873cec 100644
--- a/plugins/input/csv/csv_inline_featureset.hpp
+++ b/plugins/input/csv/csv_inline_featureset.hpp
@@ -28,11 +28,10 @@
 #include "csv_utils.hpp"
 #include "csv_datasource.hpp"
 #include <deque>
-#include <cstdio>
 
 class csv_inline_featureset : public mapnik::Featureset
 {
-    using locator_type = detail::geometry_column_locator;
+    using locator_type = csv_utils::geometry_column_locator;
 public:
     using array_type = std::deque<csv_datasource::item_type>;
     csv_inline_featureset(std::string const& inline_string,
@@ -55,7 +54,7 @@ private:
     array_type::const_iterator index_end_;
     mapnik::context_ptr ctx_;
     mapnik::value_integer feature_id_ = 0;
-    detail::geometry_column_locator const& locator_;
+    locator_type const& locator_;
     mapnik::transcoder tr_;
 };
 
diff --git a/plugins/input/csv/csv_utils.cpp b/plugins/input/csv/csv_utils.cpp
new file mode 100644
index 0000000..217276f
--- /dev/null
+++ b/plugins/input/csv/csv_utils.cpp
@@ -0,0 +1,507 @@
+/*****************************************************************************
+ *
+ * This file is part of Mapnik (c++ mapping toolkit)
+ *
+ * Copyright (C) 2015 Artem Pavlenko
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *****************************************************************************/
+
+// mapnik
+#include <mapnik/debug.hpp>
+#include <mapnik/geometry.hpp>
+#include <mapnik/geometry_correct.hpp>
+#include <mapnik/wkt/wkt_factory.hpp>
+#include <mapnik/json/geometry_parser.hpp>
+#include <mapnik/util/conversions.hpp>
+#include <mapnik/util/trim.hpp>
+#include <mapnik/datasource.hpp>
+// csv grammar
+#include <mapnik/csv/csv_grammar_impl.hpp>
+//
+#include "csv_getline.hpp"
+#include "csv_utils.hpp"
+
+#include <fstream>
+#include <string>
+#include <cstdio>
+#include <algorithm>
+
+namespace csv_utils {
+namespace detail {
+
+std::size_t file_length(std::istream & stream)
+{
+    stream.seekg(0, std::ios::end);
+    return stream.tellg();
+}
+
+std::tuple<char, bool, char, char> autodetect_csv_flavour(std::istream & stream, std::size_t file_length)
+{
+    // autodetect newlines/quotes/separators
+    char newline = '\n'; // default
+    bool has_newline = false;
+    bool has_single_quote = false;
+    char quote = '"'; // default
+    char separator = ','; // default
+    // local counters
+    int num_commas = 0;
+    int num_tabs = 0;
+    int num_pipes = 0;
+    int num_semicolons = 0;
+
+    static std::size_t const max_size = 4000;
+    std::size_t size = std::min(file_length, max_size);
+    std::vector<char> buffer;
+    buffer.resize(size);
+    stream.read(buffer.data(), size);
+    for (auto c : buffer)
+    {
+        switch (c)
+        {
+        case '\r':
+            newline = '\r';
+            has_newline = true;
+            break;
+        case '\n':
+            has_newline = true;
+            break;
+        case '\'':
+            if (!has_single_quote)
+            {
+                quote = c;
+                has_single_quote = true;
+            }
+            break;
+        case ',':
+            if (!has_newline) ++num_commas;
+            break;
+        case '\t':
+            if (!has_newline) ++num_tabs;
+            break;
+        case '|':
+            if (!has_newline) ++num_pipes;
+            break;
+        case ';':
+           if (!has_newline) ++num_semicolons;
+            break;
+        }
+    }
+    // detect separator
+    if (num_tabs > 0 && num_tabs > num_commas)
+    {
+        separator = '\t';
+        MAPNIK_LOG_DEBUG(csv) << "csv_datasource: auto detected tab separator";
+    }
+    else // pipes/semicolons
+    {
+        if (num_pipes > num_commas)
+        {
+            separator = '|';
+            MAPNIK_LOG_DEBUG(csv) << "csv_datasource: auto detected '|' separator";
+        }
+        else  if (num_semicolons > num_commas)
+        {
+            separator = ';';
+            MAPNIK_LOG_DEBUG(csv) << "csv_datasource: auto detected ';' separator";
+        }
+    }
+
+    if (has_newline && has_single_quote)
+    {
+        std::istringstream ss(std::string(buffer.begin(), buffer.end()));
+        std::size_t num_columns = 0;
+        for (std::string line; csv_utils::getline_csv(ss, line, newline, quote); )
+        {
+            if (size < file_length && ss.eof())
+            {
+                // we can't be sure that last line
+                // is not truncated so skip it
+                break;
+            }
+            if (line.size() == 0 || (line.size() == 1 && line[0] == char(0xa))) continue; // empty lines are not interesting
+            auto num_quotes = std::count(line.begin(), line.end(), quote);
+            if (num_quotes % 2 != 0)
+            {
+                quote = '"';
+                break;
+            }
+            auto columns = csv_utils::parse_line(line, separator, quote);
+            if (num_columns > 0 && num_columns != columns.size())
+            {
+                quote = '"';
+                break;
+            }
+            num_columns = columns.size();
+        }
+    }
+    return std::make_tuple(newline, has_newline, separator, quote);
+}
+
+void locate_geometry_column(std::string const& header, std::size_t index, geometry_column_locator & locator)
+{
+    std::string lower_val(header);
+    std::transform(lower_val.begin(), lower_val.end(), lower_val.begin(), ::tolower);
+    if (lower_val == "wkt" || (lower_val.find("geom") != std::string::npos))
+    {
+        locator.type = geometry_column_locator::WKT;
+        locator.index = index;
+    }
+    else if (lower_val == "geojson")
+    {
+        locator.type = geometry_column_locator::GEOJSON;
+        locator.index = index;
+    }
+    else if (lower_val == "x" || lower_val == "lon"
+             || lower_val == "lng" || lower_val == "long"
+             || (lower_val.find("longitude") != std::string::npos))
+    {
+        locator.index = index;
+        locator.type = geometry_column_locator::LON_LAT;
+    }
+
+    else if (lower_val == "y"
+             || lower_val == "lat"
+             || (lower_val.find("latitude") != std::string::npos))
+    {
+        locator.index2 = index;
+        locator.type = geometry_column_locator::LON_LAT;
+    }
+}
+
+bool valid(geometry_column_locator const& locator, std::size_t max_size)
+{
+    if (locator.type == geometry_column_locator::UNKNOWN) return false;
+    if (locator.index >= max_size) return false;
+    if (locator.type == geometry_column_locator::LON_LAT && locator.index2 >= max_size) return false;
+    return true;
+}
+
+} // namespace detail
+
+static const mapnik::csv_line_grammar<char const*> line_g;
+static const mapnik::csv_white_space_skipper skipper{};
+
+mapnik::csv_line parse_line(char const* start, char const* end, char separator, char quote, std::size_t num_columns)
+{
+    mapnik::csv_line values;
+    if (num_columns > 0) values.reserve(num_columns);
+    if (!boost::spirit::qi::phrase_parse(start, end, (line_g)(separator, quote), skipper, values))
+    {
+        throw mapnik::datasource_exception("Failed to parse CSV line:\n" + std::string(start, end));
+    }
+    return values;
+}
+
+mapnik::csv_line parse_line(std::string const& line_str, char separator, char quote)
+{
+    auto start = line_str.c_str();
+    auto end   = start + line_str.length();
+    return parse_line(start, end, separator, quote, 0);
+}
+
+
+bool is_likely_number(std::string const& value)
+{
+    return (std::strspn( value.c_str(), "e-.+0123456789" ) == value.size());
+}
+
+struct ignore_case_equal_pred
+{
+    bool operator () (unsigned char a, unsigned char b) const
+    {
+        return std::tolower(a) == std::tolower(b);
+    }
+};
+
+bool ignore_case_equal(std::string const& s0, std::string const& s1)
+{
+    return std::equal(s0.begin(), s0.end(),
+                      s1.begin(), ignore_case_equal_pred());
+}
+
+void csv_file_parser::add_feature(mapnik::value_integer, mapnik::csv_line const & )
+{
+    // no-op by default
+}
+
+template <typename T>
+void csv_file_parser::parse_csv_and_boxes(std::istream & csv_file, T & boxes)
+{
+    using boxes_type = T;
+    using box_type = typename boxes_type::value_type::first_type;
+
+    auto file_length = detail::file_length(csv_file);
+    // set back to start
+    csv_file.seekg(0, std::ios::beg);
+    char newline;
+    bool has_newline;
+    char detected_quote;
+    char detected_separator;
+    std::tie(newline, has_newline, detected_separator, detected_quote) = detail::autodetect_csv_flavour(csv_file, file_length);
+    if (quote_ == 0) quote_ = detected_quote;
+    if (separator_ == 0) separator_ = detected_separator;
+
+    // set back to start
+    MAPNIK_LOG_DEBUG(csv) << "csv_datasource: separator: '" << separator_
+                          << "' quote: '" << quote_ << "'";
+
+    // rewind stream
+    csv_file.seekg(0, std::ios::beg);
+    //
+    std::string csv_line;
+    csv_utils::getline_csv(csv_file, csv_line, newline, quote_);
+    csv_file.seekg(0, std::ios::beg);
+    int line_number = 0;
+    if (!manual_headers_.empty())
+    {
+        std::size_t index = 0;
+        auto headers = csv_utils::parse_line(manual_headers_, separator_, quote_);
+        headers_.reserve(headers.size());
+        for (auto const& header : headers)
+        {
+            detail::locate_geometry_column(header, index++, locator_);
+            headers_.push_back(header);
+        }
+    }
+    else // parse first line as headers
+    {
+        while (csv_utils::getline_csv(csv_file, csv_line, newline, quote_))
+        {
+            try
+            {
+                auto headers = csv_utils::parse_line(csv_line, separator_, quote_);
+                // skip blank lines
+                if (headers.size() > 0 && headers[0].empty()) ++line_number;
+                else
+                {
+                    std::size_t index = 0;
+                    headers_.reserve(headers.size());
+                    for (auto & header : headers)
+                    {
+                        mapnik::util::trim(header);
+                        if (header.empty())
+                        {
+                            if (strict_)
+                            {
+                                std::ostringstream s;
+                                s << "CSV Plugin: expected a column header at line ";
+                                s << line_number << ", column " << index;
+                                s << " - ensure this row contains valid header fields: '";
+                                s << csv_line;
+                                throw mapnik::datasource_exception(s.str());
+                            }
+                            else
+                            {
+                                // create a placeholder for the empty header
+                                std::ostringstream s;
+                                s << "_" << index;
+                                headers_.push_back(s.str());
+                            }
+                        }
+                        else
+                        {
+                            detail::locate_geometry_column(header, index, locator_);
+                            headers_.push_back(header);
+                        }
+                        ++index;
+                    }
+                    ++line_number;
+                    break;
+                }
+            }
+            catch (std::exception const& ex)
+            {
+                std::string s("CSV Plugin: error parsing headers: ");
+                s += ex.what();
+                throw mapnik::datasource_exception(s);
+            }
+        }
+    }
+
+    std::size_t num_headers = headers_.size();
+    if (!detail::valid(locator_, num_headers))
+    {
+        std::string str("CSV Plugin: could not detect column(s) with the name(s) of wkt, geojson, x/y, or ");
+        str += "latitude/longitude in:\n";
+        str += csv_line;
+        str += "\n - this is required for reading geometry data";
+        throw mapnik::datasource_exception(str);
+    }
+
+    mapnik::value_integer feature_count = 0;
+    auto pos = csv_file.tellg();
+    // handle rare case of a single line of data and user-provided headers
+    // where a lack of a newline will mean that csv_utils::getline_csv returns false
+    bool is_first_row = false;
+
+    if (!has_newline)
+    {
+        csv_file.setstate(std::ios::failbit);
+        pos = 0;
+        if (!csv_line.empty())
+        {
+            is_first_row = true;
+        }
+    }
+
+    while (is_first_row || csv_utils::getline_csv(csv_file, csv_line, newline, quote_))
+    {
+        ++line_number;
+        if ((row_limit_ > 0) && (line_number > row_limit_))
+        {
+            MAPNIK_LOG_DEBUG(csv) << "csv_datasource: row limit hit, exiting at feature: " << feature_count;
+            break;
+        }
+        auto record_offset = pos;
+        auto record_size = csv_line.length();
+        pos = csv_file.tellg();
+        is_first_row = false;
+
+        // skip blank lines
+        if (record_size <= 10)
+        {
+            std::string trimmed = csv_line;
+            boost::trim_if(trimmed, boost::algorithm::is_any_of("\",'\r\n "));
+            if (trimmed.empty())
+            {
+                MAPNIK_LOG_DEBUG(csv) << "csv_datasource: empty row encountered at line: " << line_number;
+                continue;
+            }
+        }
+
+        try
+        {
+            auto const* line_start = csv_line.data();
+            auto const* line_end = line_start + csv_line.size();
+            auto values = csv_utils::parse_line(line_start, line_end, separator_, quote_, num_headers);
+            unsigned num_fields = values.size();
+            if (num_fields != num_headers)
+            {
+                std::ostringstream s;
+                s << "CSV Plugin: # of columns(" << num_fields << ")";
+                if (num_fields > num_headers)
+                {
+                    s << " > ";
+                }
+                else
+                {
+                    s << " < ";
+                }
+                s << "# of headers(" << num_headers << ") parsed";
+                throw mapnik::datasource_exception(s.str());
+            }
+
+            auto geom = extract_geometry(values, locator_);
+            if (!geom.is<mapnik::geometry::geometry_empty>())
+            {
+                auto box = mapnik::geometry::envelope(geom);
+                if (!extent_initialized_)
+                {
+                    if (extent_.valid())
+                        extent_.expand_to_include(box);
+                    else
+                        extent_ = box;
+                }
+                boxes.emplace_back(box_type(box), make_pair(record_offset, record_size));
+                add_feature(++feature_count, values);
+            }
+            else
+            {
+                std::ostringstream s;
+                s << "CSV Plugin: expected geometry column: could not parse row "
+                  << line_number << " "
+                  << values.at(locator_.index) << "'";
+                throw mapnik::datasource_exception(s.str());
+            }
+        }
+        catch (mapnik::datasource_exception const& ex )
+        {
+            if (strict_) throw ex;
+            else
+            {
+                MAPNIK_LOG_ERROR(csv) << ex.what() << " at line: " << line_number;
+            }
+        }
+        catch (std::exception const& ex)
+        {
+            std::ostringstream s;
+            s << "CSV Plugin: unexpected error parsing line: " << line_number
+              << " - found " << headers_.size() << " with values like: " << csv_line << "\n"
+              << " and got error like: " << ex.what();
+            if (strict_)
+            {
+                throw mapnik::datasource_exception(s.str());
+            }
+            else
+            {
+                MAPNIK_LOG_ERROR(csv) << s.str();
+            }
+        }
+        // return early if *.index is present
+        if (has_disk_index_) return;
+    }
+}
+
+
+mapnik::geometry::geometry<double> extract_geometry(std::vector<std::string> const& row, geometry_column_locator const& locator)
+{
+    mapnik::geometry::geometry<double> geom;
+    if (locator.type == geometry_column_locator::WKT)
+    {
+        auto wkt_value = row.at(locator.index);
+        if (mapnik::from_wkt(wkt_value, geom))
+        {
+            // correct orientations ..
+            mapnik::geometry::correct(geom);
+        }
+        else
+        {
+            throw mapnik::datasource_exception("Failed to parse WKT: '" + wkt_value + "'");
+        }
+    }
+    else if (locator.type == geometry_column_locator::GEOJSON)
+    {
+
+        auto json_value = row.at(locator.index);
+        if (!mapnik::json::from_geojson(json_value, geom))
+        {
+            throw mapnik::datasource_exception("Failed to parse GeoJSON: '" + json_value + "'");
+        }
+    }
+    else if (locator.type == geometry_column_locator::LON_LAT)
+    {
+        double x, y;
+        auto long_value = row.at(locator.index);
+        auto lat_value = row.at(locator.index2);
+        if (!mapnik::util::string2double(long_value,x))
+        {
+            throw mapnik::datasource_exception("Failed to parse Longitude: '" + long_value + "'");
+        }
+        if (!mapnik::util::string2double(lat_value,y))
+        {
+            throw mapnik::datasource_exception("Failed to parse Latitude: '" + lat_value + "'");
+        }
+        geom = mapnik::geometry::point<double>(x,y);
+    }
+    return geom;
+}
+
+template void csv_file_parser::parse_csv_and_boxes(std::istream & csv_file, std::vector<std::pair<mapnik::box2d<double>, std::pair<std::size_t, std::size_t>>> & boxes);
+
+template void csv_file_parser::parse_csv_and_boxes(std::istream & csv_file, std::vector<std::pair<mapnik::box2d<float>, std::pair<std::size_t, std::size_t>>> & boxes);
+
+} // namespace csv_utils
diff --git a/plugins/input/csv/csv_utils.hpp b/plugins/input/csv/csv_utils.hpp
index 4171d45..df976e3 100644
--- a/plugins/input/csv/csv_utils.hpp
+++ b/plugins/input/csv/csv_utils.hpp
@@ -24,220 +24,26 @@
 #define MAPNIK_CSV_UTILS_DATASOURCE_HPP
 
 // mapnik
-#include <mapnik/debug.hpp>
+#include <mapnik/box2d.hpp>
 #include <mapnik/geometry.hpp>
-#include <mapnik/geometry_correct.hpp>
-#include <mapnik/wkt/wkt_factory.hpp>
-#include <mapnik/json/geometry_parser.hpp>
+#include <mapnik/value_types.hpp>
 #include <mapnik/util/conversions.hpp>
-#include <mapnik/csv/csv_grammar.hpp>
 #include <mapnik/util/trim.hpp>
-#include <mapnik/datasource.hpp>
-
-#pragma GCC diagnostic push
-#include <mapnik/warning_ignore.hpp>
-#include <boost/algorithm/string.hpp>
-#pragma GCC diagnostic pop
+#include <mapnik/csv/csv_types.hpp>
 
+// std
+#include <iosfwd>
 #include <string>
-#include <cstdio>
-#include <algorithm>
-
-namespace csv_utils
-{
-
-static const mapnik::csv_line_grammar<char const*> line_g;
-static const mapnik::csv_white_space_skipper skipper{};
-
-template <typename Iterator>
-static mapnik::csv_line parse_line(Iterator start, Iterator end, char separator, char quote, std::size_t num_columns)
-{
-    mapnik::csv_line values;
-    if (num_columns > 0) values.reserve(num_columns);
-    if (!boost::spirit::qi::phrase_parse(start, end, (line_g)(separator, quote), skipper, values))
-    {
-        throw mapnik::datasource_exception("Failed to parse CSV line:\n" + std::string(start, end));
-    }
-    return values;
-}
-
-static inline mapnik::csv_line parse_line(std::string const& line_str, char separator, char quote)
-{
-    auto start = line_str.c_str();
-    auto end   = start + line_str.length();
-    return parse_line(start, end, separator, quote, 0);
-}
-
-static inline bool is_likely_number(std::string const& value)
-{
-    return (std::strspn( value.c_str(), "e-.+0123456789" ) == value.size());
-}
-
-struct ignore_case_equal_pred
-{
-    bool operator () (unsigned char a, unsigned char b) const
-    {
-        return std::tolower(a) == std::tolower(b);
-    }
-};
-
-inline bool ignore_case_equal(std::string const& s0, std::string const& s1)
-{
-    return std::equal(s0.begin(), s0.end(),
-                      s1.begin(), ignore_case_equal_pred());
-}
-
-template <class CharT, class Traits, class Allocator>
-std::basic_istream<CharT, Traits>& getline_csv(std::istream& is, std::basic_string<CharT,Traits,Allocator>& s, CharT delim, CharT quote)
-{
-    typename std::basic_string<CharT,Traits,Allocator>::size_type nread = 0;
-    typename std::basic_istream<CharT, Traits>::sentry sentry(is, true);
-    if (sentry)
-    {
-        std::basic_streambuf<CharT, Traits>* buf = is.rdbuf();
-        s.clear();
-        bool has_quote = false;
-        while (nread < s.max_size())
-        {
-            int c1 = buf->sbumpc();
-            if (Traits::eq_int_type(c1, Traits::eof()))
-            {
-                is.setstate(std::ios_base::eofbit);
-                break;
-            }
-            else
-            {
-                ++nread;
-                CharT c = Traits::to_char_type(c1);
-                if (Traits::eq(c, quote))
-                    has_quote = !has_quote;
-                if (!Traits::eq(c, delim) || has_quote)
-                    s.push_back(c);
-                else
-                    break;// Character is extracted but not appended.
-            }
-        }
-    }
-    if (nread == 0 || nread >= s.max_size())
-        is.setstate(std::ios_base::failbit);
-
-    return is;
-}
-
-}
+#include <vector>
 
+namespace csv_utils {
 
-namespace detail {
+mapnik::csv_line parse_line(char const* start, char const* end, char separator, char quote, std::size_t num_columns);
+mapnik::csv_line parse_line(std::string const& line_str, char separator, char quote);
 
-template <typename T>
-std::size_t file_length(T & stream)
-{
-    stream.seekg(0, std::ios::end);
-    return stream.tellg();
-}
+bool is_likely_number(std::string const& value);
 
-template <typename T>
-std::tuple<char, bool, char, char> autodect_csv_flavour(T & stream, std::size_t file_length)
-{
-    // autodetect newlines/quotes/separators
-    char newline = '\n'; // default
-    bool has_newline = false;
-    bool has_single_quote = false;
-    char quote = '"'; // default
-    char separator = ','; // default
-    // local counters
-    int num_commas = 0;
-    int num_tabs = 0;
-    int num_pipes = 0;
-    int num_semicolons = 0;
-
-    static std::size_t const max_size = 4000;
-    std::size_t size = std::min(file_length, max_size);
-    std::vector<char> buffer;
-    buffer.resize(size);
-    stream.read(buffer.data(), size);
-    for (auto c : buffer)
-    {
-        switch (c)
-        {
-        case '\r':
-            newline = '\r';
-            has_newline = true;
-            break;
-        case '\n':
-            has_newline = true;
-            break;
-        case '\'':
-            if (!has_single_quote)
-            {
-                quote = c;
-                has_single_quote = true;
-            }
-            break;
-        case ',':
-            if (!has_newline) ++num_commas;
-            break;
-        case '\t':
-            if (!has_newline) ++num_tabs;
-            break;
-        case '|':
-            if (!has_newline) ++num_pipes;
-            break;
-        case ';':
-           if (!has_newline) ++num_semicolons;
-            break;
-        }
-    }
-    // detect separator
-    if (num_tabs > 0 && num_tabs > num_commas)
-    {
-        separator = '\t';
-        MAPNIK_LOG_DEBUG(csv) << "csv_datasource: auto detected tab separator";
-    }
-    else // pipes/semicolons
-    {
-        if (num_pipes > num_commas)
-        {
-            separator = '|';
-            MAPNIK_LOG_DEBUG(csv) << "csv_datasource: auto detected '|' separator";
-        }
-        else  if (num_semicolons > num_commas)
-        {
-            separator = ';';
-            MAPNIK_LOG_DEBUG(csv) << "csv_datasource: auto detected ';' separator";
-        }
-    }
-
-    if (has_newline && has_single_quote)
-    {
-        std::istringstream ss(std::string(buffer.begin(), buffer.end()));
-        std::size_t num_columns = 0;
-        for (std::string line; csv_utils::getline_csv(ss, line, newline, quote); )
-        {
-            if (size < file_length && ss.eof())
-            {
-                // we can't be sure last line
-                // is not truncated so skip it
-                break;
-            }
-            if (line.size() == 0) continue; // empty lines are not interesting
-            auto num_quotes = std::count(line.begin(), line.end(), quote);
-            if (num_quotes % 2 != 0)
-            {
-                quote = '"';
-                break;
-            }
-            auto columns = csv_utils::parse_line(line, separator, quote);
-            if (num_columns > 0 && num_columns != columns.size())
-            {
-                quote = '"';
-                break;
-            }
-            num_columns = columns.size();
-        }
-    }
-    return std::make_tuple(newline, has_newline, separator, quote);
-}
+bool ignore_case_equal(std::string const& s0, std::string const& s1);
 
 struct geometry_column_locator
 {
@@ -249,87 +55,8 @@ struct geometry_column_locator
     std::size_t index2;
 };
 
-static inline void locate_geometry_column(std::string const& header, std::size_t index, geometry_column_locator & locator)
-{
-    std::string lower_val(header);
-    std::transform(lower_val.begin(), lower_val.end(), lower_val.begin(), ::tolower);
-    if (lower_val == "wkt" || (lower_val.find("geom") != std::string::npos))
-    {
-        locator.type = geometry_column_locator::WKT;
-        locator.index = index;
-    }
-    else if (lower_val == "geojson")
-    {
-        locator.type = geometry_column_locator::GEOJSON;
-        locator.index = index;
-    }
-    else if (lower_val == "x" || lower_val == "lon"
-             || lower_val == "lng" || lower_val == "long"
-             || (lower_val.find("longitude") != std::string::npos))
-    {
-        locator.index = index;
-        locator.type = geometry_column_locator::LON_LAT;
-    }
 
-    else if (lower_val == "y"
-             || lower_val == "lat"
-             || (lower_val.find("latitude") != std::string::npos))
-    {
-        locator.index2 = index;
-        locator.type = geometry_column_locator::LON_LAT;
-    }
-}
-
-static inline bool valid(geometry_column_locator const& locator, std::size_t max_size)
-{
-    if (locator.type == geometry_column_locator::UNKNOWN) return false;
-    if (locator.index >= max_size) return false;
-    if (locator.type == geometry_column_locator::LON_LAT && locator.index2 >= max_size) return false;
-    return true;
-}
-
-static inline mapnik::geometry::geometry<double> extract_geometry(std::vector<std::string> const& row, geometry_column_locator const& locator)
-{
-    mapnik::geometry::geometry<double> geom;
-    if (locator.type == geometry_column_locator::WKT)
-    {
-        auto wkt_value = row.at(locator.index);
-        if (mapnik::from_wkt(wkt_value, geom))
-        {
-            // correct orientations ..
-            mapnik::geometry::correct(geom);
-        }
-        else
-        {
-            throw mapnik::datasource_exception("Failed to parse WKT: '" + wkt_value + "'");
-        }
-    }
-    else if (locator.type == geometry_column_locator::GEOJSON)
-    {
-
-        auto json_value = row.at(locator.index);
-        if (!mapnik::json::from_geojson(json_value, geom))
-        {
-            throw mapnik::datasource_exception("Failed to parse GeoJSON: '" + json_value + "'");
-        }
-    }
-    else if (locator.type == geometry_column_locator::LON_LAT)
-    {
-        double x, y;
-        auto long_value = row.at(locator.index);
-        auto lat_value = row.at(locator.index2);
-        if (!mapnik::util::string2double(long_value,x))
-        {
-            throw mapnik::datasource_exception("Failed to parse Longitude: '" + long_value + "'");
-        }
-        if (!mapnik::util::string2double(lat_value,y))
-        {
-            throw mapnik::datasource_exception("Failed to parse Latitude: '" + lat_value + "'");
-        }
-        geom = mapnik::geometry::point<double>(x,y);
-    }
-    return geom;
-}
+mapnik::geometry::geometry<double> extract_geometry(std::vector<std::string> const& row, geometry_column_locator const& locator);
 
 template <typename Feature, typename Headers, typename Values, typename Locator, typename Transcoder>
 void process_properties(Feature & feature, Headers const& headers, Values const& values, Locator const& locator, Transcoder const& tr)
@@ -348,8 +75,8 @@ void process_properties(Feature & feature, Headers const& headers, Values const&
         std::string value = mapnik::util::trim_copy(*val_beg++);
         int value_length = value.length();
 
-        if (locator.index == i && (locator.type == detail::geometry_column_locator::WKT
-                                   || locator.type == detail::geometry_column_locator::GEOJSON)  ) continue;
+        if (locator.index == i && (locator.type == geometry_column_locator::WKT
+                                   || locator.type == geometry_column_locator::GEOJSON)  ) continue;
 
 
         bool matched = false;
@@ -401,7 +128,25 @@ void process_properties(Feature & feature, Headers const& headers, Values const&
     }
 }
 
+struct csv_file_parser
+{
+    template <typename T>
+    void parse_csv_and_boxes(std::istream & csv_file, T & boxes);
+
+    virtual void add_feature(mapnik::value_integer index, mapnik::csv_line const & values);
+
+    std::vector<std::string> headers_;
+    std::string manual_headers_;
+    geometry_column_locator locator_;
+    mapnik::box2d<double> extent_;
+    mapnik::value_integer row_limit_ = 0;
+    char separator_ = '\0';
+    char quote_ = '\0';
+    bool strict_ = false;
+    bool extent_initialized_ = false;
+    bool has_disk_index_ = false;
+};
 
-}// ns detail
+} // namespace csv_utils
 
 #endif // MAPNIK_CSV_UTILS_DATASOURCE_HPP
diff --git a/plugins/input/gdal/gdal_datasource.cpp b/plugins/input/gdal/gdal_datasource.cpp
index 8a06a92..07cec47 100644
--- a/plugins/input/gdal/gdal_datasource.cpp
+++ b/plugins/input/gdal/gdal_datasource.cpp
@@ -45,21 +45,27 @@ using mapnik::layer_descriptor;
 using mapnik::datasource_exception;
 
 
+static bool GDALAllRegister_once_()
+{
+    static bool const quiet_unused = (GDALAllRegister(), true);
+    return quiet_unused;
+}
+
 gdal_datasource::gdal_datasource(parameters const& params)
     : datasource(params),
-      dataset_(nullptr),
+      dataset_(nullptr, &GDALClose),
       desc_(gdal_datasource::name(), "utf-8"),
       nodata_value_(params.get<double>("nodata")),
       nodata_tolerance_(*params.get<double>("nodata_tolerance",1e-12))
 {
     MAPNIK_LOG_DEBUG(gdal) << "gdal_datasource: Initializing...";
 
+    GDALAllRegister_once_();
+
 #ifdef MAPNIK_STATS
     mapnik::progress_timer __stats__(std::clog, "gdal_datasource::init");
 #endif
 
-    GDALAllRegister();
-
     boost::optional<std::string> file = params.get<std::string>("file");
     if (! file) throw datasource_exception("missing <file> parameter");
 
@@ -79,12 +85,14 @@ gdal_datasource::gdal_datasource(parameters const& params)
 #if GDAL_VERSION_NUM >= 1600
     if (shared_dataset_)
     {
-        dataset_ = reinterpret_cast<GDALDataset*>(GDALOpenShared((dataset_name_).c_str(), GA_ReadOnly));
+        auto ds = GDALOpenShared(dataset_name_.c_str(), GA_ReadOnly);
+        dataset_.reset(static_cast<GDALDataset*>(ds));
     }
     else
 #endif
     {
-        dataset_ = reinterpret_cast<GDALDataset*>(GDALOpen((dataset_name_).c_str(), GA_ReadOnly));
+        auto ds = GDALOpen(dataset_name_.c_str(), GA_ReadOnly);
+        dataset_.reset(static_cast<GDALDataset*>(ds));
     }
 
     if (! dataset_)
@@ -92,7 +100,7 @@ gdal_datasource::gdal_datasource(parameters const& params)
         throw datasource_exception(CPLGetLastErrorMsg());
     }
 
-    MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: opened Dataset=" << dataset_;
+    MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: opened Dataset=" << dataset_.get();
 
     nbands_ = dataset_->GetRasterCount();
     width_ = dataset_->GetRasterXSize();
@@ -182,8 +190,7 @@ gdal_datasource::gdal_datasource(parameters const& params)
 
 gdal_datasource::~gdal_datasource()
 {
-    MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Closing Dataset=" << dataset_;
-    GDALClose(dataset_);
+    MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Closing Dataset=" << dataset_.get();
 }
 
 datasource::datasource_t gdal_datasource::type() const
@@ -217,12 +224,9 @@ featureset_ptr gdal_datasource::features(query const& q) const
     mapnik::progress_timer __stats__(std::clog, "gdal_datasource::features");
 #endif
 
-    gdal_query gq = q;
-
-    // TODO - move to std::make_shared, but must reduce # of args to <= 9
-    return featureset_ptr(new gdal_featureset(*dataset_,
+    return std::make_shared<gdal_featureset>(*dataset_,
                                               band_,
-                                              gq,
+                                              gdal_query(q),
                                               extent_,
                                               width_,
                                               height_,
@@ -230,7 +234,7 @@ featureset_ptr gdal_datasource::features(query const& q) const
                                               dx_,
                                               dy_,
                                               nodata_value_,
-                                              nodata_tolerance_));
+                                              nodata_tolerance_);
 }
 
 featureset_ptr gdal_datasource::features_at_point(coord2d const& pt, double tol) const
@@ -239,12 +243,9 @@ featureset_ptr gdal_datasource::features_at_point(coord2d const& pt, double tol)
     mapnik::progress_timer __stats__(std::clog, "gdal_datasource::features_at_point");
 #endif
 
-    gdal_query gq = pt;
-
-    // TODO - move to std::make_shared, but must reduce # of args to <= 9
-    return featureset_ptr(new gdal_featureset(*dataset_,
+    return std::make_shared<gdal_featureset>(*dataset_,
                                               band_,
-                                              gq,
+                                              gdal_query(pt),
                                               extent_,
                                               width_,
                                               height_,
@@ -252,5 +253,5 @@ featureset_ptr gdal_datasource::features_at_point(coord2d const& pt, double tol)
                                               dx_,
                                               dy_,
                                               nodata_value_,
-                                              nodata_tolerance_));
+                                              nodata_tolerance_);
 }
diff --git a/plugins/input/gdal/gdal_datasource.hpp b/plugins/input/gdal/gdal_datasource.hpp
index 7e7b221..3fc3036 100644
--- a/plugins/input/gdal/gdal_datasource.hpp
+++ b/plugins/input/gdal/gdal_datasource.hpp
@@ -55,8 +55,7 @@ public:
     boost::optional<mapnik::datasource_geometry_t> get_geometry_type() const;
     mapnik::layer_descriptor get_descriptor() const;
 private:
-    GDALDataset* open_dataset() const;
-    GDALDataset* dataset_;
+    std::unique_ptr<GDALDataset, decltype(&GDALClose)> dataset_;
     mapnik::box2d<double> extent_;
     std::string dataset_name_;
     int band_;
diff --git a/plugins/input/gdal/gdal_featureset.cpp b/plugins/input/gdal/gdal_featureset.cpp
index 968fc6d..fe1fe64 100644
--- a/plugins/input/gdal/gdal_featureset.cpp
+++ b/plugins/input/gdal/gdal_featureset.cpp
@@ -21,7 +21,7 @@
  *****************************************************************************/
 
 // mapnik
-#include <mapnik/make_unique.hpp>
+#include <mapnik/datasource.hpp>
 #include <mapnik/global.hpp>
 #include <mapnik/debug.hpp>
 #include <mapnik/image.hpp>
@@ -29,7 +29,6 @@
 #include <mapnik/view_transform.hpp>
 #include <mapnik/feature.hpp>
 #include <mapnik/feature_factory.hpp>
-#include <mapnik/util/variant.hpp>
 
 // stl
 #include <cmath>
@@ -39,8 +38,6 @@
 #include "gdal_featureset.hpp"
 #include <gdal_priv.h>
 
-using mapnik::query;
-using mapnik::coord2d;
 using mapnik::box2d;
 using mapnik::feature_ptr;
 using mapnik::view_transform;
@@ -77,8 +74,6 @@ gdal_featureset::gdal_featureset(GDALDataset& dataset,
 
 gdal_featureset::~gdal_featureset()
 {
-    MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Closing Dataset=" << &dataset_;
-
 }
 
 feature_ptr gdal_featureset::next()
diff --git a/plugins/input/gdal/gdal_featureset.hpp b/plugins/input/gdal/gdal_featureset.hpp
index b909211..639028b 100644
--- a/plugins/input/gdal/gdal_featureset.hpp
+++ b/plugins/input/gdal/gdal_featureset.hpp
@@ -24,13 +24,12 @@
 #define GDAL_FEATURESET_HPP
 
 // mapnik
-#include <mapnik/feature.hpp>
+#include <mapnik/featureset.hpp>
+#include <mapnik/query.hpp>
 #include <mapnik/util/variant.hpp>
 // boost
 #include <boost/optional.hpp>
 
-#include "gdal_datasource.hpp"
-
 class GDALDataset;
 class GDALRasterBand;
 
diff --git a/plugins/input/geojson/geojson_datasource.cpp b/plugins/input/geojson/geojson_datasource.cpp
index d63e243..e9456f8 100644
--- a/plugins/input/geojson/geojson_datasource.cpp
+++ b/plugins/input/geojson/geojson_datasource.cpp
@@ -151,7 +151,7 @@ geojson_datasource::geojson_datasource(parameters const& params)
         cache_features_ = *params.get<mapnik::boolean_type>("cache_features", true);
 #if !defined(MAPNIK_MEMORY_MAPPED_FILE)
         mapnik::util::file file(filename_);
-        if (!file.open())
+        if (!file)
         {
             throw mapnik::datasource_exception("GeoJSON Plugin: could not open: '" + filename_ + "'");
         }
@@ -192,12 +192,14 @@ geojson_datasource::geojson_datasource(parameters const& params)
 }
 
 namespace {
+using box_type = box2d<double>;
+using boxes_type = std::vector<std::pair<box_type, std::pair<std::size_t, std::size_t>>>;
 using base_iterator_type = char const*;
 const mapnik::transcoder geojson_datasource_static_tr("utf8");
 const mapnik::json::feature_collection_grammar<base_iterator_type,mapnik::feature_impl> geojson_datasource_static_fc_grammar(geojson_datasource_static_tr);
 const mapnik::json::feature_grammar_callback<base_iterator_type,mapnik::feature_impl> geojson_datasource_static_feature_callback_grammar(geojson_datasource_static_tr);
 const mapnik::json::feature_grammar<base_iterator_type, mapnik::feature_impl> geojson_datasource_static_feature_grammar(geojson_datasource_static_tr);
-const mapnik::json::extract_bounding_box_grammar<base_iterator_type> geojson_datasource_static_bbox_grammar;
+const mapnik::json::extract_bounding_box_grammar<base_iterator_type, boxes_type> geojson_datasource_static_bbox_grammar;
 }
 
 void geojson_datasource::initialise_descriptor(mapnik::feature_ptr const& feature)
@@ -230,7 +232,7 @@ void geojson_datasource::initialise_disk_index(std::string const& filename)
                                 std::ifstream>::query_first_n(filter, index, positions, num_features_to_query_);
 
     mapnik::util::file file(filename_);
-    if (!file.open()) throw mapnik::datasource_exception("GeoJSON Plugin: could not open: '" + filename_ + "'");
+    if (!file) throw mapnik::datasource_exception("GeoJSON Plugin: could not open: '" + filename_ + "'");
 
     for (auto const& pos : positions)
     {
@@ -257,7 +259,7 @@ void geojson_datasource::initialise_disk_index(std::string const& filename)
 template <typename Iterator>
 void geojson_datasource::initialise_index(Iterator start, Iterator end)
 {
-    mapnik::json::boxes_type boxes;
+    boxes_type boxes;
     boost::spirit::standard::space_type space;
     Iterator itr = start;
     if (!boost::spirit::qi::phrase_parse(itr, end, (geojson_datasource_static_bbox_grammar)(boost::phoenix::ref(boxes)) , space))
@@ -454,7 +456,7 @@ boost::optional<mapnik::datasource_geometry_t> geojson_datasource::get_geometry_
 
         mapnik::util::file file(filename_);
 
-        if (!file.open()) throw mapnik::datasource_exception("GeoJSON Plugin: could not open: '" + filename_ + "'");
+        if (!file) throw mapnik::datasource_exception("GeoJSON Plugin: could not open: '" + filename_ + "'");
 
         for (auto const& pos : positions)
         {
@@ -508,7 +510,7 @@ boost::optional<mapnik::datasource_geometry_t> geojson_datasource::get_geometry_
     else
     {
         mapnik::util::file file(filename_);
-        if (!file.open())
+        if (!file)
         {
             throw mapnik::datasource_exception("GeoJSON Plugin: could not open: '" + filename_ + "'");
         }
diff --git a/plugins/input/geojson/geojson_index_featureset.cpp b/plugins/input/geojson/geojson_index_featureset.cpp
index bdf7f8a..4cd1398 100644
--- a/plugins/input/geojson/geojson_index_featureset.cpp
+++ b/plugins/input/geojson/geojson_index_featureset.cpp
@@ -24,7 +24,6 @@
 #include "geojson_index_featureset.hpp"
 #include <mapnik/feature.hpp>
 #include <mapnik/feature_factory.hpp>
-#include <mapnik/json/geometry_grammar.hpp>
 #include <mapnik/json/feature_grammar.hpp>
 #include <mapnik/util/utf_conv_win.hpp>
 #include <mapnik/util/spatial_index.hpp>
diff --git a/plugins/input/geojson/geojson_memory_index_featureset.cpp b/plugins/input/geojson/geojson_memory_index_featureset.cpp
index 61c5053..32b8513 100644
--- a/plugins/input/geojson/geojson_memory_index_featureset.cpp
+++ b/plugins/input/geojson/geojson_memory_index_featureset.cpp
@@ -23,7 +23,6 @@
 // mapnik
 #include <mapnik/feature.hpp>
 #include <mapnik/feature_factory.hpp>
-#include <mapnik/json/geometry_grammar.hpp>
 #include <mapnik/json/feature_grammar.hpp>
 #include <mapnik/util/utf_conv_win.hpp>
 #include <mapnik/geometry_is_empty.hpp>
diff --git a/plugins/input/pgraster/pgraster_wkb_reader.cpp b/plugins/input/pgraster/pgraster_wkb_reader.cpp
index 87f71c0..b97d0cd 100644
--- a/plugins/input/pgraster/pgraster_wkb_reader.cpp
+++ b/plugins/input/pgraster/pgraster_wkb_reader.cpp
@@ -183,17 +183,16 @@ mapnik::raster_ptr read_data_band(mapnik::box2d<double> const& bbox,
 {
   mapnik::image_gray32f image(width, height);
   float* data = image.data();
-  double val;
-  val = reader(); // nodata value, need to read anyway
+  double nodataval = reader();
   for (int y=0; y<height; ++y) {
     for (int x=0; x<width; ++x) {
-      val = reader();
+      double val = reader();
       int off = y * width + x;
       data[off] = val;
     }
   }
   mapnik::raster_ptr raster = std::make_shared<mapnik::raster>(bbox, image, 1.0);
-  if ( hasnodata ) raster->set_nodata(val);
+  if ( hasnodata ) raster->set_nodata(nodataval);
   return raster;
 }
 
@@ -270,15 +269,13 @@ mapnik::raster_ptr read_grayscale_band(mapnik::box2d<double> const& bbox,
   image.set(0xffffffff);
 
 
-  int val;
-  int nodataval;
   uint8_t * data = image.bytes();
   int ps = 4; // sizeof(image::pixel_type)
   int off;
-  nodataval = reader(); // nodata value, need to read anyway
+  int nodataval = reader();
   for (int y=0; y<height; ++y) {
     for (int x=0; x<width; ++x) {
-      val = reader();
+      int val = reader();
       // Apply harsh type clipping rules ala GDAL
       if ( val < 0 ) val = 0;
       if ( val > 255 ) val = 255;
@@ -298,7 +295,7 @@ mapnik::raster_ptr read_grayscale_band(mapnik::box2d<double> const& bbox,
     }
   }
   mapnik::raster_ptr raster = std::make_shared<mapnik::raster>(bbox, image, 1.0);
-  if ( hasnodata ) raster->set_nodata(val);
+  if ( hasnodata ) raster->set_nodata(nodataval);
   return raster;
 }
 
diff --git a/plugins/input/postgis/postgis_datasource.cpp b/plugins/input/postgis/postgis_datasource.cpp
index d95aa33..909cd58 100644
--- a/plugins/input/postgis/postgis_datasource.cpp
+++ b/plugins/input/postgis/postgis_datasource.cpp
@@ -88,6 +88,17 @@ postgis_datasource::postgis_datasource(parameters const& params)
       extent_from_subquery_(*params.get<mapnik::boolean_type>("extent_from_subquery", false)),
       max_async_connections_(*params_.get<mapnik::value_integer>("max_async_connection", 1)),
       asynchronous_request_(false),
+      twkb_encoding_(false),
+      twkb_rounding_adjustment_(*params_.get<mapnik::value_double>("twkb_rounding_adjustment", 0.0)),
+      simplify_snap_ratio_(*params_.get<mapnik::value_double>("simplify_snap_ratio", 1.0/40.0)),
+      // 1/20 of pixel seems to be a good compromise to avoid
+      // drop of collapsed polygons.
+      // See https://github.com/mapnik/mapnik/issues/1639
+      // See http://trac.osgeo.org/postgis/ticket/2093
+      simplify_dp_ratio_(*params_.get<mapnik::value_double>("simplify_dp_ratio", 1.0/20.0)),
+      simplify_prefilter_(*params_.get<mapnik::value_double>("simplify_prefilter", 0.0)),
+      simplify_dp_preserve_(false),
+      simplify_clip_resolution_(*params_.get<mapnik::value_double>("simplify_clip_resolution", 0.0)),
       // TODO - use for known tokens too: "(@\\w+|!\\w+!)"
       pattern_(boost::regex("(@\\w+)",boost::regex::normal | boost::regbase::icase)),
       // params below are for testing purposes only and may be removed at any time
@@ -130,6 +141,12 @@ postgis_datasource::postgis_datasource(parameters const& params)
     boost::optional<mapnik::boolean_type> simplify_opt = params.get<mapnik::boolean_type>("simplify_geometries", false);
     simplify_geometries_ = simplify_opt && *simplify_opt;
 
+    boost::optional<mapnik::boolean_type> twkb_opt = params.get<mapnik::boolean_type>("twkb_encoding", false);
+    twkb_encoding_ = twkb_opt && *twkb_opt;
+
+    boost::optional<mapnik::boolean_type> simplify_preserve_opt = params.get<mapnik::boolean_type>("simplify_dp_preserve", false);
+    simplify_dp_preserve_ = simplify_preserve_opt && *simplify_preserve_opt;
+
     ConnectionManager::instance().registerPool(creator_, *initial_size, pool_max_size_);
     CnxPool_ptr pool = ConnectionManager::instance().getPool(creator_.id());
     if (pool)
@@ -794,25 +811,91 @@ featureset_ptr postgis_datasource::features_with_context(query const& q,processo
 
         const double px_gw = 1.0 / std::get<0>(q.resolution());
         const double px_gh = 1.0 / std::get<1>(q.resolution());
+        const double px_sz = std::min(px_gw, px_gh);
 
-        s << "SELECT ST_AsBinary(";
+        if (twkb_encoding_)
+        {
+            // This will only work against PostGIS 2.2, or a back-patched version
+            // that has (a) a ST_Simplify with a "preserve collapsed" flag and
+            // (b) a ST_RemoveRepeatedPoints with a tolerance parameter and
+            // (c) a ST_AsTWKB implementation
 
-        if (simplify_geometries_) {
-          s << "ST_Simplify(";
-        }
+            // What number of decimals of rounding does the pixel size imply?
+            const int twkb_rounding = -1 * std::lround(log10(px_sz) + twkb_rounding_adjustment_) + 1;
+            // And what's that in map units?
+            const double twkb_tolerance = pow(10.0, -1.0 * twkb_rounding);
 
-        s << "\"" << geometryColumn_ << "\"";
+            s << "SELECT ST_AsTWKB(";
+            s << "ST_Simplify(";
+            s << "ST_RemoveRepeatedPoints(";
 
-        if (simplify_geometries_) {
-          // 1/20 of pixel seems to be a good compromise to avoid
-          // drop of collapsed polygons.
-          // See https://github.com/mapnik/mapnik/issues/1639
-          const double tolerance = std::min(px_gw, px_gh) / 20.0;
-          s << ", " << tolerance << ")";
+            if (simplify_clip_resolution_ > 0.0 && simplify_clip_resolution_ > px_sz)
+            {
+                s << "ST_ClipByBox2D(";
+            }
+            s << "\"" << geometryColumn_ << "\"";
+
+            // ! ST_ClipByBox2D()
+            if (simplify_clip_resolution_ > 0.0 && simplify_clip_resolution_ > px_sz)
+            {
+                s << "," << sql_bbox(box) << ")";
+            }
+
+            // ! ST_RemoveRepeatedPoints()
+            s << "," << twkb_tolerance << ")";
+            // ! ST_Simplify(), with parameter to keep collapsed geometries
+            s << "," << twkb_tolerance << ",true)";
+            // ! ST_TWKB()
+            s << "," << twkb_rounding << ") AS geom";
         }
+        else
+        {
+            s << "SELECT ST_AsBinary(";
+            if (simplify_geometries_)
+            {
+                s << "ST_Simplify(";
+            }
+            if (simplify_clip_resolution_ > 0.0 && simplify_clip_resolution_ > px_sz)
+            {
+                s << "ST_ClipByBox2D(";
+            }
+            if (simplify_geometries_ && simplify_snap_ratio_ > 0.0)
+            {
+                s<< "ST_SnapToGrid(";
+            }
+
+            // Geometry column!
+            s << "\"" << geometryColumn_ << "\"";
 
-        s << ") AS geom";
+            // ! ST_SnapToGrid()
+            if (simplify_geometries_ && simplify_snap_ratio_ > 0.0)
+            {
+                const double tolerance = px_sz * simplify_snap_ratio_;
+                s << "," << tolerance << ")";
+            }
 
+            // ! ST_ClipByBox2D()
+            if (simplify_clip_resolution_ > 0.0 && simplify_clip_resolution_ > px_sz)
+            {
+                s << "," << sql_bbox(box) << ")";
+            }
+
+            // ! ST_Simplify()
+            if (simplify_geometries_)
+            {
+                const double tolerance = px_sz * simplify_dp_ratio_;
+                s << ", " << tolerance;
+                // Add parameter to ST_Simplify to keep collapsed geometries
+                if (simplify_dp_preserve_)
+                {
+                    s << ", true";
+                }
+                s << ")";
+            }
+
+            // ! ST_AsBinary()
+            s << ") AS geom";
+        }
         mapnik::context_ptr ctx = std::make_shared<mapnik::context_type>();
         std::set<std::string> const& props = q.property_names();
         std::set<std::string>::const_iterator pos = props.begin();
@@ -854,7 +937,8 @@ featureset_ptr postgis_datasource::features_with_context(query const& q,processo
         }
 
         std::shared_ptr<IResultSet> rs = get_resultset(conn, s.str(), pool, proc_ctx);
-        return std::make_shared<postgis_featureset>(rs, ctx, desc_.get_encoding(), !key_field_.empty(), key_field_as_attribute_);
+        return std::make_shared<postgis_featureset>(rs, ctx, desc_.get_encoding(), !key_field_.empty(),
+                                                    key_field_as_attribute_, twkb_encoding_);
 
     }
 
@@ -941,7 +1025,8 @@ featureset_ptr postgis_datasource::features_at_point(coord2d const& pt, double t
             }
 
             std::shared_ptr<IResultSet> rs = get_resultset(conn, s.str(), pool);
-            return std::make_shared<postgis_featureset>(rs, ctx, desc_.get_encoding(), !key_field_.empty(), key_field_as_attribute_);
+            return std::make_shared<postgis_featureset>(rs, ctx, desc_.get_encoding(), !key_field_.empty(),
+                                                        key_field_as_attribute_, twkb_encoding_);
         }
     }
 
diff --git a/plugins/input/postgis/postgis_datasource.hpp b/plugins/input/postgis/postgis_datasource.hpp
index 2f5d24f..80ba894 100644
--- a/plugins/input/postgis/postgis_datasource.hpp
+++ b/plugins/input/postgis/postgis_datasource.hpp
@@ -119,6 +119,13 @@ private:
     bool estimate_extent_;
     int max_async_connections_;
     bool asynchronous_request_;
+    bool twkb_encoding_;
+    mapnik::value_double twkb_rounding_adjustment_;
+    mapnik::value_double simplify_snap_ratio_;
+    mapnik::value_double simplify_dp_ratio_;
+    mapnik::value_double simplify_prefilter_;
+    bool simplify_dp_preserve_;
+    mapnik::value_double simplify_clip_resolution_;
     boost::regex pattern_;
     int intersect_min_scale_;
     int intersect_max_scale_;
diff --git a/plugins/input/postgis/postgis_featureset.cpp b/plugins/input/postgis/postgis_featureset.cpp
index 6d417be..25e2b6b 100644
--- a/plugins/input/postgis/postgis_featureset.cpp
+++ b/plugins/input/postgis/postgis_featureset.cpp
@@ -49,14 +49,16 @@ postgis_featureset::postgis_featureset(std::shared_ptr<IResultSet> const& rs,
                                        context_ptr const& ctx,
                                        std::string const& encoding,
                                        bool key_field,
-                                       bool key_field_as_attribute)
+                                       bool key_field_as_attribute,
+                                       bool twkb_encoding)
     : rs_(rs),
       ctx_(ctx),
       tr_(new transcoder(encoding)),
       totalGeomSize_(0),
       feature_id_(1),
       key_field_(key_field),
-      key_field_as_attribute_(key_field_as_attribute)
+      key_field_as_attribute_(key_field_as_attribute),
+      twkb_encoding_(twkb_encoding)
 {
 }
 
@@ -123,8 +125,14 @@ feature_ptr postgis_featureset::next()
         int size = rs_->getFieldLength(0);
         const char *data = rs_->getValue(0);
 
-        mapnik::geometry::geometry<double> geometry = geometry_utils::from_wkb(data, size);
-        feature->set_geometry(std::move(geometry));
+        if (twkb_encoding_ )
+        {
+            feature->set_geometry(geometry_utils::from_twkb(data, size));
+        }
+        else
+        {
+            feature->set_geometry(geometry_utils::from_wkb(data, size));
+        }
 
         totalGeomSize_ += size;
         unsigned num_attrs = ctx_->size() + 1;
diff --git a/plugins/input/postgis/postgis_featureset.hpp b/plugins/input/postgis/postgis_featureset.hpp
index 4984ec9..9ef8cb3 100644
--- a/plugins/input/postgis/postgis_featureset.hpp
+++ b/plugins/input/postgis/postgis_featureset.hpp
@@ -44,7 +44,8 @@ public:
                        context_ptr const& ctx,
                        std::string const& encoding,
                        bool key_field,
-                       bool key_field_as_attribute);
+                       bool key_field_as_attribute,
+                       bool twkb_encoding);
     feature_ptr next();
     ~postgis_featureset();
 
@@ -56,6 +57,7 @@ private:
     mapnik::value_integer feature_id_;
     bool key_field_;
     bool key_field_as_attribute_;
+    bool twkb_encoding_;
 };
 
 #endif // POSTGIS_FEATURESET_HPP
diff --git a/plugins/input/topojson/topojson_datasource.cpp b/plugins/input/topojson/topojson_datasource.cpp
index f9ba8ec..4c4e6b5 100644
--- a/plugins/input/topojson/topojson_datasource.cpp
+++ b/plugins/input/topojson/topojson_datasource.cpp
@@ -166,7 +166,7 @@ topojson_datasource::topojson_datasource(parameters const& params)
     else
     {
         mapnik::util::file file(filename_);
-        if (!file.open())
+        if (!file)
         {
             throw mapnik::datasource_exception("TopoJSON Plugin: could not open: '" + filename_ + "'");
         }
diff --git a/plugins/input/topojson/topojson_featureset.cpp b/plugins/input/topojson/topojson_featureset.cpp
index 9e7c23e..36dbdf9 100644
--- a/plugins/input/topojson/topojson_featureset.cpp
+++ b/plugins/input/topojson/topojson_featureset.cpp
@@ -21,13 +21,8 @@
  *****************************************************************************/
 
 // mapnik
-#include <mapnik/feature.hpp>
-#include <mapnik/feature_factory.hpp>
 #include <mapnik/json/topology.hpp>
-#include <mapnik/util/variant.hpp>
-#include <mapnik/geometry_adapters.hpp>
-#include <mapnik/geometry_correct.hpp>
-
+#include <mapnik/json/topojson_utils.hpp>
 // stl
 #include <string>
 #include <vector>
@@ -40,334 +35,6 @@
 
 #include "topojson_featureset.hpp"
 
-namespace mapnik { namespace topojson {
-
-struct attribute_value_visitor
-
-{
-public:
-    attribute_value_visitor(mapnik::transcoder const& tr)
-        : tr_(tr) {}
-
-    mapnik::value operator()(std::string const& val) const
-    {
-        return mapnik::value(tr_.transcode(val.c_str()));
-    }
-
-    template <typename T>
-    mapnik::value operator()(T const& val) const
-    {
-        return mapnik::value(val);
-    }
-
-    mapnik::transcoder const& tr_;
-};
-
-template <typename T>
-void assign_properties(mapnik::feature_impl & feature, T const& geom, mapnik::transcoder const& tr)
-{
-    if ( geom.props)
-    {
-        for (auto const& p : *geom.props)
-        {
-            feature.put_new(std::get<0>(p), mapnik::util::apply_visitor(attribute_value_visitor(tr),std::get<1>(p)));
-        }
-    }
-}
-
-template <typename Context>
-struct feature_generator
-{
-    feature_generator(Context & ctx,  mapnik::transcoder const& tr, topology const& topo, std::size_t feature_id)
-        : ctx_(ctx),
-          tr_(tr),
-          topo_(topo),
-          num_arcs_(topo.arcs.size()),
-          feature_id_(feature_id) {}
-
-    feature_ptr operator() (point const& pt) const
-    {
-        mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_,feature_id_));
-        double x = pt.coord.x;
-        double y = pt.coord.y;
-        if (topo_.tr)
-        {
-            x =  x * (*topo_.tr).scale_x + (*topo_.tr).translate_x;
-            y =  y * (*topo_.tr).scale_y + (*topo_.tr).translate_y;
-        }
-        mapnik::geometry::point<double> point(x, y);
-        feature->set_geometry(std::move(point));
-        assign_properties(*feature, pt, tr_);
-        return feature;
-    }
-
-    feature_ptr operator() (multi_point const& multi_pt) const
-    {
-        mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_,feature_id_));
-        mapnik::geometry::multi_point<double> multi_point;
-        multi_point.reserve(multi_pt.points.size());
-        for (auto const& pt : multi_pt.points)
-        {
-            double x = pt.x;
-            double y = pt.y;
-            if (topo_.tr)
-            {
-                x =  x * (*topo_.tr).scale_x + (*topo_.tr).translate_x;
-                y =  y * (*topo_.tr).scale_y + (*topo_.tr).translate_y;
-            }
-            multi_point.add_coord(x, y);
-        }
-        feature->set_geometry(std::move(multi_point));
-        assign_properties(*feature, multi_pt, tr_);
-        return feature;
-    }
-
-    feature_ptr operator() (linestring const& line) const
-    {
-        mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_,feature_id_));
-        if (num_arcs_ > 0)
-        {
-            index_type index = line.ring;
-            index_type arc_index = index < 0 ? std::abs(index) - 1 : index;
-            if (arc_index >= 0 && arc_index < static_cast<int>(num_arcs_))
-            {
-                auto const& arcs = topo_.arcs[arc_index];
-                double px = 0, py = 0;
-                mapnik::geometry::line_string<double> line_string;
-                line_string.reserve(arcs.coordinates.size());
-
-                for (auto pt : arcs.coordinates)
-                {
-                    double x = pt.x;
-                    double y = pt.y;
-                    if (topo_.tr)
-                    {
-                        x =  (px += x) * (*topo_.tr).scale_x + (*topo_.tr).translate_x;
-                        y =  (py += y) * (*topo_.tr).scale_y + (*topo_.tr).translate_y;
-                    }
-                    line_string.add_coord(x,y);
-                }
-                feature->set_geometry(std::move(line_string));
-                assign_properties(*feature, line, tr_);
-            }
-        }
-        return feature;
-    }
-
-    feature_ptr operator() (multi_linestring const& multi_line) const
-    {
-        mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_,feature_id_));
-        if (num_arcs_ > 0)
-        {
-            mapnik::geometry::multi_line_string<double> multi_line_string;
-            bool hit = false;
-            multi_line_string.reserve(multi_line.rings.size());
-            for (auto const& index : multi_line.rings)
-            {
-                index_type arc_index = index < 0 ? std::abs(index) - 1 : index;
-                if (arc_index >= 0 && arc_index < static_cast<int>(num_arcs_))
-                {
-                    hit = true;
-                    double px = 0, py = 0;
-                    mapnik::geometry::line_string<double> line_string;
-                    auto const& arcs = topo_.arcs[arc_index];
-                    line_string.reserve(arcs.coordinates.size());
-                    for (auto pt : arcs.coordinates)
-                    {
-                        double x = pt.x;
-                        double y = pt.y;
-                        if (topo_.tr)
-                        {
-                            x =  (px += x) * (*topo_.tr).scale_x + (*topo_.tr).translate_x;
-                            y =  (py += y) * (*topo_.tr).scale_y + (*topo_.tr).translate_y;
-                        }
-                        line_string.add_coord(x, y);
-                    }
-                    multi_line_string.push_back(std::move(line_string));
-                }
-            }
-            if (hit)
-            {
-                feature->set_geometry(std::move(multi_line_string));
-                assign_properties(*feature, multi_line, tr_);
-            }
-        }
-        return feature;
-    }
-
-    feature_ptr operator() (polygon const& poly) const
-    {
-        mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_,feature_id_));
-        if (num_arcs_ > 0)
-        {
-            std::vector<mapnik::topojson::coordinate> processed_coords;
-            mapnik::geometry::polygon<double> polygon;
-            if (poly.rings.size() > 1) polygon.interior_rings.reserve(poly.rings.size() - 1);
-            bool first = true;
-            bool hit = false;
-            for (auto const& ring : poly.rings)
-            {
-                mapnik::geometry::linear_ring<double> linear_ring;
-                for (auto const& index : ring)
-                {
-                    double px = 0, py = 0;
-                    bool reverse = index < 0;
-                    index_type arc_index = reverse ? std::abs(index) - 1 : index;
-                    if (arc_index >= 0 && arc_index < static_cast<int>(num_arcs_))
-                    {
-                        hit = true;
-                        auto const& arcs = topo_.arcs[arc_index];
-                        auto const& coords = arcs.coordinates;
-                        processed_coords.clear();
-                        processed_coords.reserve(coords.size());
-                        for (auto const& pt : coords )
-                        {
-                            double x = pt.x;
-                            double y = pt.y;
-
-                            if (topo_.tr)
-                            {
-                                transform const& tr = *topo_.tr;
-                                x =  (px += x) * tr.scale_x + tr.translate_x;
-                                y =  (py += y) * tr.scale_y + tr.translate_y;
-                            }
-                            processed_coords.emplace_back(coordinate{x,y});
-                        }
-
-                        if (reverse)
-                        {
-                            for (auto const& c : processed_coords | boost::adaptors::reversed)
-                            {
-                                linear_ring.emplace_back(c.x, c.y);
-                            }
-                        }
-                        else
-                        {
-                            for (auto const& c : processed_coords)
-                            {
-                                linear_ring.emplace_back(c.x, c.y);
-                            }
-                        }
-                    }
-                }
-                if (first)
-                {
-                    first = false;
-                    polygon.set_exterior_ring(std::move(linear_ring));
-                }
-                else
-                {
-                    polygon.add_hole(std::move(linear_ring));
-                }
-            }
-            if (hit)
-            {
-                mapnik::geometry::correct(polygon);
-                feature->set_geometry(std::move(polygon));
-                assign_properties(*feature, poly, tr_);
-            }
-        }
-        return feature;
-    }
-
-    feature_ptr operator() (multi_polygon const& multi_poly) const
-    {
-        mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_,feature_id_));
-        if (num_arcs_ > 0)
-        {
-            std::vector<mapnik::topojson::coordinate> processed_coords;
-            mapnik::geometry::multi_polygon<double> multi_polygon;
-            multi_polygon.reserve(multi_poly.polygons.size());
-            bool hit = false;
-            for (auto const& poly : multi_poly.polygons)
-            {
-                bool first = true;
-                mapnik::geometry::polygon<double> polygon;
-                if (poly.size() > 1) polygon.interior_rings.reserve(poly.size() - 1);
-
-                for (auto const& ring : poly)
-                {
-                    mapnik::geometry::linear_ring<double> linear_ring;
-                    for (auto const& index : ring)
-                    {
-                        double px = 0, py = 0;
-                        bool reverse = index < 0;
-                        index_type arc_index = reverse ? std::abs(index) - 1 : index;
-                        if (arc_index >= 0 && arc_index < static_cast<int>(num_arcs_))
-                        {
-                            hit = true;
-                            auto const& arcs = topo_.arcs[arc_index];
-                            auto const& coords = arcs.coordinates;
-                            processed_coords.clear();
-                            processed_coords.reserve(coords.size());
-                            for (auto const& pt : coords )
-                            {
-                                double x = pt.x;
-                                double y = pt.y;
-
-                                if (topo_.tr)
-                                {
-                                    x =  (px += x) * (*topo_.tr).scale_x + (*topo_.tr).translate_x;
-                                    y =  (py += y) * (*topo_.tr).scale_y + (*topo_.tr).translate_y;
-                                }
-                                processed_coords.emplace_back(coordinate{x,y});
-                            }
-
-                            using namespace boost::adaptors;
-
-                            if (reverse)
-                            {
-                                for (auto const& c : (processed_coords | reversed))
-                                {
-                                    linear_ring.add_coord(c.x, c.y);
-                                }
-                            }
-                            else
-                            {
-                                for (auto const& c : processed_coords)
-                                {
-                                    linear_ring.add_coord(c.x, c.y);
-                                }
-                            }
-                        }
-                    }
-                    if (first)
-                    {
-                        first = false;
-                        polygon.set_exterior_ring(std::move(linear_ring));
-                    }
-                    else
-                    {
-                        polygon.add_hole(std::move(linear_ring));
-                    }
-                }
-                multi_polygon.push_back(std::move(polygon));
-            }
-            if (hit)
-            {
-                mapnik::geometry::correct(multi_polygon);
-                feature->set_geometry(std::move(multi_polygon));
-                assign_properties(*feature, multi_poly, tr_);
-            }
-        }
-        return feature;
-    }
-
-    template<typename T>
-    feature_ptr operator() (T const& ) const
-    {
-        return feature_ptr();
-    }
-
-    Context & ctx_;
-    mapnik::transcoder const& tr_;
-    topology const& topo_;
-    std::size_t num_arcs_;
-    std::size_t feature_id_;
-};
-
-}}
-
 topojson_featureset::topojson_featureset(mapnik::topojson::topology const& topo,
                                          mapnik::transcoder const& tr,
                                          array_type && index_array)
diff --git a/scripts/build-appveyor.bat b/scripts/build-appveyor.bat
index 3c8b3d0..84088d4 100644
--- a/scripts/build-appveyor.bat
+++ b/scripts/build-appveyor.bat
@@ -22,14 +22,16 @@ ECHO msvs_toolset^: %msvs_toolset%
 SET BUILD_TYPE=%configuration%
 SET BUILDPLATFORM=%platform%
 SET TOOLS_VERSION=%msvs_toolset%.0
+SET ICU_VERSION=56.1
+ECHO ICU_VERSION^: %ICU_VERSION%
 IF DEFINED APPVEYOR (ECHO on AppVeyor) ELSE (ECHO NOT on AppVeyor)
 ECHO ========
 
 SET PATH=C:\Python27;%PATH%
 SET PATH=C:\Program Files\7-Zip;%PATH%
 
-::update submodule variant
-git submodule update --init deps/mapbox/variant
+::update submodules (variant + test data)
+git submodule update --init
 IF %ERRORLEVEL% NEQ 0 GOTO ERROR
 
 
diff --git a/scripts/travis-common.sh b/scripts/travis-common.sh
index cfdc57f..15b38dd 100644
--- a/scripts/travis-common.sh
+++ b/scripts/travis-common.sh
@@ -62,7 +62,7 @@ commit_message_contains () {
 }
 
 commit_message_parse () {
-    if commit_message_contains '[skip tests]'; then
+    if commit_message_contains '[skip tests]' || [[ $(uname -s) == 'Darwin' ]]; then
         config_override "CPP_TESTS = False"
     fi
     if commit_message_contains '[skip utils]'; then
@@ -81,19 +81,10 @@ config_override () {
 
 configure () {
     if enabled ${COVERAGE}; then
-        ./configure "$@" PGSQL2SQLITE=False SVG2PNG=False SVG_RENDERER=False \
-            CUSTOM_LDFLAGS='--coverage' CUSTOM_CXXFLAGS='--coverage' \
-            CUSTOM_CFLAGS='--coverage' DEBUG=True
-    elif enabled ${MASON_PUBLISH}; then
-        export MASON_NAME=mapnik
-        export MASON_VERSION=latest
-        export MASON_LIB_FILE=lib/libmapnik-wkt.a
-        source ./.mason/mason.sh
-        ./configure "$@" PREFIX=${MASON_PREFIX} \
-            PATH_REPLACE='' MAPNIK_BUNDLED_SHARE_DIRECTORY=True \
-            RUNTIME_LINK='static'
+        ./configure "$@" PREFIX=${PREFIX} PGSQL2SQLITE=False SVG2PNG=False SVG_RENDERER=False \
+            COVERAGE=True DEBUG=True WARNING_CXXFLAGS="-Wno-unknown-warning-option"
     else
-        ./configure "$@"
+        ./configure "$@" PREFIX=${PREFIX} WARNING_CXXFLAGS="-Wno-unknown-warning-option"
     fi
     # print final config values, sorted and indented
     sort -sk1,1 ./config.py | sed -e 's/^/	/'
@@ -101,9 +92,29 @@ configure () {
 
 coverage () {
     ./mason_packages/.link/bin/cpp-coveralls \
-        --build-root . --gcov-options '\-lp' --exclude mason_packages \
+        --gcov /usr/bin/llvm-cov-${LLVM_VERSION} \
+        --build-root . --gcov-options '\-lp' \
+        --exclude mason_packages \
         --exclude .sconf_temp --exclude benchmark --exclude deps \
         --exclude scons --exclude test --exclude demo --exclude docs \
-        --exclude fonts --exclude utils \
+        --exclude fonts \
         > /dev/null
 }
+
+trigger_downstream() {
+    body="{
+        \"request\": {
+          \"message\": \"Triggered build: Mapnik core commit ${TRAVIS_COMMIT}\",
+          \"branch\":\"master\"
+        }
+    }
+    "
+
+    curl -s -X POST \
+      -H "Content-Type: application/json" \
+      -H "Accept: application/json" \
+      -H "Travis-API-Version: 3" \
+      -H "Authorization: token ${TRAVIS_TRIGGER_TOKEN}" \
+      -d "$body" \
+      https://api.travis-ci.org/repo/mapnik%2Fpython-mapnik/requests
+}
diff --git a/src/agg/agg_renderer.cpp b/src/agg/agg_renderer.cpp
index 9fbcdca..f144cea 100644
--- a/src/agg/agg_renderer.cpp
+++ b/src/agg/agg_renderer.cpp
@@ -43,7 +43,9 @@
 #include <mapnik/image_filter.hpp>
 #include <mapnik/image_util.hpp>
 #include <mapnik/image_any.hpp>
-// agg
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_rendering_buffer.h"
 #include "agg_pixfmt_rgba.h"
 #include "agg_color_rgba.h"
@@ -53,9 +55,12 @@
 #include "agg_span_allocator.h"
 #include "agg_image_accessors.h"
 #include "agg_span_image_filter_rgba.h"
+#pragma GCC diagnostic pop
 
-// boost
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/optional.hpp>
+#pragma GCC diagnostic pop
 
 // stl
 #include <cmath>
diff --git a/src/agg/process_building_symbolizer.cpp b/src/agg/process_building_symbolizer.cpp
index aabba77..d27b68b 100644
--- a/src/agg/process_building_symbolizer.cpp
+++ b/src/agg/process_building_symbolizer.cpp
@@ -33,10 +33,12 @@
 #include <mapnik/expression.hpp>
 #include <mapnik/renderer_common/process_building_symbolizer.hpp>
 #include <mapnik/transform_path_adapter.hpp>
+
 // stl
 #include <deque>
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_basics.h"
 #include "agg_rendering_buffer.h"
 #include "agg_color_rgba.h"
@@ -45,6 +47,7 @@
 #include "agg_scanline_u.h"
 #include "agg_renderer_scanline.h"
 #include "agg_conv_stroke.h"
+#pragma GCC diagnostic pop
 
 namespace mapnik
 {
diff --git a/src/agg/process_debug_symbolizer.cpp b/src/agg/process_debug_symbolizer.cpp
index 2016c45..3c3f898 100644
--- a/src/agg/process_debug_symbolizer.cpp
+++ b/src/agg/process_debug_symbolizer.cpp
@@ -33,7 +33,8 @@
 #include <mapnik/agg_helpers.hpp>
 #include <mapnik/util/is_clockwise.hpp>
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_basics.h"
 #include "agg_rendering_buffer.h"
 #include "agg_color_rgba.h"
@@ -41,6 +42,7 @@
 #include "agg_scanline_u.h"
 #include "agg_renderer_scanline.h"
 #include "agg_conv_stroke.h"
+#pragma GCC diagnostic pop
 
 namespace mapnik {
 
diff --git a/src/agg/process_dot_symbolizer.cpp b/src/agg/process_dot_symbolizer.cpp
index cc37586..cfb58c6 100644
--- a/src/agg/process_dot_symbolizer.cpp
+++ b/src/agg/process_dot_symbolizer.cpp
@@ -33,7 +33,8 @@
 #include <mapnik/proj_transform.hpp>
 #include <mapnik/image_compositing.hpp>
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_ellipse.h"
 #include "agg_rendering_buffer.h"
 #include "agg_pixfmt_rgba.h"
@@ -41,6 +42,7 @@
 #include "agg_renderer_scanline.h"
 #include "agg_color_rgba.h"
 #include "agg_renderer_base.h"
+#pragma GCC diagnostic pop
 
 namespace mapnik { namespace detail {
 
diff --git a/src/agg/process_group_symbolizer.cpp b/src/agg/process_group_symbolizer.cpp
index 010d3f1..6ba5605 100644
--- a/src/agg/process_group_symbolizer.cpp
+++ b/src/agg/process_group_symbolizer.cpp
@@ -35,8 +35,10 @@
 #include <mapnik/svg/svg_path_adapter.hpp>
 #include <mapnik/svg/svg_converter.hpp>
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_trans_affine.h"
+#pragma GCC diagnostic pop
 
 namespace mapnik {
 
diff --git a/src/agg/process_line_pattern_symbolizer.cpp b/src/agg/process_line_pattern_symbolizer.cpp
index f5045c5..3b947a4 100644
--- a/src/agg/process_line_pattern_symbolizer.cpp
+++ b/src/agg/process_line_pattern_symbolizer.cpp
@@ -37,7 +37,10 @@
 #include <mapnik/renderer_common/clipping_extent.hpp>
 #include <mapnik/renderer_common/render_pattern.hpp>
 #include <mapnik/renderer_common/apply_vertex_converter.hpp>
-// agg
+
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_basics.h"
 #include "agg_pixfmt_rgba.h"
 #include "agg_color_rgba.h"
@@ -50,6 +53,7 @@
 #include "agg_span_allocator.h"
 #include "agg_span_pattern_rgba.h"
 #include "agg_renderer_outline_image.h"
+#pragma GCC diagnostic pop
 
 namespace mapnik {
 
diff --git a/src/agg/process_line_symbolizer.cpp b/src/agg/process_line_symbolizer.cpp
index b3a01c7..9bace25 100644
--- a/src/agg/process_line_symbolizer.cpp
+++ b/src/agg/process_line_symbolizer.cpp
@@ -32,7 +32,9 @@
 #include <mapnik/renderer_common/clipping_extent.hpp>
 #include <mapnik/renderer_common/apply_vertex_converter.hpp>
 #include <mapnik/geometry_type.hpp>
-// agg
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_basics.h"
 #include "agg_rendering_buffer.h"
 #include "agg_pixfmt_rgba.h"
@@ -45,6 +47,7 @@
 #include "agg_conv_dash.h"
 #include "agg_renderer_outline_aa.h"
 #include "agg_rasterizer_outline_aa.h"
+#pragma GCC diagnostic pop
 
 // stl
 #include <string>
diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp
index b229f01..3fc122d 100644
--- a/src/agg/process_markers_symbolizer.cpp
+++ b/src/agg/process_markers_symbolizer.cpp
@@ -33,7 +33,8 @@
 #include <mapnik/renderer_common/clipping_extent.hpp>
 #include <mapnik/renderer_common/render_markers_symbolizer.hpp>
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_basics.h"
 #include "agg_renderer_base.h"
 #include "agg_renderer_scanline.h"
@@ -44,6 +45,7 @@
 #include "agg_scanline_u.h"
 #include "agg_path_storage.h"
 #include "agg_conv_transform.h"
+#pragma GCC diagnostic pop
 
 namespace mapnik {
 
diff --git a/src/agg/process_point_symbolizer.cpp b/src/agg/process_point_symbolizer.cpp
index 1da740f..bb54db5 100644
--- a/src/agg/process_point_symbolizer.cpp
+++ b/src/agg/process_point_symbolizer.cpp
@@ -34,8 +34,10 @@
 #include <mapnik/pixel_position.hpp>
 #include <mapnik/renderer_common/process_point_symbolizer.hpp>
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_trans_affine.h"
+#pragma GCC diagnostic pop
 
 // stl
 #include <string>
diff --git a/src/agg/process_polygon_pattern_symbolizer.cpp b/src/agg/process_polygon_pattern_symbolizer.cpp
index 8e340a9..e654886 100644
--- a/src/agg/process_polygon_pattern_symbolizer.cpp
+++ b/src/agg/process_polygon_pattern_symbolizer.cpp
@@ -39,7 +39,9 @@
 #include <mapnik/renderer_common/render_pattern.hpp>
 #include <mapnik/renderer_common/apply_vertex_converter.hpp>
 #include <mapnik/renderer_common/pattern_alignment.hpp>
-// agg
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_basics.h"
 #include "agg_rendering_buffer.h"
 #include "agg_pixfmt_rgba.h"
@@ -52,6 +54,7 @@
 #include "agg_span_pattern_rgba.h"
 #include "agg_image_accessors.h"
 #include "agg_conv_clip_polygon.h"
+#pragma GCC diagnostic pop
 
 namespace mapnik {
 
diff --git a/src/agg/process_polygon_symbolizer.cpp b/src/agg/process_polygon_symbolizer.cpp
index 9af6d4a..bd2d2bc 100644
--- a/src/agg/process_polygon_symbolizer.cpp
+++ b/src/agg/process_polygon_symbolizer.cpp
@@ -32,7 +32,9 @@
 #include <mapnik/vertex_converters.hpp>
 #include <mapnik/renderer_common/process_polygon_symbolizer.hpp>
 #include <mapnik/renderer_common/clipping_extent.hpp>
-// agg
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_basics.h"
 #include "agg_rendering_buffer.h"
 #include "agg_pixfmt_rgba.h"
@@ -40,6 +42,7 @@
 #include "agg_renderer_scanline.h"
 #include "agg_rasterizer_scanline_aa.h"
 #include "agg_scanline_u.h"
+#pragma GCC diagnostic pop
 
 namespace mapnik {
 
diff --git a/src/agg/process_raster_symbolizer.cpp b/src/agg/process_raster_symbolizer.cpp
index 0105e9b..746a5cc 100644
--- a/src/agg/process_raster_symbolizer.cpp
+++ b/src/agg/process_raster_symbolizer.cpp
@@ -38,9 +38,11 @@
 // stl
 #include <cmath>
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_rendering_buffer.h"
 #include "agg_pixfmt_rgba.h"
+#pragma GCC diagnostic pop
 
 namespace mapnik {
 
diff --git a/src/box2d.cpp b/src/box2d.cpp
index 26e6929..7d54233 100644
--- a/src/box2d.cpp
+++ b/src/box2d.cpp
@@ -299,33 +299,43 @@ void box2d<T>::re_center(coord<T,2> const& c)
 }
 
 template <typename T>
-void box2d<T>::init(T x0,T y0,T x1,T y1)
+void box2d<T>::init(T x0, T y0, T x1, T y1)
 {
-    if (x0<x1)
+    if (x0 < x1)
     {
-        minx_=x0;maxx_=x1;
+        minx_ = x0;
+        maxx_ = x1;
     }
     else
     {
-        minx_=x1;maxx_=x0;
+        minx_ = x1;
+        maxx_ = x0;
     }
-    if (y0<y1)
+    if (y0 < y1)
     {
-        miny_=y0;maxy_=y1;
+        miny_ = y0;
+        maxy_ = y1;
     }
     else
     {
-        miny_=y1;maxy_=y0;
+        miny_ = y1;
+        maxy_ = y0;
     }
 }
 
 template <typename T>
+void box2d<T>::init(T x, T y)
+{
+    init(x, y, x, y);
+}
+
+template <typename T>
 void box2d<T>::clip(box2d_type const& other)
 {
-    minx_ = std::max(minx_,other.minx());
-    miny_ = std::max(miny_,other.miny());
-    maxx_ = std::min(maxx_,other.maxx());
-    maxy_ = std::min(maxy_,other.maxy());
+    minx_ = std::max(minx_, other.minx());
+    miny_ = std::max(miny_, other.miny());
+    maxx_ = std::min(maxx_, other.maxx());
+    maxy_ = std::min(maxy_, other.maxy());
 }
 
 template <typename T>
@@ -337,7 +347,6 @@ void box2d<T>::pad(T padding)
     maxy_ += padding;
 }
 
-
 template <typename T>
 bool box2d<T>::from_string(std::string const& str)
 {
@@ -346,8 +355,7 @@ bool box2d<T>::from_string(std::string const& str)
     boost::spirit::ascii::space_type space;
     bool r = boost::spirit::qi::phrase_parse(str.begin(),
                                              str.end(),
-                                             double_ >> -lit(',') >> double_ >> -lit(',')
-                                             >> double_ >> -lit(',') >> double_,
+                                             double_ >> -lit(',') >> double_ >> -lit(',') >> double_ >> -lit(',') >> double_,
                                              space,
                                              *this);
     return r;
@@ -372,9 +380,16 @@ template <typename T>
 std::string box2d<T>::to_string() const
 {
     std::ostringstream s;
-    s << "box2d(" << std::fixed << std::setprecision(16)
-      << minx_ << ',' << miny_ << ','
-      << maxx_ << ',' << maxy_ << ')';
+    if (valid())
+    {
+        s << "box2d(" << std::fixed << std::setprecision(16)
+          << minx_ << ',' << miny_ << ','
+          << maxx_ << ',' << maxy_ << ')';
+    }
+    else
+    {
+        s << "box2d(INVALID)";
+    }
     return s.str();
 }
 
@@ -480,6 +495,7 @@ box2d<T>& box2d<T>::operator*=(agg::trans_affine const& tr)
 }
 
 template class box2d<int>;
+template class box2d<float>;
 template class box2d<double>;
 
 }
diff --git a/src/build.py b/src/build.py
index c405eb1..6dd0f24 100644
--- a/src/build.py
+++ b/src/build.py
@@ -62,6 +62,10 @@ system = 'boost_system%s' % env['BOOST_APPEND']
 lib_env['LIBS'] = [filesystem,
                    regex]
 
+if env['COVERAGE']:
+    lib_env.Append(LINKFLAGS='--coverage')
+    lib_env.Append(CXXFLAGS='--coverage')
+
 if env['HAS_CAIRO']:
     lib_env.Append(LIBS=env['CAIRO_ALL_LIBS'])
 
@@ -201,6 +205,7 @@ source = Split(
     rule.cpp
     save_map.cpp
     wkb.cpp
+    twkb.cpp
     projection.cpp
     proj_transform.cpp
     scale_denominator.cpp
@@ -221,6 +226,7 @@ source = Split(
     warp.cpp
     css_color_grammar.cpp
     vertex_cache.cpp
+    vertex_adapters.cpp
     text/font_library.cpp
     text/text_layout.cpp
     text/text_line.cpp
@@ -257,6 +263,7 @@ source = Split(
     renderer_common/render_pattern.cpp
     renderer_common/render_thunk_extractor.cpp
     math.cpp
+    value.cpp
     """
     )
 
diff --git a/src/cairo/process_polygon_pattern_symbolizer.cpp b/src/cairo/process_polygon_pattern_symbolizer.cpp
index aa7b0ca..c2b211f 100644
--- a/src/cairo/process_polygon_pattern_symbolizer.cpp
+++ b/src/cairo/process_polygon_pattern_symbolizer.cpp
@@ -124,8 +124,7 @@ void cairo_renderer<T>::process(polygon_pattern_symbolizer const& sym,
     agg::trans_affine tr;
     auto geom_transform = get_optional<transform_type>(sym, keys::geometry_transform);
     if (geom_transform) { evaluate_transform(tr, feature, common_.vars_, *geom_transform, common_.scale_factor_); }
-    using vertex_converter_type = vertex_converter<
-                                                   clip_poly_tag,
+    using vertex_converter_type = vertex_converter<clip_poly_tag,
                                                    transform_tag,
                                                    affine_transform_tag,
                                                    simplify_tag,
diff --git a/src/debug.cpp b/src/debug.cpp
index 169272f..d1ae15f 100644
--- a/src/debug.cpp
+++ b/src/debug.cpp
@@ -22,6 +22,7 @@
 
 // mapnik
 #include <mapnik/debug.hpp>
+#include <mapnik/stringify_macro.hpp>
 
 // stl
 #include <ctime>
@@ -74,14 +75,7 @@ logger::severity_type logger::severity_level_ {
 
 logger::severity_map logger::object_severity_level_ = logger::severity_map();
 
-
-// format
-
-#define __xstr__(s) __str__(s)
-#define __str__(s) #s
-std::string logger::format_ = __xstr__(MAPNIK_LOG_FORMAT);
-#undef __xstr__
-#undef __str__
+std::string logger::format_ = MAPNIK_STRINGIFY(MAPNIK_LOG_FORMAT);
 
 std::string logger::str()
 {
diff --git a/src/feature_kv_iterator.cpp b/src/feature_kv_iterator.cpp
index 8fdba82..4ae3842 100644
--- a/src/feature_kv_iterator.cpp
+++ b/src/feature_kv_iterator.cpp
@@ -22,7 +22,11 @@
 
 #include <mapnik/feature_kv_iterator.hpp>
 #include <mapnik/feature.hpp>
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/optional.hpp>
+#pragma GCC diagnostic pop
 
 namespace mapnik {
 
diff --git a/src/font_engine_freetype.cpp b/src/font_engine_freetype.cpp
index efe654b..a14e6b6 100644
--- a/src/font_engine_freetype.cpp
+++ b/src/font_engine_freetype.cpp
@@ -33,11 +33,6 @@
 #include <mapnik/warning_ignore.hpp>
 #include <boost/algorithm/string/predicate.hpp>
 #include <boost/optional.hpp>
-#pragma GCC diagnostic pop
-
-// stl
-#include <algorithm>
-#include <stdexcept>
 
 // freetype2
 extern "C"
@@ -47,6 +42,11 @@ extern "C"
 #include FT_STROKER_H
 #include FT_MODULE_H
 }
+#pragma GCC diagnostic pop
+
+// stl
+#include <algorithm>
+#include <stdexcept>
 
 
 namespace mapnik
@@ -75,7 +75,7 @@ unsigned long ft_read_cb(FT_Stream stream, unsigned long offset, unsigned char *
     if (count <= 0) return 0;
     FILE * file = static_cast<FILE *>(stream->descriptor.pointer);
     std::fseek (file , offset , SEEK_SET);
-    return std::fread ((char*)buffer, 1, count, file);
+    return std::fread(reinterpret_cast<unsigned char*>(buffer), 1, count, file);
 }
 
 bool freetype_engine::register_font(std::string const& file_name)
@@ -93,7 +93,7 @@ bool freetype_engine::register_font_impl(std::string const& file_name,
 {
     MAPNIK_LOG_DEBUG(font_engine_freetype) << "registering: " << file_name;
     mapnik::util::file file(file_name);
-    if (!file.open()) return false;
+    if (!file) return false;
 
     FT_Face face = 0;
     FT_Open_Args args;
@@ -258,7 +258,7 @@ bool freetype_engine::can_open(std::string const& face_name,
     }
     if (!found_font_file) return false;
     mapnik::util::file file(itr->second.second);
-    if (!file.open()) return false;
+    if (!file) return false;
     FT_Face face = 0;
     FT_Open_Args args;
     FT_StreamRec streamRec;
@@ -332,7 +332,7 @@ face_ptr freetype_engine::create_face(std::string const& family_name,
     if (found_font_file)
     {
         mapnik::util::file file(itr->second.second);
-        if (file.open())
+        if (file)
         {
 #ifdef MAPNIK_THREADSAFE
             std::lock_guard<std::mutex> lock(mutex_);
diff --git a/src/fs.cpp b/src/fs.cpp
index 9c87d97..6403453 100644
--- a/src/fs.cpp
+++ b/src/fs.cpp
@@ -24,9 +24,12 @@
 #include <mapnik/util/utf_conv_win.hpp>
 #include <mapnik/util/fs.hpp>
 
-// boost
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/filesystem/operations.hpp>  // for absolute, exists, etc
 #include <boost/filesystem/path.hpp>    // for path, operator/
+#pragma GCC diagnostic pop
 
 // stl
 #include <stdexcept>
diff --git a/src/grid/grid_renderer.cpp b/src/grid/grid_renderer.cpp
index 33d10ee..fd970f5 100644
--- a/src/grid/grid_renderer.cpp
+++ b/src/grid/grid_renderer.cpp
@@ -47,11 +47,15 @@
 #include <mapnik/svg/svg_path_adapter.hpp>
 #include <mapnik/pixel_position.hpp>
 
-// boost
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/math/special_functions/round.hpp>
+#pragma GCC diagnostic pop
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_trans_affine.h"
+#pragma GCC diagnostic pop
 
 namespace mapnik
 {
diff --git a/src/grid/process_building_symbolizer.cpp b/src/grid/process_building_symbolizer.cpp
index e6649da..13ee8d4 100644
--- a/src/grid/process_building_symbolizer.cpp
+++ b/src/grid/process_building_symbolizer.cpp
@@ -39,11 +39,13 @@
 // stl
 #include <deque>
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_rasterizer_scanline_aa.h"
 #include "agg_renderer_scanline.h"
 #include "agg_scanline_bin.h"
 #include "agg_conv_stroke.h"
+#pragma GCC diagnostic pop
 
 namespace mapnik
 {
diff --git a/src/grid/process_group_symbolizer.cpp b/src/grid/process_group_symbolizer.cpp
index a93ea9d..ba7f48e 100644
--- a/src/grid/process_group_symbolizer.cpp
+++ b/src/grid/process_group_symbolizer.cpp
@@ -37,8 +37,10 @@
 #include <mapnik/svg/svg_path_attributes.hpp>
 #include <mapnik/renderer_common/render_group_symbolizer.hpp>
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_trans_affine.h"
+#pragma GCC diagnostic pop
 
 namespace mapnik {
 
diff --git a/src/grid/process_line_pattern_symbolizer.cpp b/src/grid/process_line_pattern_symbolizer.cpp
index dc370f7..af54ac5 100644
--- a/src/grid/process_line_pattern_symbolizer.cpp
+++ b/src/grid/process_line_pattern_symbolizer.cpp
@@ -35,12 +35,15 @@
 #include <mapnik/vertex_processor.hpp>
 #include <mapnik/parse_path.hpp>
 #include <mapnik/renderer_common/apply_vertex_converter.hpp>
-// agg
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_rasterizer_scanline_aa.h"
 #include "agg_renderer_scanline.h"
 #include "agg_scanline_bin.h"
 #include "agg_conv_stroke.h"
 #include "agg_conv_dash.h"
+#pragma GCC diagnostic pop
 
 // stl
 #include <string>
diff --git a/src/grid/process_line_symbolizer.cpp b/src/grid/process_line_symbolizer.cpp
index c569f6b..b65dd85 100644
--- a/src/grid/process_line_symbolizer.cpp
+++ b/src/grid/process_line_symbolizer.cpp
@@ -32,12 +32,15 @@
 #include <mapnik/vertex_processor.hpp>
 #include <mapnik/renderer_common/apply_vertex_converter.hpp>
 #include <mapnik/geometry_type.hpp>
-// agg
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_rasterizer_scanline_aa.h"
 #include "agg_renderer_scanline.h"
 #include "agg_scanline_bin.h"
 #include "agg_conv_stroke.h"
 #include "agg_conv_dash.h"
+#pragma GCC diagnostic pop
 
 // stl
 #include <string>
diff --git a/src/grid/process_markers_symbolizer.cpp b/src/grid/process_markers_symbolizer.cpp
index 2fa71c8..3809232 100644
--- a/src/grid/process_markers_symbolizer.cpp
+++ b/src/grid/process_markers_symbolizer.cpp
@@ -55,10 +55,12 @@ porting notes -->
 #include <mapnik/svg/svg_path_attributes.hpp>
 #include <mapnik/renderer_common/render_markers_symbolizer.hpp>
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_basics.h"
 #include "agg_rendering_buffer.h"
 #include "agg_rasterizer_scanline_aa.h"
+#pragma GCC diagnostic pop
 
 namespace mapnik {
 
diff --git a/src/grid/process_point_symbolizer.cpp b/src/grid/process_point_symbolizer.cpp
index 130fc1f..6032800 100644
--- a/src/grid/process_point_symbolizer.cpp
+++ b/src/grid/process_point_symbolizer.cpp
@@ -36,8 +36,10 @@
 #include <mapnik/pixel_position.hpp>
 #include <mapnik/renderer_common/process_point_symbolizer.hpp>
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_trans_affine.h"
+#pragma GCC diagnostic pop
 
 // stl
 #include <string>
diff --git a/src/grid/process_polygon_pattern_symbolizer.cpp b/src/grid/process_polygon_pattern_symbolizer.cpp
index 06408a8..03e27c6 100644
--- a/src/grid/process_polygon_pattern_symbolizer.cpp
+++ b/src/grid/process_polygon_pattern_symbolizer.cpp
@@ -36,10 +36,12 @@
 #include <mapnik/parse_path.hpp>
 #include <mapnik/renderer_common/apply_vertex_converter.hpp>
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_rasterizer_scanline_aa.h"
 #include "agg_renderer_scanline.h"
 #include "agg_scanline_bin.h"
+#pragma GCC diagnostic pop
 
 // stl
 #include <string>
@@ -76,7 +78,12 @@ void grid_renderer<T>::process(polygon_pattern_symbolizer const& sym,
         evaluate_transform(tr, feature, common_.vars_, *transform, common_.scale_factor_);
     }
 
-    using vertex_converter_type = vertex_converter<clip_poly_tag,transform_tag,affine_transform_tag,smooth_tag>;
+    using vertex_converter_type = vertex_converter<clip_poly_tag,
+                                                   transform_tag,
+                                                   affine_transform_tag,
+                                                   simplify_tag,
+                                                   smooth_tag>;
+
     vertex_converter_type converter(common_.query_extent_,sym,common_.t_,prj_trans,tr,feature,common_.vars_,common_.scale_factor_);
 
     if (prj_trans.equal() && clip) converter.set<clip_poly_tag>();
diff --git a/src/grid/process_polygon_symbolizer.cpp b/src/grid/process_polygon_symbolizer.cpp
index 3e1f089..ab85262 100644
--- a/src/grid/process_polygon_symbolizer.cpp
+++ b/src/grid/process_polygon_symbolizer.cpp
@@ -34,10 +34,12 @@
 #include <mapnik/vertex_converters.hpp>
 #include <mapnik/renderer_common/process_polygon_symbolizer.hpp>
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_rasterizer_scanline_aa.h"
 #include "agg_renderer_scanline.h"
 #include "agg_scanline_bin.h"
+#pragma GCC diagnostic pop
 
 // stl
 #include <string>
diff --git a/src/grid/process_shield_symbolizer.cpp b/src/grid/process_shield_symbolizer.cpp
index 50bc820..0463bee 100644
--- a/src/grid/process_shield_symbolizer.cpp
+++ b/src/grid/process_shield_symbolizer.cpp
@@ -33,8 +33,11 @@
 #include <mapnik/text/renderer.hpp>
 #include <mapnik/text/glyph_positions.hpp>
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_trans_affine.h"
+#include "agg_gamma_functions.h"
+#pragma GCC diagnostic pop
 
 namespace mapnik {
 
diff --git a/src/image_compositing.cpp b/src/image_compositing.cpp
index 925f56e..a8f9bba 100644
--- a/src/image_compositing.cpp
+++ b/src/image_compositing.cpp
@@ -33,7 +33,8 @@
 #include <boost/bimap.hpp>
 #pragma GCC diagnostic pop
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_rendering_buffer.h"
 #include "agg_rasterizer_scanline_aa.h"
 #include "agg_scanline_u.h"
@@ -41,7 +42,7 @@
 #include "agg_pixfmt_rgba.h"
 #include "agg_pixfmt_gray.h"
 #include "agg_color_rgba.h"
-
+#pragma GCC diagnostic pop
 
 namespace mapnik
 {
diff --git a/src/image_scaling.cpp b/src/image_scaling.cpp
index f0cc450..413948c 100644
--- a/src/image_scaling.cpp
+++ b/src/image_scaling.cpp
@@ -25,14 +25,14 @@
 #include <mapnik/image_scaling.hpp>
 #include <mapnik/image_scaling_traits.hpp>
 
-// boost
 #pragma GCC diagnostic push
 #include <mapnik/warning_ignore.hpp>
 #include <boost/assign/list_of.hpp>
 #include <boost/bimap.hpp>
 #pragma GCC diagnostic pop
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_image_accessors.h"
 #include "agg_pixfmt_rgba.h"
 #include "agg_pixfmt_gray.h"
@@ -47,6 +47,7 @@
 #include "agg_span_interpolator_linear.h"
 #include "agg_trans_affine.h"
 #include "agg_image_filters.h"
+#pragma GCC diagnostic pop
 
 namespace mapnik
 {
diff --git a/src/image_util.cpp b/src/image_util.cpp
index 43c5991..1fec8b1 100644
--- a/src/image_util.cpp
+++ b/src/image_util.cpp
@@ -38,13 +38,14 @@
 #include <mapnik/safe_cast.hpp>
 #ifdef SSE_MATH
 #include <mapnik/sse.hpp>
-
 #endif
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_rendering_buffer.h"
 #include "agg_pixfmt_rgba.h"
 #include "agg_color_rgba.h"
+#pragma GCC diagnostic pop
 
 // stl
 #include <string>
diff --git a/include/mapnik/util/geometry_to_geojson.hpp b/src/json/mapnik_geometry_to_geojson.cpp
similarity index 86%
copy from include/mapnik/util/geometry_to_geojson.hpp
copy to src/json/mapnik_geometry_to_geojson.cpp
index 5cccb09..ab26180 100644
--- a/include/mapnik/util/geometry_to_geojson.hpp
+++ b/src/json/mapnik_geometry_to_geojson.cpp
@@ -20,16 +20,13 @@
  *
  *****************************************************************************/
 
-#ifndef MAPNIK_GEOMETRY_TO_GEOJSON_HPP
-#define MAPNIK_GEOMETRY_TO_GEOJSON_HPP
-
 // mapnik
-
+#include <mapnik/util/geometry_to_geojson.hpp>
 #include <mapnik/json/geometry_generator_grammar.hpp>
 
 namespace mapnik { namespace util {
 
-inline bool to_geojson(std::string & json, mapnik::geometry::geometry<double> const& geom)
+bool to_geojson(std::string & json, mapnik::geometry::geometry<double> const& geom)
 {
     using sink_type = std::back_insert_iterator<std::string>;
     static const mapnik::json::geometry_generator_grammar<sink_type, mapnik::geometry::geometry<double> > grammar;
@@ -38,5 +35,3 @@ inline bool to_geojson(std::string & json, mapnik::geometry::geometry<double> co
 }
 
 }}
-
-#endif // MAPNIK_GEOMETRY_TO_GEOJSON_HPP
diff --git a/include/mapnik/json/geometry_parser.hpp b/src/json/mapnik_json_geometry_parser.cpp
similarity index 84%
copy from include/mapnik/json/geometry_parser.hpp
copy to src/json/mapnik_json_geometry_parser.cpp
index c83901d..278d2c4 100644
--- a/include/mapnik/json/geometry_parser.hpp
+++ b/src/json/mapnik_json_geometry_parser.cpp
@@ -2,7 +2,7 @@
  *
  * This file is part of Mapnik (c++ mapping toolkit)
  *
- * Copyright (C) 2015 Artem Pavlenko
+ * Copyright (C) 2016 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,12 +20,8 @@
  *
  *****************************************************************************/
 
-#ifndef MAPNIK_JSON_GEOMETRY_PARSER_HPP
-#define MAPNIK_JSON_GEOMETRY_PARSER_HPP
-
-// mapnik
-
 
+#include <mapnik/json/geometry_parser.hpp>
 #include <mapnik/json/geometry_grammar.hpp>
 
 // boost
@@ -34,7 +30,7 @@
 
 namespace mapnik { namespace json {
 
-inline bool from_geojson(std::string const& json, mapnik::geometry::geometry<double> & geom)
+bool from_geojson(std::string const& json, mapnik::geometry::geometry<double> & geom)
 {
     using namespace boost::spirit;
     static const geometry_grammar<char const*> g;
@@ -45,5 +41,3 @@ inline bool from_geojson(std::string const& json, mapnik::geometry::geometry<dou
 }
 
 }}
-
-#endif // MAPNIK_JSON_GEOMETRY_PARSER_HPP
diff --git a/include/mapnik/grid/grid_rendering_buffer.hpp b/src/json/mapnik_json_positions_grammar.cpp
similarity index 77%
copy from include/mapnik/grid/grid_rendering_buffer.hpp
copy to src/json/mapnik_json_positions_grammar.cpp
index 4282e3b..a13f0e3 100644
--- a/include/mapnik/grid/grid_rendering_buffer.hpp
+++ b/src/json/mapnik_json_positions_grammar.cpp
@@ -20,16 +20,8 @@
  *
  *****************************************************************************/
 
-#ifndef MAPNIK_GRID_RENDERING_BUFFER_HPP
-#define MAPNIK_GRID_RENDERING_BUFFER_HPP
+#include <mapnik/json/positions_grammar_impl.hpp>
+#include <string>
 
-#include <mapnik/grid/grid.hpp>
-#include "agg_rendering_buffer.h"
-
-namespace mapnik {
-
-using grid_rendering_buffer = agg::row_ptr_cache<mapnik::grid::value_type>;
-
-}
-
-#endif //MAPNIK_AGG_RASTERIZER_HPP
+using iterator_type = char const*;
+template struct mapnik::json::positions_grammar<iterator_type>;
diff --git a/src/load_map.cpp b/src/load_map.cpp
index 6e15ba2..f217082 100644
--- a/src/load_map.cpp
+++ b/src/load_map.cpp
@@ -59,18 +59,22 @@
 #include <mapnik/evaluate_global_attributes.hpp>
 #include <mapnik/boolean.hpp>
 
-// boost
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/optional.hpp>
 #include <boost/tokenizer.hpp>
 #include <boost/property_tree/ptree.hpp>
 #include <boost/property_tree/xml_parser.hpp>
 #include <boost/static_assert.hpp>
+#pragma GCC diagnostic pop
 
 // stl
 #include <algorithm>
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_trans_affine.h"
+#pragma GCC diagnostic pop
 
 using boost::tokenizer;
 
diff --git a/src/map.cpp b/src/map.cpp
index c44735c..3aff557 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -307,7 +307,7 @@ bool Map::load_fonts()
             continue;
         }
         mapnik::util::file file(file_path);
-        if (file.open())
+        if (file)
         {
             auto item = font_memory_cache_.emplace(file_path, std::make_pair(file.data(),file.size()));
             if (item.second) result = true;
diff --git a/src/marker_cache.cpp b/src/marker_cache.cpp
index 9e40622..6fef861 100644
--- a/src/marker_cache.cpp
+++ b/src/marker_cache.cpp
@@ -39,9 +39,11 @@
 #include <boost/algorithm/string.hpp>
 #pragma GCC diagnostic pop
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_rendering_buffer.h"
 #include "agg_pixfmt_rgba.h"
+#pragma GCC diagnostic pop
 
 namespace mapnik
 {
diff --git a/src/marker_helpers.cpp b/src/marker_helpers.cpp
index cf37cdb..dc9f679 100644
--- a/src/marker_helpers.cpp
+++ b/src/marker_helpers.cpp
@@ -23,9 +23,13 @@
 // mapnik
 #include <mapnik/marker_helpers.hpp>
 #include <mapnik/svg/svg_converter.hpp>
+#include <mapnik/label_collision_detector.hpp>
 
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_ellipse.h"
 #include "agg_color_rgba.h"
+#pragma GCC diagnostic pop
 
 namespace mapnik {
 
@@ -158,5 +162,142 @@ void setup_transform_scaling(agg::trans_affine & tr,
     }
 }
 
+template <typename Processor>
+void apply_markers_single(vertex_converter_type & converter, Processor & proc,
+                          geometry::geometry<double> const& geom, geometry::geometry_types type)
+{
+    if (type == geometry::geometry_types::Point)
+    {
+        geometry::point_vertex_adapter<double> va(geom.get<geometry::point<double>>());
+        converter.apply(va, proc);
+    }
+    else if (type == geometry::geometry_types::LineString)
+    {
+        geometry::line_string_vertex_adapter<double> va(geom.get<geometry::line_string<double>>());
+        converter.apply(va, proc);
+    }
+    else if (type == geometry::geometry_types::Polygon)
+    {
+        geometry::polygon_vertex_adapter<double> va(geom.get<geometry::polygon<double>>());
+        converter.apply(va, proc);
+    }
+    else if (type == geometry::geometry_types::MultiPoint)
+    {
+        for (auto const& pt : geom.get<geometry::multi_point<double>>())
+        {
+            geometry::point_vertex_adapter<double> va(pt);
+            converter.apply(va, proc);
+        }
+    }
+    else if (type == geometry::geometry_types::MultiLineString)
+    {
+        for (auto const& line : geom.get<geometry::multi_line_string<double>>())
+        {
+            geometry::line_string_vertex_adapter<double> va(line);
+            converter.apply(va, proc);
+        }
+    }
+    else if (type == geometry::geometry_types::MultiPolygon)
+    {
+        for (auto const& poly : geom.get<geometry::multi_polygon<double>>())
+        {
+            geometry::polygon_vertex_adapter<double> va(poly);
+            converter.apply(va, proc);
+        }
+    }
+}
+
+template <typename Processor>
+void apply_markers_multi(feature_impl const& feature, attributes const& vars,
+                         vertex_converter_type & converter, Processor & proc, symbolizer_base const& sym)
+{
+    auto const& geom = feature.get_geometry();
+    geometry::geometry_types type = geometry::geometry_type(geom);
+
+    if (type == geometry::geometry_types::Point
+        ||
+        type == geometry::geometry_types::LineString
+        ||
+        type == geometry::geometry_types::Polygon)
+    {
+        apply_markers_single(converter, proc, geom, type);
+    }
+    else
+    {
+
+        marker_multi_policy_enum multi_policy = get<marker_multi_policy_enum, keys::markers_multipolicy>(sym, feature, vars);
+        marker_placement_enum placement = get<marker_placement_enum, keys::markers_placement_type>(sym, feature, vars);
+
+        if (placement == MARKER_POINT_PLACEMENT &&
+            multi_policy == MARKER_WHOLE_MULTI)
+        {
+            geometry::point<double> pt;
+            // test if centroid is contained by bounding box
+            if (geometry::centroid(geom, pt) && converter.disp_.args_.bbox.contains(pt.x, pt.y))
+            {
+                // unset any clipping since we're now dealing with a point
+                converter.template unset<clip_poly_tag>();
+                geometry::point_vertex_adapter<double> va(pt);
+                converter.apply(va, proc);
+            }
+        }
+        else if ((placement == MARKER_POINT_PLACEMENT || placement == MARKER_INTERIOR_PLACEMENT) &&
+                 multi_policy == MARKER_LARGEST_MULTI)
+        {
+            // Only apply to path with largest envelope area
+            // TODO: consider using true area for polygon types
+            if (type == geometry::geometry_types::MultiPolygon)
+            {
+                geometry::multi_polygon<double> const& multi_poly = mapnik::util::get<geometry::multi_polygon<double> >(geom);
+                double maxarea = 0;
+                geometry::polygon<double> const* largest = 0;
+                for (geometry::polygon<double> const& poly : multi_poly)
+                {
+                    box2d<double> bbox = geometry::envelope(poly);
+                    double area = bbox.width() * bbox.height();
+                    if (area > maxarea)
+                    {
+                        maxarea = area;
+                        largest = &poly;
+                    }
+                }
+                if (largest)
+                {
+                    geometry::polygon_vertex_adapter<double> va(*largest);
+                    converter.apply(va, proc);
+                }
+            }
+            else
+            {
+                MAPNIK_LOG_WARN(marker_symbolizer) << "TODO: if you get here -> open an issue";
+            }
+        }
+        else
+        {
+            if (multi_policy != MARKER_EACH_MULTI && placement != MARKER_POINT_PLACEMENT)
+            {
+                MAPNIK_LOG_WARN(marker_symbolizer) << "marker_multi_policy != 'each' has no effect with marker_placement != 'point'";
+            }
+            if (type == geometry::geometry_types::GeometryCollection)
+            {
+                for (auto const& g : geom.get<geometry::geometry_collection<double>>())
+                {
+                    apply_markers_single(converter, proc, g, geometry::geometry_type(g));
+                }
+            }
+            else
+            {
+                apply_markers_single(converter, proc, geom, type);
+            }
+        }
+    }
+}
+template void apply_markers_multi<vector_dispatch_type>(feature_impl const& feature, attributes const& vars,
+                                                        vertex_converter_type & converter, vector_dispatch_type & proc,
+                                                        symbolizer_base const& sym);
+
+template void apply_markers_multi<raster_dispatch_type>(feature_impl const& feature, attributes const& vars,
+                                                        vertex_converter_type & converter, raster_dispatch_type & proc,
+                                                        symbolizer_base const& sym);
 
 } // end namespace mapnik
diff --git a/src/palette.cpp b/src/palette.cpp
index 54e4346..4c3807d 100644
--- a/src/palette.cpp
+++ b/src/palette.cpp
@@ -37,8 +37,8 @@ rgb::rgb(rgba const& c)
 // ordering by mean(a,r,g,b), a, r, g, b
 bool rgba::mean_sort_cmp::operator() (const rgba& x, const rgba& y) const
 {
-    int t1 = (int)x.a + x.r + x.g + x.b;
-    int t2 = (int)y.a + y.r + y.g + y.b;
+    int t1 = x.a + x.r + x.g + x.b;
+    int t2 = y.a + y.r + y.g + y.b;
     if (t1 != t2) return t1 < t2;
 
     // https://github.com/mapnik/mapnik/issues/1087
@@ -97,9 +97,9 @@ std::string rgba_palette::to_string() const
     str << std::hex << std::setfill('0');
     for (unsigned i = 0; i < length; i++) {
         str << " #";
-        str << std::setw(2) << (unsigned)rgb_pal_[i].r;
-        str << std::setw(2) << (unsigned)rgb_pal_[i].g;
-        str << std::setw(2) << (unsigned)rgb_pal_[i].b;
+        str << std::setw(2) << static_cast<unsigned>(rgb_pal_[i].r);
+        str << std::setw(2) << static_cast<unsigned>(rgb_pal_[i].g);
+        str << std::setw(2) << static_cast<unsigned>(rgb_pal_[i].b);
         if (i < alphaLength) str << std::setw(2) << alpha_pal_[i];
     }
     str << "]";
diff --git a/src/plugin.cpp b/src/plugin.cpp
index 7b05728..af9bef3 100644
--- a/src/plugin.cpp
+++ b/src/plugin.cpp
@@ -93,7 +93,9 @@ PluginInfo::~PluginInfo()
         */
         if (module_->dl && name_ != "gdal" && name_ != "ogr")
         {
+#ifndef MAPNIK_NO_DLCLOSE
             dlclose(module_->dl),module_->dl=0;
+#endif
         }
 #endif
         delete module_;
diff --git a/src/rapidxml_loader.cpp b/src/rapidxml_loader.cpp
index c0a631f..94e8294 100644
--- a/src/rapidxml_loader.cpp
+++ b/src/rapidxml_loader.cpp
@@ -28,12 +28,16 @@
 #include <mapnik/config_error.hpp>
 #include <mapnik/util/fs.hpp>
 #include <mapnik/xml_loader.hpp>
-#include <boost/property_tree/detail/xml_parser_read_rapidxml.hpp>
 #include <mapnik/xml_node.hpp>
 #include <mapnik/util/trim.hpp>
 #include <mapnik/util/noncopyable.hpp>
 #include <mapnik/util/utf_conv_win.hpp>
 
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
+#include <boost/property_tree/detail/xml_parser_read_rapidxml.hpp>
+#pragma GCC diagnostic pop
+
 // stl
 #include <iostream>
 #include <fstream>
diff --git a/src/raster_colorizer.cpp b/src/raster_colorizer.cpp
index 22d3ee8..2c43df6 100644
--- a/src/raster_colorizer.cpp
+++ b/src/raster_colorizer.cpp
@@ -149,7 +149,7 @@ void raster_colorizer::colorize(image_rgba8 & out, T const& in,
 
 inline unsigned interpolate(unsigned start, unsigned end, float fraction)
 {
-    return static_cast<unsigned>(fraction * ((float)end - (float)start) + start);
+    return static_cast<unsigned>(fraction * (static_cast<float>(end) - static_cast<float>(start)) + static_cast<float>(start));
 }
 
 unsigned raster_colorizer::get_color(float value) const
diff --git a/src/renderer_common/render_markers_symbolizer.cpp b/src/renderer_common/render_markers_symbolizer.cpp
index 12da737..2ecc51b 100644
--- a/src/renderer_common/render_markers_symbolizer.cpp
+++ b/src/renderer_common/render_markers_symbolizer.cpp
@@ -20,9 +20,9 @@
  *
  *****************************************************************************/
 
+#include <mapnik/label_collision_detector.hpp>
 #include <mapnik/svg/svg_storage.hpp>
 #include <mapnik/svg/svg_path_adapter.hpp>
-#include <mapnik/vertex_converters.hpp>
 #include <mapnik/marker_cache.hpp>
 #include <mapnik/marker_helpers.hpp>
 #include <mapnik/geometry_type.hpp>
@@ -39,14 +39,6 @@ struct render_marker_symbolizer_visitor
     using vector_dispatch_type = vector_markers_dispatch<Detector>;
     using raster_dispatch_type = raster_markers_dispatch<Detector>;
 
-    using vertex_converter_type = vertex_converter<clip_line_tag,
-                                                   clip_poly_tag,
-                                                   transform_tag,
-                                                   affine_transform_tag,
-                                                   simplify_tag,
-                                                   smooth_tag,
-                                                   offset_transform_tag>;
-
     render_marker_symbolizer_visitor(std::string const& filename,
                                      markers_symbolizer const& sym,
                                      mapnik::feature_impl & feature,
@@ -62,134 +54,131 @@ struct render_marker_symbolizer_visitor
           clip_box_(clip_box),
           renderer_context_(renderer_context) {}
 
+    svg_attribute_type const& get_marker_attributes(svg_path_ptr const& stock_marker,
+                                                    svg_attribute_type & custom_attr) const
+    {
+        auto const& stock_attr = stock_marker->attributes();
+        if (push_explicit_style(stock_attr, custom_attr, sym_, feature_, common_.vars_))
+            return custom_attr;
+        else
+            return stock_attr;
+    }
+
+    template <typename Marker, typename Dispatch>
+    void render_marker(Marker const& mark, Dispatch & rasterizer_dispatch) const
+    {
+        auto const& vars = common_.vars_;
+
+        agg::trans_affine geom_tr;
+        if (auto geometry_transform = get_optional<transform_type>(sym_, keys::geometry_transform))
+        {
+            evaluate_transform(geom_tr, feature_, vars, *geometry_transform, common_.scale_factor_);
+        }
+
+        vertex_converter_type converter(clip_box_,
+                                        sym_,
+                                        common_.t_,
+                                        prj_trans_,
+                                        geom_tr,
+                                        feature_,
+                                        vars,
+                                        common_.scale_factor_);
+
+        bool clip = get<value_bool, keys::clip>(sym_, feature_, vars);
+        double offset = get<value_double, keys::offset>(sym_, feature_, vars);
+        double simplify_tolerance = get<value_double, keys::simplify_tolerance>(sym_, feature_, vars);
+        double smooth = get<value_double, keys::smooth>(sym_, feature_, vars);
+
+        if (clip)
+        {
+            geometry::geometry_types type = geometry::geometry_type(feature_.get_geometry());
+            switch (type)
+            {
+                case geometry::geometry_types::Polygon:
+                case geometry::geometry_types::MultiPolygon:
+                    converter.template set<clip_poly_tag>();
+                    break;
+                case geometry::geometry_types::LineString:
+                case geometry::geometry_types::MultiLineString:
+                    converter.template set<clip_line_tag>();
+                    break;
+                default:
+                    // silence warning: 4 enumeration values not handled in switch
+                    break;
+            }
+        }
+
+        converter.template set<transform_tag>(); //always transform
+        if (std::fabs(offset) > 0.0) converter.template set<offset_transform_tag>(); // parallel offset
+        converter.template set<affine_transform_tag>(); // optional affine transform
+        if (simplify_tolerance > 0.0) converter.template set<simplify_tag>(); // optional simplify converter
+        if (smooth > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
+
+        apply_markers_multi(feature_, vars, converter, rasterizer_dispatch, sym_);
+    }
+
     void operator() (marker_null const&) const {}
 
     void operator() (marker_svg const& mark) const
     {
         using namespace mapnik::svg;
-        bool clip = get<value_bool, keys::clip>(sym_, feature_, common_.vars_);
-        double offset = get<value_double, keys::offset>(sym_, feature_, common_.vars_);
-        double simplify_tolerance = get<value_double, keys::simplify_tolerance>(sym_, feature_, common_.vars_);
-        double smooth = get<value_double, keys::smooth>(sym_, feature_, common_.vars_);
 
         // https://github.com/mapnik/mapnik/issues/1316
         bool snap_to_pixels = !mapnik::marker_cache::instance().is_uri(filename_);
 
-        agg::trans_affine geom_tr;
-        auto transform = get_optional<transform_type>(sym_, keys::geometry_transform);
-        if (transform) evaluate_transform(geom_tr, feature_, common_.vars_, *transform, common_.scale_factor_);
         agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_);
 
         boost::optional<svg_path_ptr> const& stock_vector_marker = mark.get_data();
+        svg_path_ptr marker_ptr = *stock_vector_marker;
+        bool is_ellipse = false;
+
+        svg_attribute_type s_attributes;
+        auto const& r_attributes = get_marker_attributes(*stock_vector_marker, s_attributes);
 
         // special case for simple ellipse markers
         // to allow for full control over rx/ry dimensions
         if (filename_ == "shape://ellipse"
            && (has_key(sym_,keys::width) || has_key(sym_,keys::height)))
         {
-            svg_path_ptr marker_ellipse = std::make_shared<svg_storage_type>();
-            vertex_stl_adapter<svg_path_storage> stl_storage(marker_ellipse->source());
-            svg_path_adapter svg_path(stl_storage);
-            build_ellipse(sym_, feature_, common_.vars_, *marker_ellipse, svg_path);
-            svg_attribute_type s_attributes;
-            bool result = push_explicit_style( (*stock_vector_marker)->attributes(), s_attributes, sym_, feature_, common_.vars_);
-            auto image_transform = get_optional<transform_type>(sym_, keys::image_transform);
-            if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform);
-            vector_dispatch_type rasterizer_dispatch(marker_ellipse,
-                                                     svg_path,
-                                                     result ? s_attributes : (*stock_vector_marker)->attributes(),
-                                                     image_tr,
-                                                     sym_,
-                                                     *common_.detector_,
-                                                     common_.scale_factor_,
-                                                     feature_,
-                                                     common_.vars_,
-                                                     snap_to_pixels,
-                                                     renderer_context_);
-
-            vertex_converter_type converter(clip_box_,
-                                            sym_,
-                                            common_.t_,
-                                            prj_trans_,
-                                            geom_tr,
-                                            feature_,
-                                            common_.vars_,
-                                            common_.scale_factor_);
-            if (clip)
-            {
-                geometry::geometry_types type = geometry::geometry_type(feature_.get_geometry());
-                if (type == geometry::geometry_types::Polygon || type == geometry::geometry_types::MultiPolygon)
-                    converter.template set<clip_poly_tag>();
-                else if (type == geometry::geometry_types::LineString || type == geometry::geometry_types::MultiLineString)
-                    converter.template set<clip_line_tag>();
-            }
-
-            converter.template set<transform_tag>(); //always transform
-            if (std::fabs(offset) > 0.0) converter.template set<offset_transform_tag>(); // parallel offset
-            converter.template set<affine_transform_tag>(); // optional affine transform
-            if (simplify_tolerance > 0.0) converter.template set<simplify_tag>(); // optional simplify converter
-            if (smooth > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
-            apply_markers_multi(feature_, common_.vars_, converter, rasterizer_dispatch, sym_);
+            marker_ptr = std::make_shared<svg_storage_type>();
+            is_ellipse = true;
         }
         else
         {
             box2d<double> const& bbox = mark.bounding_box();
             setup_transform_scaling(image_tr, bbox.width(), bbox.height(), feature_, common_.vars_, sym_);
-            auto image_transform = get_optional<transform_type>(sym_, keys::image_transform);
-            if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform);
-            vertex_stl_adapter<svg_path_storage> stl_storage((*stock_vector_marker)->source());
-            svg_path_adapter svg_path(stl_storage);
-            svg_attribute_type s_attributes;
-            bool result = push_explicit_style( (*stock_vector_marker)->attributes(), s_attributes, sym_, feature_, common_.vars_);
-            vector_dispatch_type rasterizer_dispatch(*stock_vector_marker,
-                                                     svg_path,
-                                                     result ? s_attributes : (*stock_vector_marker)->attributes(),
-                                                     image_tr,
-                                                     sym_,
-                                                     *common_.detector_,
-                                                     common_.scale_factor_,
-                                                     feature_,
-                                                     common_.vars_,
-                                                     snap_to_pixels,
-                                                     renderer_context_);
-
-            vertex_converter_type converter(clip_box_,
-                                            sym_,
-                                            common_.t_,
-                                            prj_trans_,
-                                            geom_tr,
-                                            feature_,
-                                            common_.vars_,
-                                            common_.scale_factor_);
-            if (clip)
-            {
-                geometry::geometry_types type = geometry::geometry_type(feature_.get_geometry());
-                if (type == geometry::geometry_types::Polygon || type == geometry::geometry_types::MultiPolygon)
-                    converter.template set<clip_poly_tag>();
-                else if (type == geometry::geometry_types::LineString || type == geometry::geometry_types::MultiLineString)
-                    converter.template set<clip_line_tag>();
-            }
+        }
+
+        vertex_stl_adapter<svg_path_storage> stl_storage(marker_ptr->source());
+        svg_path_adapter svg_path(stl_storage);
 
-            converter.template set<transform_tag>(); //always transform
-            if (std::fabs(offset) > 0.0) converter.template set<offset_transform_tag>(); // parallel offset
-            converter.template set<affine_transform_tag>(); // optional affine transform
-            if (simplify_tolerance > 0.0) converter.template set<simplify_tag>(); // optional simplify converter
-            if (smooth > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
-            apply_markers_multi(feature_, common_.vars_, converter, rasterizer_dispatch,  sym_);
+        if (is_ellipse)
+        {
+            build_ellipse(sym_, feature_, common_.vars_, *marker_ptr, svg_path);
         }
+
+        if (auto image_transform = get_optional<transform_type>(sym_, keys::image_transform))
+        {
+            evaluate_transform(image_tr, feature_, common_.vars_, *image_transform);
+        }
+
+        vector_dispatch_type rasterizer_dispatch(marker_ptr,
+                                                 svg_path,
+                                                 r_attributes,
+                                                 image_tr,
+                                                 sym_,
+                                                 *common_.detector_,
+                                                 common_.scale_factor_,
+                                                 feature_,
+                                                 common_.vars_,
+                                                 snap_to_pixels,
+                                                 renderer_context_);
+
+        render_marker(mark, rasterizer_dispatch);
     }
 
     void operator() (marker_rgba8 const& mark) const
     {
-        using namespace mapnik::svg;
-        bool clip = get<value_bool, keys::clip>(sym_, feature_, common_.vars_);
-        double offset = get<value_double, keys::offset>(sym_, feature_, common_.vars_);
-        double simplify_tolerance = get<value_double, keys::simplify_tolerance>(sym_, feature_, common_.vars_);
-        double smooth = get<value_double, keys::smooth>(sym_, feature_, common_.vars_);
-
-        agg::trans_affine geom_tr;
-        auto transform = get_optional<transform_type>(sym_, keys::geometry_transform);
-        if (transform) evaluate_transform(geom_tr, feature_, common_.vars_, *transform, common_.scale_factor_);
         agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_);
 
         setup_transform_scaling(image_tr, mark.width(), mark.height(), feature_, common_.vars_, sym_);
@@ -210,30 +199,7 @@ struct render_marker_symbolizer_visitor
                                                  common_.vars_,
                                                  renderer_context_);
 
-
-        vertex_converter_type converter(clip_box_,
-                                        sym_,
-                                        common_.t_,
-                                        prj_trans_,
-                                        geom_tr,
-                                        feature_,
-                                        common_.vars_,
-                                        common_.scale_factor_);
-
-        if (clip)
-        {
-            geometry::geometry_types type = geometry::geometry_type(feature_.get_geometry());
-            if (type == geometry::geometry_types::Polygon || type == geometry::geometry_types::MultiPolygon)
-                converter.template set<clip_poly_tag>();
-            else if (type == geometry::geometry_types::LineString || type == geometry::geometry_types::MultiLineString)
-                converter.template set<clip_line_tag>();
-        }
-        converter.template set<transform_tag>(); //always transform
-        if (std::fabs(offset) > 0.0) converter.template set<offset_transform_tag>(); // parallel offset
-        converter.template set<affine_transform_tag>(); // optional affine transform
-        if (simplify_tolerance > 0.0) converter.template set<simplify_tag>(); // optional simplify converter
-        if (smooth > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
-        apply_markers_multi(feature_, common_.vars_, converter, rasterizer_dispatch, sym_);
+        render_marker(mark, rasterizer_dispatch);
     }
 
   private:
@@ -279,7 +245,7 @@ void render_markers_symbolizer(markers_symbolizer const& sym,
                                box2d<double> const& clip_box,
                                markers_renderer_context & renderer_context)
 {
-    using Detector = decltype(*common.detector_);
+    using Detector = label_collision_detector4;
     using RendererType = renderer_common;
     using ContextType = markers_renderer_context;
     using VisitorType = detail::render_marker_symbolizer_visitor<Detector,
diff --git a/src/renderer_common/render_pattern.cpp b/src/renderer_common/render_pattern.cpp
index 06477d4..5e6f958 100644
--- a/src/renderer_common/render_pattern.cpp
+++ b/src/renderer_common/render_pattern.cpp
@@ -28,12 +28,15 @@
 #include <mapnik/svg/svg_path_adapter.hpp>
 #include <mapnik/agg_rasterizer.hpp>
 
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_rendering_buffer.h"
 #include "agg_pixfmt_rgba.h"
 #include "agg_pixfmt_gray.h"
 #include "agg_color_rgba.h"
 #include "agg_color_gray.h"
 #include "agg_scanline_u.h"
+#pragma GCC diagnostic pop
 
 namespace mapnik {
 
diff --git a/src/svg/svg_parser.cpp b/src/svg/svg_parser.cpp
index 6613d5c..2483bae 100644
--- a/src/svg/svg_parser.cpp
+++ b/src/svg/svg_parser.cpp
@@ -30,10 +30,14 @@
 #include <mapnik/util/file_io.hpp>
 #include <mapnik/util/utf_conv_win.hpp>
 #include <mapnik/util/dasharray_parser.hpp>
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_ellipse.h"
 #include "agg_rounded_rect.h"
 #include "agg_span_gradient.h"
 #include "agg_color_rgba.h"
+#pragma GCC diagnostic pop
 
 #pragma GCC diagnostic push
 #include <mapnik/warning_ignore.hpp>
@@ -150,7 +154,7 @@ double parse_svg_value(T & error_messages, const char* str, bool & percent)
         ("pc", DPI/6.0)
         ("mm", DPI/25.4)
         ("cm", DPI/2.54)
-        ("in", (double)DPI)
+        ("in", static_cast<double>(DPI))
         ;
     const char* cur = str; // phrase_parse modifies the first iterator
     const char* end = str + std::strlen(str);
diff --git a/src/svg/svg_path_parser.cpp b/src/svg/svg_path_parser.cpp
index 986f99b..52f95ef 100644
--- a/src/svg/svg_path_parser.cpp
+++ b/src/svg/svg_path_parser.cpp
@@ -21,32 +21,29 @@
  *****************************************************************************/
 
 // mapnik
-#include <mapnik/svg/svg_path_attributes.hpp>
-#include <mapnik/svg/svg_path_parser.hpp>
-#include <mapnik/svg/svg_path_grammar.hpp>
-#include <mapnik/svg/svg_converter.hpp>
-
-// agg
-#include "agg_path_storage.h"
 
+#include <mapnik/svg/svg_path_parser.hpp>
+#include <mapnik/svg/svg_path_grammar_impl.hpp>
 // stl
-#include <string>
 #include <cstring>
+#include <string>
 
-namespace mapnik { namespace svg {
+namespace mapnik {
+namespace svg {
 
-    template <typename PathType>
-    bool parse_path(const char* wkt, PathType & p)
-    {
-        using namespace boost::spirit;
-        using iterator_type = const char*;
-        using skip_type = ascii::space_type;
-        svg_path_grammar<iterator_type,skip_type,PathType> g(p);
-        iterator_type first = wkt;
-        iterator_type last =  wkt + std::strlen(wkt);
-        bool status = qi::phrase_parse(first, last, g, skip_type());
-        return (status && (first == last));
-    }
-    template bool MAPNIK_DECL parse_path<svg_converter_type>(const char*, svg_converter_type&);
+template <typename PathType>
+bool parse_path(const char* wkt, PathType& p)
+{
+    using namespace boost::spirit;
+    using iterator_type = const char*;
+    using skip_type = ascii::space_type;
+    static const svg_path_grammar<iterator_type, PathType, skip_type> g;
+    iterator_type first = wkt;
+    iterator_type last = wkt + std::strlen(wkt);
+    bool status = qi::phrase_parse(first, last, (g)(boost::phoenix::ref(p)), skip_type());
+    return (status && (first == last));
+}
+template bool MAPNIK_DECL parse_path<svg_converter_type>(const char*, svg_converter_type&);
 
-}}
+} // namespace svg
+} // namespace mapnik
diff --git a/src/svg/svg_points_parser.cpp b/src/svg/svg_points_parser.cpp
index 99de4c9..3e292ba 100644
--- a/src/svg/svg_points_parser.cpp
+++ b/src/svg/svg_points_parser.cpp
@@ -22,26 +22,27 @@
 
 // mapnik
 #include <mapnik/svg/svg_path_parser.hpp>
-#include <mapnik/svg/svg_points_grammar.hpp>
-#include <mapnik/svg/svg_converter.hpp>
+#include <mapnik/svg/svg_points_grammar_impl.hpp>
 // stl
 #include <string>
 #include <cstring>
 
-namespace mapnik { namespace svg {
+namespace mapnik {
+namespace svg {
 
-    template <typename PathType>
-    bool parse_points(const char* wkt, PathType & p)
-    {
-        using namespace boost::spirit;
-        using iterator_type = const char* ;
-        using skip_type = ascii::space_type;
-        svg_points_grammar<iterator_type,skip_type,PathType> g(p);
-        iterator_type first = wkt;
-        iterator_type last =  wkt + std::strlen(wkt);
-        return qi::phrase_parse(first, last, g, skip_type());
-    }
+template <typename PathType>
+bool parse_points(const char* wkt, PathType& p)
+{
+    using namespace boost::spirit;
+    using iterator_type = const char*;
+    using skip_type = ascii::space_type;
+    static const svg_points_grammar<iterator_type, PathType, skip_type> g;
+    iterator_type first = wkt;
+    iterator_type last = wkt + std::strlen(wkt);
+    return qi::phrase_parse(first, last, (g)(boost::phoenix::ref(p)), skip_type());
+}
 
-    template bool parse_points<svg_converter_type>(const char*, svg_converter_type&);
+template bool parse_points<svg_converter_type>(const char*, svg_converter_type&);
 
-    }}
+} // namespace svg
+} // namespace mapnik
diff --git a/src/svg/svg_transform_parser.cpp b/src/svg/svg_transform_parser.cpp
index f41b7b1..7b90ca4 100644
--- a/src/svg/svg_transform_parser.cpp
+++ b/src/svg/svg_transform_parser.cpp
@@ -21,27 +21,28 @@
  *****************************************************************************/
 
 // mapnik
-#include <mapnik/svg/svg_path_parser.hpp>
-#include <mapnik/svg/svg_transform_grammar.hpp>
+#include <mapnik/config.hpp>
+#include <mapnik/svg/svg_transform_grammar_impl.hpp>
 // stl
 #include <string>
 #include <cstring>
 
-namespace mapnik { namespace svg {
+namespace mapnik {
+namespace svg {
 
-    template <typename TransformType>
-    bool parse_svg_transform(const char * wkt, TransformType & p)
-    {
-        using namespace boost::spirit;
-        using iterator_type = const char *;
-        using skip_type = ascii::space_type;
-        // TODO - make it possible for this to be static const
-        // by avoiding ctor taking arg - https://github.com/mapnik/mapnik/pull/2231
-        svg_transform_grammar<iterator_type,skip_type,TransformType> g(p);
-        iterator_type first = wkt;
-        iterator_type last =  wkt + std::strlen(wkt);
-        return qi::phrase_parse(first, last, g, skip_type());
-    }
+template <typename TransformType>
+bool parse_svg_transform(const char* wkt, TransformType& tr)
+{
+    using namespace boost::spirit;
+    using iterator_type = const char*;
+    using skip_type = ascii::space_type;
+    static const svg_transform_grammar<iterator_type, TransformType, skip_type> g;
+    iterator_type first = wkt;
+    iterator_type last = wkt + std::strlen(wkt);
+    return qi::phrase_parse(first, last, (g)(boost::phoenix::ref(tr)), skip_type());
+}
 
-    template MAPNIK_DECL bool parse_svg_transform<agg::trans_affine>(const char*, agg::trans_affine&);
-}}
+template bool MAPNIK_DECL parse_svg_transform<agg::trans_affine>(const char*, agg::trans_affine&);
+
+} // namespace svg
+} // namespace mapnik
diff --git a/src/text/face.cpp b/src/text/face.cpp
index 79f35d8..1d3ad78 100644
--- a/src/text/face.cpp
+++ b/src/text/face.cpp
@@ -23,11 +23,16 @@
 #include <mapnik/text/face.hpp>
 #include <mapnik/debug.hpp>
 
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
+
 extern "C"
 {
 #include FT_GLYPH_H
 }
 
+#pragma GCC diagnostic pop
+
 namespace mapnik
 {
 
@@ -36,7 +41,7 @@ font_face::font_face(FT_Face face)
 
 bool font_face::set_character_sizes(double size)
 {
-    return (FT_Set_Char_Size(face_,0,(FT_F26Dot6)(size * (1<<6)),0,0) == 0);
+    return (FT_Set_Char_Size(face_,0,static_cast<FT_F26Dot6>(size * (1<<6)),0,0) == 0);
 }
 
 bool font_face::set_unscaled_character_sizes()
@@ -108,7 +113,7 @@ void font_face_set::set_unscaled_character_sizes()
 
 void stroker::init(double radius)
 {
-    FT_Stroker_Set(s_, (FT_Fixed) (radius * (1<<6)),
+    FT_Stroker_Set(s_, static_cast<FT_Fixed>(radius * (1<<6)),
                    FT_STROKER_LINECAP_ROUND,
                    FT_STROKER_LINEJOIN_ROUND,
                    0);
diff --git a/src/text/font_library.cpp b/src/text/font_library.cpp
index 2bdb4ba..37fd6a4 100644
--- a/src/text/font_library.cpp
+++ b/src/text/font_library.cpp
@@ -28,6 +28,9 @@
 #include <cstdlib>
 #include <stdexcept>
 
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
+
 // freetype2
 extern "C"
 {
@@ -36,6 +39,8 @@ extern "C"
 #include FT_MODULE_H
 }
 
+#pragma GCC diagnostic pop
+
 namespace {
 
 void* _Alloc_Func(FT_Memory, long size)
diff --git a/src/text/formatting/format.cpp b/src/text/formatting/format.cpp
index 8e0fef5..8a6a8cc 100644
--- a/src/text/formatting/format.cpp
+++ b/src/text/formatting/format.cpp
@@ -30,9 +30,11 @@
 #include <mapnik/ptree_helpers.hpp>
 #include <mapnik/xml_node.hpp>
 
-//boost
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/optional.hpp>
 #include <boost/property_tree/ptree.hpp>
+#pragma GCC diagnostic pop
 
 namespace mapnik { namespace formatting {
 
diff --git a/src/text/formatting/layout.cpp b/src/text/formatting/layout.cpp
index 19da033..ef908c5 100644
--- a/src/text/formatting/layout.cpp
+++ b/src/text/formatting/layout.cpp
@@ -35,8 +35,10 @@
 #include <mapnik/text/properties_util.hpp>
 #include <mapnik/boolean.hpp>
 
-// boost
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/property_tree/ptree.hpp>
+#pragma GCC diagnostic pop
 
 namespace mapnik { namespace formatting {
 
diff --git a/src/text/formatting/list.cpp b/src/text/formatting/list.cpp
index 89e9d23..4bf7c4d 100644
--- a/src/text/formatting/list.cpp
+++ b/src/text/formatting/list.cpp
@@ -25,8 +25,10 @@
 #include <mapnik/feature.hpp>
 #include <mapnik/symbolizer.hpp>
 
-// boost
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/property_tree/ptree.hpp>
+#pragma GCC diagnostic pop
 
 namespace mapnik {
 using boost::property_tree::ptree;
diff --git a/src/text/formatting/text.cpp b/src/text/formatting/text.cpp
index c24aab1..3158f20 100644
--- a/src/text/formatting/text.cpp
+++ b/src/text/formatting/text.cpp
@@ -30,8 +30,10 @@
 #include <mapnik/text/text_layout.hpp>
 #include <mapnik/debug.hpp>
 
-// boost
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/property_tree/ptree.hpp>
+#pragma GCC diagnostic pop
 
 namespace mapnik
 {
diff --git a/src/text/placements/list.cpp b/src/text/placements/list.cpp
index 65c729b..7d609f2 100644
--- a/src/text/placements/list.cpp
+++ b/src/text/placements/list.cpp
@@ -24,8 +24,10 @@
 #include <mapnik/text/placements/list.hpp>
 #include <mapnik/xml_node.hpp>
 
-//boost
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/property_tree/ptree.hpp>
+#pragma GCC diagnostic pop
 
 namespace mapnik
 {
diff --git a/src/text/scrptrun.cpp b/src/text/scrptrun.cpp
index 37a02e7..0cbb2c8 100644
--- a/src/text/scrptrun.cpp
+++ b/src/text/scrptrun.cpp
@@ -14,8 +14,11 @@
  * http://source.icu-project.org/repos/icu/icu/trunk/license.html
  */
 
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <unicode/utypes.h>
 #include <unicode/uscript.h>
+#pragma GCC diagnostic pop
 
 #include <mapnik/text/scrptrun.hpp>
 
diff --git a/src/text/text_layout.cpp b/src/text/text_layout.cpp
index ff37d28..3a3818c 100644
--- a/src/text/text_layout.cpp
+++ b/src/text/text_layout.cpp
@@ -29,8 +29,11 @@
 #include <mapnik/text/harfbuzz_shaper.hpp>
 #include <mapnik/make_unique.hpp>
 
-// ICU
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <unicode/brkiter.h>
+#pragma GCC diagnostic pop
+
 #include <algorithm>
 
 namespace mapnik
diff --git a/src/text/text_properties.cpp b/src/text/text_properties.cpp
index 4b08c10..ef5b9af 100644
--- a/src/text/text_properties.cpp
+++ b/src/text/text_properties.cpp
@@ -34,8 +34,10 @@
 #include <mapnik/boolean.hpp>
 #include <mapnik/make_unique.hpp>
 
-// boost
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/property_tree/ptree.hpp>
+#pragma GCC diagnostic pop
 
 namespace mapnik
 {
diff --git a/src/twkb.cpp b/src/twkb.cpp
new file mode 100644
index 0000000..f1928e5
--- /dev/null
+++ b/src/twkb.cpp
@@ -0,0 +1,387 @@
+/*****************************************************************************
+ *
+ * This file is part of Mapnik (c++ mapping toolkit)
+ *
+ * Copyright (C) 2016 Artem Pavlenko
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *****************************************************************************/
+
+
+// mapnik
+#include <mapnik/wkb.hpp>
+#include <mapnik/feature.hpp>
+#include <mapnik/geom_util.hpp>
+#include <mapnik/util/noncopyable.hpp>
+#include <mapnik/geometry_correct.hpp>
+#include <cmath>
+
+namespace mapnik { namespace detail {
+
+struct twkb_reader : mapnik::util::noncopyable
+{
+private:
+    const char *twkb_;
+    size_t size_;
+    unsigned int pos_;
+    // Metadata on the geometry we are parsing
+    uint8_t twkb_type_;
+    uint8_t has_bbox_;
+    uint8_t has_size_;
+    uint8_t has_idlist_;
+    uint8_t has_z_;
+    uint8_t has_m_;
+    uint8_t is_empty_;
+    // Precision factors to convert ints to double
+    double factor_xy_;
+    double factor_z_;
+    double factor_m_;
+    // An array to keep delta values from 4 dimensions
+    int64_t coord_x_;
+    int64_t coord_y_;
+    int64_t coord_z_;
+    int64_t coord_m_;
+
+public:
+    enum twkbGeometryType : std::uint8_t
+    {
+        twkbPoint = 1,
+        twkbLineString = 2,
+        twkbPolygon = 3,
+        twkbMultiPoint = 4,
+        twkbMultiLineString = 5,
+        twkbMultiPolygon = 6,
+        twkbGeometryCollection = 7
+    };
+
+    twkb_reader(char const* twkb, size_t size)
+        : twkb_(twkb), size_(size), pos_(0), twkb_type_(0), // Geometry type
+          has_bbox_(0),                                     // Bounding box?
+          has_size_(0),                                     // Size attribute?
+          has_idlist_(0),                                   // Presence of X/Y
+          has_z_(0),                                        // Presence of Z
+          has_m_(0),                                        // Presence of M
+          is_empty_(0),                                     // Empty?
+          factor_xy_(0.0), // Expansion factor for X/Y
+          factor_z_(0.0),  // Expansion factor for Z
+          factor_m_(0.0)   // Expansion factor for M
+    {}
+
+    mapnik::geometry::geometry<double> read()
+    {
+        mapnik::geometry::geometry<double> geom = mapnik::geometry::geometry_empty();
+        // Read the metadata bytes, populating all the
+        // information about optional fields, extended (z/m) dimensions
+        // expansion factors and so on
+        read_header();
+
+        // Each new read call has to reset the coordinate accumulators
+        coord_x_ = 0; // Accumulation register (x)
+        coord_y_ = 0; // Accumulation register (y)
+        coord_z_ = 0; // Accumulation register (z)
+        coord_m_ = 0; // Accumulation register (m)
+
+        // If the geometry is empty, add nothing to the paths array
+        if (is_empty_)
+            return geom;
+
+        // Read the [optional] size information
+        if (has_size_)
+            size_ = read_unsigned_integer();
+
+        // Read the [optional] bounding box information
+        if (has_bbox_) read_bbox();
+
+        switch (twkb_type_)
+        {
+        case twkbPoint:
+            geom = read_point();
+            break;
+        case twkbLineString:
+            geom = read_linestring();
+            break;
+        case twkbPolygon:
+            geom = read_polygon();
+            break;
+        case twkbMultiPoint:
+            geom = read_multipoint();
+            break;
+        case twkbMultiLineString:
+            geom = read_multilinestring();
+            break;
+        case twkbMultiPolygon:
+            geom = read_multipolygon();
+            break;
+        case twkbGeometryCollection:
+            geom = read_collection();
+        default:
+            break;
+        }
+        return geom;
+    }
+
+private:
+    int64_t unzigzag64(uint64_t val)
+    {
+        if (val & 0x01)
+            return -1 * (int64_t)((val + 1) >> 1);
+        else
+            return (int64_t)(val >> 1);
+    }
+
+    int32_t unzigzag32(uint32_t val)
+    {
+        if (val & 0x01) return -1 * (int32_t)((val + 1) >> 1);
+        else return (int32_t)(val >> 1);
+    }
+
+    int8_t unzigzag8(uint8_t val)
+    {
+        if (val & 0x01) return -1 * (int8_t)((val + 1) >> 1);
+        else return (int8_t)(val >> 1);
+    }
+
+    // Read from signed 64bit varint
+    int64_t read_signed_integer() { return unzigzag64(read_unsigned_integer()); }
+
+    // Read from unsigned 64bit varint
+    uint64_t read_unsigned_integer()
+    {
+        uint64_t nVal = 0;
+        int nShift = 0;
+        uint8_t nByte;
+
+        // Check so we don't read beyond the twkb
+        while (pos_ < size_)
+        {
+            nByte = twkb_[pos_];
+            // We get here when there is more to read in the input varInt
+            // Here we take the least significant 7 bits of the read
+            // byte and put it in the most significant place in the result variable.
+            nVal |= ((uint64_t)(nByte & 0x7f)) << nShift;
+            // move the "cursor" of the input buffer step (8 bits)
+            pos_++;
+            // move the cursor in the resulting variable (7 bits)
+            nShift += 7;
+            // Hibit isn't set, so this is the last byte
+            if (!(nByte & 0x80)) {
+                return nVal;
+            }
+        }
+        return 0;
+    }
+
+    // Every TWKB geometry starts with a metadata header
+    //
+    // type_and_dims     byte
+    // metadata_header   byte
+    // [extended_dims]   byte
+    // [size]            uvarint
+    // [bounds]          bbox
+    //
+    void read_header()
+    {
+        uint8_t type_precision = twkb_[pos_++];
+        uint8_t metadata = twkb_[pos_++];
+        twkb_type_ = type_precision & 0x0F;
+        int8_t precision = unzigzag8((type_precision & 0xF0) >> 4);
+        factor_xy_ = std::pow(10, static_cast<double>(precision));
+        has_bbox_ = metadata & 0x01;
+        has_size_ = (metadata & 0x02) >> 1;
+        has_idlist_ = (metadata & 0x04) >> 2;
+        uint8_t zm = (metadata & 0x08) >> 3;
+        is_empty_ = (metadata & 0x10) >> 4;
+
+        // Flag for higher dimensions means read a third byte
+        // of extended dimension information
+        if (zm)
+        {
+            zm = twkb_[pos_++];
+            // Strip Z/M presence and precision from ext byte
+            has_z_ = (zm & 0x01);
+            has_m_ = (zm & 0x02) >> 1;
+            // Convert the precision into factor
+            int8_t precision_z = (zm & 0x1C) >> 2;
+            int8_t precision_m = (zm & 0xE0) >> 5;
+            factor_z_ = pow(10, (double)precision_z);
+            factor_m_ = pow(10, (double)precision_m);
+        }
+    }
+
+    void read_bbox()
+    {
+        // we have nowhere to store this box information
+        // for now, so we'll just move the read head forward
+        // an appropriate number of times
+        if (has_bbox_)
+        {
+            read_signed_integer(); // uint64_t xmin
+            read_signed_integer(); // uint64_t xdelta
+            read_signed_integer(); // uint64_t ymin
+            read_signed_integer(); // uint64_t ydelta
+            if (has_z_)
+            {
+                read_signed_integer(); // uint64_t zmin
+                read_signed_integer(); // uint64_t zdelta
+            }
+            if (has_m_)
+            {
+                read_signed_integer(); // uint64_t mmin
+                read_signed_integer(); // uint64_t mdelta
+            }
+        }
+    }
+
+    void read_idlist(unsigned int num_ids)
+    {
+        // we have nowhere to store this id information
+        // for now, so we'll just move the read head
+        // forward an appropriate number of times
+        if (has_idlist_)
+        {
+            for (unsigned int i = 0; i < num_ids; ++i)
+            {
+                read_signed_integer(); // uint64_t id
+            }
+        }
+    }
+
+    template <typename Ring>
+    void read_coords(Ring & ring, std::size_t num_points)
+    {
+        for (std::size_t i = 0; i < num_points; ++i)
+        {
+            coord_x_ += read_signed_integer();
+            coord_y_ += read_signed_integer();
+            ring.emplace_back( coord_x_ / factor_xy_, coord_y_ / factor_xy_);
+            // Skip Z and M
+            if (has_z_) coord_z_ += read_signed_integer();
+            if (has_m_) coord_m_ += read_signed_integer();
+        }
+    }
+
+    mapnik::geometry::point<double> read_point()
+    {
+        coord_x_ += read_signed_integer();
+        coord_y_ += read_signed_integer();
+        double x = coord_x_ / factor_xy_;
+        double y = coord_y_ / factor_xy_;
+        return mapnik::geometry::point<double>(x, y);
+    }
+
+    mapnik::geometry::multi_point<double> read_multipoint()
+    {
+        mapnik::geometry::multi_point<double> multi_point;
+        unsigned int num_points = read_unsigned_integer();
+        if (has_idlist_) read_idlist(num_points);
+
+        if (num_points > 0)
+        {
+            multi_point.reserve(num_points);
+            for (unsigned int i = 0; i < num_points; ++i)
+            {
+                multi_point.emplace_back(read_point());
+            }
+        }
+        return multi_point;
+    }
+
+    mapnik::geometry::line_string<double> read_linestring()
+    {
+        mapnik::geometry::line_string<double> line;
+        unsigned int num_points = read_unsigned_integer();
+        if (num_points > 0)
+        {
+            line.reserve(num_points);
+            read_coords<mapnik::geometry::line_string<double>>(line, num_points);
+        }
+        return line;
+    }
+
+    mapnik::geometry::multi_line_string<double> read_multilinestring()
+    {
+        mapnik::geometry::multi_line_string<double> multi_line;
+        unsigned int num_lines = read_unsigned_integer();
+        if (has_idlist_) read_idlist(num_lines);
+        multi_line.reserve(num_lines);
+        for (unsigned int i = 0; i < num_lines; ++i)
+        {
+            multi_line.push_back(read_linestring());
+        }
+        return multi_line;
+    }
+
+    mapnik::geometry::polygon<double> read_polygon()
+    {
+        unsigned int num_rings = read_unsigned_integer();
+        mapnik::geometry::polygon<double> poly;
+        if (num_rings > 1)
+        {
+            poly.interior_rings.reserve(num_rings - 1);
+        }
+
+        for (unsigned int i = 0; i < num_rings; ++i)
+        {
+            mapnik::geometry::linear_ring<double> ring;
+            unsigned int num_points = read_unsigned_integer();
+            if (num_points > 0)
+            {
+                ring.reserve(num_points);
+                read_coords<mapnik::geometry::linear_ring<double>>(ring, num_points);
+            }
+            if ( i == 0) poly.set_exterior_ring(std::move(ring));
+            else poly.add_hole(std::move(ring));
+        }
+        return poly;
+    }
+
+    mapnik::geometry::multi_polygon<double> read_multipolygon()
+    {
+        mapnik::geometry::multi_polygon<double> multi_poly;
+        unsigned int num_polys = read_unsigned_integer();
+        if (has_idlist_) read_idlist(num_polys);
+        for (unsigned int i = 0; i < num_polys; ++i)
+        {
+            multi_poly.push_back(read_polygon());
+        }
+        return multi_poly;
+    }
+
+    mapnik::geometry::geometry_collection<double> read_collection()
+    {
+        unsigned int num_geometries = read_unsigned_integer();
+        mapnik::geometry::geometry_collection<double> collection;
+        if (has_idlist_) read_idlist(num_geometries);
+        for (unsigned int i = 0; i < num_geometries; ++i)
+        {
+            collection.push_back(read());
+        }
+        return collection;
+    }
+};
+
+} // namespace detail
+
+mapnik::geometry::geometry<double> geometry_utils::from_twkb(const char* wkb, std::size_t size)
+{
+    detail::twkb_reader reader(wkb, size);
+    mapnik::geometry::geometry<double> geom(reader.read());
+    // note: this will only be applied to polygons
+    mapnik::geometry::correct(geom);
+    return geom;
+}
+
+} // namespace mapnik
diff --git a/src/unicode.cpp b/src/unicode.cpp
index dac9b29..c96c589 100644
--- a/src/unicode.cpp
+++ b/src/unicode.cpp
@@ -27,8 +27,10 @@
 // std
 #include <stdexcept>
 
-// icu
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <unicode/ucnv.h>
+#pragma GCC diagnostic pop
 
 namespace mapnik {
 
@@ -60,4 +62,12 @@ transcoder::~transcoder()
 {
     if (conv_) ucnv_close(conv_);
 }
+
+
+void to_utf8(mapnik::value_unicode_string const& input, std::string & target)
+{
+    target.clear(); // mimic previous target.assign(...) semantics
+    input.toUTF8String(target); // this appends to target
+}
+
 }
diff --git a/src/value.cpp b/src/value.cpp
new file mode 100644
index 0000000..a3c8770
--- /dev/null
+++ b/src/value.cpp
@@ -0,0 +1,928 @@
+/*****************************************************************************
+ *
+ * This file is part of Mapnik (c++ mapping toolkit)
+ *
+ * Copyright (C) 2016 Artem Pavlenko
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *****************************************************************************/
+
+// mapnik
+#include <mapnik/value.hpp>
+#include <mapnik/value_types.hpp>
+#include <mapnik/util/conversions.hpp>
+
+// stl
+#include <cmath>
+#include <string>
+#include <type_traits>
+// icu
+#include <unicode/unistr.h>
+#include <unicode/ustring.h>
+
+namespace mapnik {
+
+namespace detail {
+
+namespace {
+template <typename T, typename U>
+struct both_arithmetic : std::integral_constant<bool,
+                                                std::is_arithmetic<T>::value &&
+                                                std::is_arithmetic<U>::value> {};
+
+struct equals
+{
+    static bool apply(value_null, value_unicode_string const& rhs)
+    {
+        return false;
+    }
+
+    template <typename T>
+    static auto apply(T const& lhs, T const& rhs)
+        -> decltype(lhs == rhs)
+    {
+        return lhs == rhs;
+    }
+};
+
+struct not_equal
+{
+    // back compatibility shim to equate empty string with null for != test
+    // https://github.com/mapnik/mapnik/issues/1859
+    // TODO - consider removing entire specialization at Mapnik 3.1.x
+    static bool apply(value_null, value_unicode_string const& rhs)
+    {
+        if (rhs.isEmpty()) return false;
+        return true;
+    }
+
+    template <typename T>
+    static auto apply(T const& lhs, T const& rhs)
+        -> decltype(lhs != rhs)
+    {
+        return lhs != rhs;
+    }
+};
+
+struct greater_than
+{
+    static bool apply(value_null, value_unicode_string const& rhs)
+    {
+        return false;
+    }
+
+    template <typename T>
+    static auto apply(T const& lhs, T const& rhs)
+        -> decltype(lhs > rhs)
+    {
+        return lhs > rhs;
+    }
+};
+
+struct greater_or_equal
+{
+    static bool apply(value_null, value_unicode_string const& rhs)
+    {
+        return false;
+    }
+
+    template <typename T>
+    static auto apply(T const& lhs, T const& rhs)
+        -> decltype(lhs >= rhs)
+    {
+        return lhs >= rhs;
+    }
+};
+
+struct less_than
+{
+    static bool apply(value_null, value_unicode_string const& rhs)
+    {
+        return false;
+    }
+
+    template <typename T>
+    static auto apply(T const& lhs, T const& rhs)
+        -> decltype(lhs < rhs)
+    {
+        return lhs < rhs;
+    }
+};
+
+struct less_or_equal
+{
+    static bool apply(value_null, value_unicode_string const& rhs)
+    {
+        return false;
+    }
+
+    template <typename T>
+    static auto apply(T const& lhs, T const& rhs)
+        -> decltype(lhs <= rhs)
+    {
+        return lhs <= rhs;
+    }
+};
+}
+
+template <typename Op, bool default_result>
+struct comparison
+{
+    // special case for unicode_strings (fixes MSVC C4800)
+    bool operator()(value_unicode_string const& lhs,
+                    value_unicode_string const& rhs) const
+    {
+        return Op::apply(lhs, rhs) ? true : false;
+    }
+
+    //////////////////////////////////////////////////////////////////////////
+    // special case for unicode_string and value_null
+    //////////////////////////////////////////////////////////////////////////
+
+    bool operator()(value_null const& lhs, value_unicode_string const& rhs) const
+    {
+        return Op::apply(lhs, rhs);
+    }
+    //////////////////////////////////////////////////////////////////////////
+
+    // same types
+    template <typename T>
+    bool operator()(T lhs, T rhs) const
+    {
+        return Op::apply(lhs, rhs);
+    }
+
+    // both types are arithmetic - promote to the common type
+    template <typename T, typename U, typename std::enable_if<both_arithmetic<T, U>::value, int>::type = 0>
+    bool operator()(T const& lhs, U const& rhs) const
+    {
+        using common_type = typename std::common_type<T, U>::type;
+        return Op::apply(static_cast<common_type>(lhs), static_cast<common_type>(rhs));
+    }
+
+    //
+    template <typename T, typename U, typename std::enable_if<!both_arithmetic<T, U>::value, int>::type = 0>
+    bool operator()(T const& lhs, U const& rhs) const
+    {
+        return default_result;
+    }
+};
+
+template <typename V>
+struct add
+{
+    using value_type = V;
+    value_type operator()(value_unicode_string const& lhs,
+                          value_unicode_string const& rhs) const
+    {
+        return lhs + rhs;
+    }
+
+    value_type operator()(value_null const& lhs,
+                          value_null const& rhs) const
+    {
+        return lhs;
+    }
+
+    value_type operator()(value_unicode_string const& lhs, value_null) const
+    {
+        return lhs;
+    }
+
+    value_type operator()(value_null, value_unicode_string const& rhs) const
+    {
+        return rhs;
+    }
+
+    template <typename L>
+    value_type operator()(L const& lhs, value_null const&) const
+    {
+        return lhs;
+    }
+
+    template <typename R>
+    value_type operator()(value_null const&, R const& rhs) const
+    {
+        return rhs;
+    }
+
+    template <typename L>
+    value_type operator()(L const& lhs, value_unicode_string const& rhs) const
+    {
+        std::string val;
+        if (util::to_string(val, lhs))
+            return value_unicode_string(val.c_str()) + rhs;
+        return rhs;
+    }
+
+    template <typename R>
+    value_type operator()(value_unicode_string const& lhs, R const& rhs) const
+    {
+        std::string val;
+        if (util::to_string(val, rhs))
+            return lhs + value_unicode_string(val.c_str());
+        return lhs;
+    }
+
+    template <typename T1, typename T2>
+    value_type operator()(T1 const& lhs, T2 const& rhs) const
+    {
+        return typename std::common_type<T1, T2>::type{lhs + rhs};
+    }
+
+    value_type operator()(value_bool lhs, value_bool rhs) const
+    {
+        return value_integer(lhs + rhs);
+    }
+};
+
+template <typename V>
+struct sub
+{
+    using value_type = V;
+
+    value_type operator()(value_null const& lhs,
+                          value_null const& rhs) const
+    {
+        return lhs;
+    }
+
+    value_type operator()(value_null, value_unicode_string const& rhs) const
+    {
+        return rhs;
+    }
+    value_type operator()(value_unicode_string const& lhs, value_null) const
+    {
+        return lhs;
+    }
+
+    template <typename R>
+    value_type operator()(value_unicode_string const& lhs, R const&) const
+    {
+        return lhs;
+    }
+
+    template <typename L>
+    value_type operator()(L const&, value_unicode_string const& rhs) const
+    {
+        return rhs;
+    }
+
+    template <typename L>
+    value_type operator()(L const& lhs, value_null const&) const
+    {
+        return lhs;
+    }
+
+    template <typename R>
+    value_type operator()(value_null const&, R const& rhs) const
+    {
+        return rhs;
+    }
+
+    template <typename T>
+    value_type operator()(T lhs, T rhs) const
+    {
+        return lhs - rhs;
+    }
+
+    value_type operator()(value_unicode_string const&,
+                          value_unicode_string const&) const
+    {
+        return value_type();
+    }
+
+    template <typename T1, typename T2>
+    value_type operator()(T1 const& lhs, T2 const& rhs) const
+    {
+        return typename std::common_type<T1, T2>::type{lhs - rhs};
+    }
+
+    value_type operator()(value_bool lhs, value_bool rhs) const
+    {
+        return value_integer(lhs - rhs);
+    }
+};
+
+template <typename V>
+struct mult
+{
+    using value_type = V;
+
+    value_type operator()(value_null const& lhs,
+                          value_null const& rhs) const
+    {
+        return lhs;
+    }
+
+    value_type operator()(value_unicode_string const& lhs, value_null) const
+    {
+        return lhs;
+    }
+
+    value_type operator()(value_null, value_unicode_string const& rhs) const
+    {
+        return rhs;
+    }
+
+    template <typename L>
+    value_type operator()(L const& lhs, value_null const&) const
+    {
+        return lhs;
+    }
+
+    template <typename R>
+    value_type operator()(value_null const&, R const& rhs) const
+    {
+        return rhs;
+    }
+
+    template <typename R>
+    value_type operator()(value_unicode_string const& lhs, R const&) const
+    {
+        return lhs;
+    }
+
+    template <typename L>
+    value_type operator()(L const&, value_unicode_string const& rhs) const
+    {
+        return rhs;
+    }
+
+    template <typename T>
+    value_type operator()(T lhs, T rhs) const
+    {
+        return lhs * rhs;
+    }
+
+    value_type operator()(value_unicode_string const&,
+                          value_unicode_string const&) const
+    {
+        return value_type();
+    }
+
+    template <typename T1, typename T2>
+    value_type operator()(T1 const& lhs, T2 const& rhs) const
+    {
+        return typename std::common_type<T1, T2>::type{lhs * rhs};
+    }
+
+    value_type operator()(value_bool lhs, value_bool rhs) const
+    {
+        return value_integer(lhs * rhs);
+    }
+};
+
+template <typename V>
+struct div
+{
+    using value_type = V;
+
+    value_type operator()(value_null const& lhs,
+                          value_null const& rhs) const
+    {
+        return lhs;
+    }
+
+    value_type operator()(value_unicode_string const& lhs, value_null) const
+    {
+        return lhs;
+    }
+
+    value_type operator()(value_null, value_unicode_string const& rhs) const
+    {
+        return rhs;
+    }
+
+    template <typename L>
+    value_type operator()(L const& lhs, value_null const&) const
+    {
+        return lhs;
+    }
+
+    template <typename R>
+    value_type operator()(value_null const&, R const& rhs) const
+    {
+        return rhs;
+    }
+
+    template <typename T>
+    value_type operator()(T lhs, T rhs) const
+    {
+        if (rhs == 0) return value_type();
+        return lhs / rhs;
+    }
+
+    value_type operator()(value_bool lhs, value_bool rhs) const
+    {
+        if (rhs == 0) return lhs;
+        return value_integer(lhs) / value_integer(rhs);
+    }
+
+    value_type operator()(value_unicode_string const&,
+                          value_unicode_string const&) const
+    {
+        return value_type();
+    }
+
+    template <typename R>
+    value_type operator()(value_unicode_string const& lhs, R const&) const
+    {
+        return lhs;
+    }
+
+    template <typename L>
+    value_type operator()(L const&, value_unicode_string const& rhs) const
+    {
+        return rhs;
+    }
+
+    template <typename T1, typename T2>
+    value_type operator()(T1 const& lhs, T2 const& rhs) const
+    {
+        if (rhs == 0) return value_type();
+        using common_type = typename std::common_type<T1, T2>::type;
+        return common_type(lhs) / common_type(rhs);
+    }
+};
+
+template <typename V>
+struct mod
+{
+    using value_type = V;
+
+    template <typename T1, typename T2>
+    value_type operator()(T1 const& lhs, T2 const&) const
+    {
+        return lhs;
+    }
+
+    template <typename T>
+    value_type operator()(T lhs, T rhs) const
+    {
+        return lhs % rhs;
+    }
+
+    value_type operator()(value_unicode_string const&,
+                          value_unicode_string const&) const
+    {
+        return value_type();
+    }
+
+    value_type operator()(value_bool,
+                          value_bool) const
+    {
+        return false;
+    }
+
+    value_type operator()(value_double lhs, value_integer rhs) const
+    {
+        return std::fmod(lhs, static_cast<value_double>(rhs));
+    }
+
+    value_type operator()(value_integer lhs, value_double rhs) const
+    {
+        return std::fmod(static_cast<value_double>(lhs), rhs);
+    }
+
+    value_type operator()(value_double lhs, value_double rhs) const
+    {
+        return std::fmod(lhs, rhs);
+    }
+};
+
+template <typename V>
+struct negate
+{
+    using value_type = V;
+
+    template <typename T>
+    value_type operator()(T val) const
+    {
+        return -val;
+    }
+
+    value_type operator()(value_null val) const
+    {
+        return val;
+    }
+
+    value_type operator()(value_bool val) const
+    {
+        return val ? value_integer(-1) : value_integer(0);
+    }
+
+    value_type operator()(value_unicode_string const&) const
+    {
+        return value_type();
+    }
+};
+
+// converters
+template <typename T>
+struct convert
+{
+};
+
+template <>
+struct convert<value_bool>
+{
+    value_bool operator()(value_bool val) const
+    {
+        return val;
+    }
+
+    value_bool operator()(value_unicode_string const& ustr) const
+    {
+        return !ustr.isEmpty();
+    }
+
+    value_bool operator()(value_null const&) const
+    {
+        return false;
+    }
+
+    template <typename T>
+    value_bool operator()(T val) const
+    {
+        return val > 0 ? true : false;
+    }
+};
+
+template <>
+struct convert<value_double>
+{
+    value_double operator()(value_double val) const
+    {
+        return val;
+    }
+
+    value_double operator()(value_integer val) const
+    {
+        return static_cast<value_double>(val);
+    }
+
+    value_double operator()(value_bool val) const
+    {
+        return static_cast<value_double>(val);
+    }
+
+    value_double operator()(std::string const& val) const
+    {
+        value_double result;
+        if (util::string2double(val, result))
+            return result;
+        return 0;
+    }
+
+    value_double operator()(value_unicode_string const& val) const
+    {
+        std::string utf8;
+        val.toUTF8String(utf8);
+        return operator()(utf8);
+    }
+
+    value_double operator()(value_null const&) const
+    {
+        return 0.0;
+    }
+};
+
+template <>
+struct convert<value_integer>
+{
+    value_integer operator()(value_integer val) const
+    {
+        return val;
+    }
+
+    value_integer operator()(value_double val) const
+    {
+        return static_cast<value_integer>(rint(val));
+    }
+
+    value_integer operator()(value_bool val) const
+    {
+        return static_cast<value_integer>(val);
+    }
+
+    value_integer operator()(std::string const& val) const
+    {
+        value_integer result;
+        if (util::string2int(val, result))
+            return result;
+        return value_integer(0);
+    }
+
+    value_integer operator()(value_unicode_string const& val) const
+    {
+        std::string utf8;
+        val.toUTF8String(utf8);
+        return operator()(utf8);
+    }
+
+    value_integer operator()(value_null const&) const
+    {
+        return value_integer(0);
+    }
+};
+
+template <>
+struct convert<std::string>
+{
+    template <typename T>
+    std::string operator()(T val) const
+    {
+        std::string str;
+        util::to_string(str, val);
+        return str;
+    }
+
+    // specializations
+    std::string operator()(value_unicode_string const& val) const
+    {
+        std::string utf8;
+        val.toUTF8String(utf8);
+        return utf8;
+    }
+
+    std::string operator()(value_double val) const
+    {
+        std::string str;
+        util::to_string(str, val); // TODO set precision(16)
+        return str;
+    }
+
+    std::string operator()(value_bool val) const
+    {
+        return val ? "true" : "false";
+    }
+
+    std::string operator()(value_null const&) const
+    {
+        return std::string();
+    }
+};
+
+struct to_unicode_impl
+{
+
+    template <typename T>
+    value_unicode_string operator()(T val) const
+    {
+        std::string str;
+        util::to_string(str, val);
+        return value_unicode_string(str.c_str());
+    }
+
+    // specializations
+    value_unicode_string const& operator()(value_unicode_string const& val) const
+    {
+        return val;
+    }
+
+    value_unicode_string operator()(value_double val) const
+    {
+        std::string str;
+        util::to_string(str, val);
+        return value_unicode_string(str.c_str());
+    }
+
+    value_unicode_string operator()(value_bool val) const
+    {
+        return value_unicode_string(val ? "true" : "false");
+    }
+
+    value_unicode_string operator()(value_null const&) const
+    {
+        return value_unicode_string();
+    }
+};
+
+struct to_expression_string_impl
+{
+    struct EscapingByteSink : U_NAMESPACE_QUALIFIER ByteSink
+    {
+        std::string dest_;
+        char quote_;
+
+        explicit EscapingByteSink(char quote)
+            : quote_(quote)
+        {
+        }
+
+        virtual void Append(const char* data, int32_t n)
+        {
+            // reserve enough room to hold the appended chunk and quotes;
+            // if another chunk follows, or any character needs escaping,
+            // the string will grow naturally
+            if (dest_.empty())
+            {
+                dest_.reserve(2 + static_cast<std::size_t>(n));
+                dest_.append(1, quote_);
+            }
+            else
+            {
+                dest_.reserve(dest_.size() + n + 1);
+            }
+
+            for (auto end = data + n; data < end; ++data)
+            {
+                if (*data == '\\' || *data == quote_)
+                    dest_.append(1, '\\');
+                dest_.append(1, *data);
+            }
+        }
+
+        virtual void Flush()
+        {
+            if (dest_.empty())
+                dest_.append(2, quote_);
+            else
+                dest_.append(1, quote_);
+        }
+    };
+
+    explicit to_expression_string_impl(char quote = '\'')
+        : quote_(quote) {}
+
+    std::string operator()(value_unicode_string const& val) const
+    {
+        // toUTF8(sink) doesn't Flush() the sink if the source string
+        // is empty -- we must return a pair of quotes in that case
+        //  https://github.com/mapnik/mapnik/issues/3362
+        if (val.isEmpty())
+        {
+            return std::string(2, quote_);
+        }
+        EscapingByteSink sink(quote_);
+        val.toUTF8(sink);
+        return sink.dest_;
+    }
+
+    std::string operator()(value_integer val) const
+    {
+        std::string output;
+        util::to_string(output, val);
+        return output;
+    }
+
+    std::string operator()(value_double val) const
+    {
+        std::string output;
+        util::to_string(output, val); // TODO precision(16)
+        return output;
+    }
+
+    std::string operator()(value_bool val) const
+    {
+        return val ? "true" : "false";
+    }
+
+    std::string operator()(value_null const&) const
+    {
+        return "null";
+    }
+
+    const char quote_;
+};
+
+} // ns detail
+
+namespace value_adl_barrier {
+
+bool value::operator==(value const& other) const
+{
+    return util::apply_visitor(detail::comparison<detail::equals, false>(), *this, other);
+}
+
+bool value::operator!=(value const& other) const
+{
+    return util::apply_visitor(detail::comparison<detail::not_equal, true>(), *this, other);
+}
+
+bool value::operator>(value const& other) const
+{
+    return util::apply_visitor(detail::comparison<detail::greater_than, false>(), *this, other);
+}
+
+bool value::operator>=(value const& other) const
+{
+    return util::apply_visitor(detail::comparison<detail::greater_or_equal, false>(), *this, other);
+}
+
+bool value::operator<(value const& other) const
+{
+    return util::apply_visitor(detail::comparison<detail::less_than, false>(), *this, other);
+}
+
+bool value::operator<=(value const& other) const
+{
+    return util::apply_visitor(detail::comparison<detail::less_or_equal, false>(), *this, other);
+}
+
+value value::operator-() const
+{
+    return util::apply_visitor(detail::negate<value>(), *this);
+}
+
+value_bool value::to_bool() const
+{
+    return util::apply_visitor(detail::convert<value_bool>(), *this);
+}
+
+std::string value::to_expression_string(char quote) const
+{
+    return util::apply_visitor(detail::to_expression_string_impl(quote), *this);
+}
+
+std::string value::to_string() const
+{
+    return util::apply_visitor(detail::convert<std::string>(), *this);
+}
+
+value_unicode_string value::to_unicode() const
+{
+    return util::apply_visitor(detail::to_unicode_impl(), *this);
+}
+
+value_double value::to_double() const
+{
+    return util::apply_visitor(detail::convert<value_double>(), *this);
+}
+
+value_integer value::to_int() const
+{
+    return util::apply_visitor(detail::convert<value_integer>(), *this);
+}
+
+bool value::is_null() const
+{
+    return util::apply_visitor(mapnik::detail::is_null_visitor(), *this);
+}
+
+template <>
+value_double value::convert() const
+{
+    return util::apply_visitor(detail::convert<value_double>(), *this);
+}
+
+template <>
+value_integer value::convert() const
+{
+    return util::apply_visitor(detail::convert<value_integer>(), *this);
+}
+
+template <>
+value_bool value::convert() const
+{
+    return util::apply_visitor(detail::convert<value_bool>(), *this);
+}
+
+template <>
+std::string value::convert() const
+{
+    return util::apply_visitor(detail::convert<std::string>(), *this);
+}
+
+//
+value operator+(value const& p1, value const& p2)
+{
+    return value(util::apply_visitor(detail::add<value>(), p1, p2));
+}
+
+value operator-(value const& p1, value const& p2)
+{
+    return value(util::apply_visitor(detail::sub<value>(), p1, p2));
+}
+
+value operator*(value const& p1, value const& p2)
+{
+    return value(util::apply_visitor(detail::mult<value>(), p1, p2));
+}
+
+value operator/(value const& p1, value const& p2)
+{
+    return value(util::apply_visitor(detail::div<value>(), p1, p2));
+}
+
+value operator%(value const& p1, value const& p2)
+{
+    return value(util::apply_visitor(detail::mod<value>(), p1, p2));
+}
+
+} // namespace value_adl_barrier
+} // namespace mapnik
diff --git a/src/vertex_adapters.cpp b/src/vertex_adapters.cpp
new file mode 100644
index 0000000..06be6c2
--- /dev/null
+++ b/src/vertex_adapters.cpp
@@ -0,0 +1,213 @@
+/*****************************************************************************
+ *
+ * This file is part of Mapnik (c++ mapping toolkit)
+ *
+ * Copyright (C) 2016 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 <mapnik/vertex_adapters.hpp>
+#include <mapnik/geometry.hpp>
+#include <mapnik/geometry_types.hpp>
+#include <mapnik/vertex.hpp>
+
+namespace mapnik { namespace geometry {
+
+// point adapter
+template <typename T>
+point_vertex_adapter<T>::point_vertex_adapter(point<T> const& pt)
+    : pt_(pt),
+      first_(true) {}
+
+template <typename T>
+unsigned point_vertex_adapter<T>::vertex(value_type * x, value_type * y) const
+{
+    if (first_)
+    {
+        *x = pt_.x;
+        *y = pt_.y;
+        first_ = false;
+        return mapnik::SEG_MOVETO;
+    }
+    return mapnik::SEG_END;
+}
+
+template <typename T>
+void point_vertex_adapter<T>::rewind(unsigned) const
+{
+    first_ = true;
+}
+
+template <typename T>
+geometry_types point_vertex_adapter<T>::type () const
+{
+    return geometry_types::Point;
+}
+
+// line_string adapter
+template <typename T>
+line_string_vertex_adapter<T>::line_string_vertex_adapter(line_string<T> const& line)
+    : line_(line),
+      current_index_(0),
+      end_index_(line.size())
+{}
+
+template <typename T>
+unsigned line_string_vertex_adapter<T>::vertex(value_type * x, value_type * y) const
+{
+    if (current_index_ != end_index_)
+    {
+        point<T> const& coord = line_[current_index_++];
+        *x = coord.x;
+        *y = coord.y;
+        if (current_index_ == 1)
+        {
+            return mapnik::SEG_MOVETO;
+        }
+        else
+        {
+            return mapnik::SEG_LINETO;
+        }
+    }
+    return mapnik::SEG_END;
+}
+
+template <typename T>
+void line_string_vertex_adapter<T>::rewind(unsigned) const
+{
+    current_index_ = 0;
+}
+
+template <typename T>
+geometry_types line_string_vertex_adapter<T>::type() const
+{
+    return geometry_types::LineString;
+}
+
+template <typename T>
+polygon_vertex_adapter<T>::polygon_vertex_adapter(polygon<T> const& poly)
+    : poly_(poly),
+      rings_itr_(0),
+      rings_end_(poly_.interior_rings.size() + 1),
+      current_index_(0),
+      end_index_((rings_itr_ < rings_end_) ? poly_.exterior_ring.size() : 0),
+      start_loop_(true) {}
+
+template <typename T>
+void polygon_vertex_adapter<T>::rewind(unsigned) const
+{
+    rings_itr_ = 0;
+    rings_end_ = poly_.interior_rings.size() + 1;
+    current_index_ = 0;
+    end_index_ = (rings_itr_ < rings_end_) ? poly_.exterior_ring.size() : 0;
+    start_loop_ = true;
+}
+template <typename T>
+unsigned polygon_vertex_adapter<T>::vertex(value_type * x, value_type * y) const
+{
+    if (rings_itr_ == rings_end_)
+    {
+        return mapnik::SEG_END;
+    }
+    if (current_index_ < end_index_)
+    {
+        point<T> const& coord = (rings_itr_ == 0) ?
+            poly_.exterior_ring[current_index_++] : poly_.interior_rings[rings_itr_- 1][current_index_++];
+        *x = coord.x;
+        *y = coord.y;
+        if (start_loop_)
+        {
+            start_loop_= false;
+            return mapnik::SEG_MOVETO;
+        }
+        if (current_index_ == end_index_)
+        {
+            *x = 0;
+            *y = 0;
+            return mapnik::SEG_CLOSE;
+        }
+        return mapnik::SEG_LINETO;
+    }
+    else if (++rings_itr_ != rings_end_)
+    {
+        current_index_ = 0;
+        end_index_ = poly_.interior_rings[rings_itr_ - 1].size();
+        point<T> const& coord = poly_.interior_rings[rings_itr_ - 1][current_index_++];
+        *x = coord.x;
+        *y = coord.y;
+        return mapnik::SEG_MOVETO;
+    }
+    return mapnik::SEG_END;
+}
+
+template <typename T>
+geometry_types polygon_vertex_adapter<T>::type () const
+{
+    return geometry_types::Polygon;
+}
+
+// ring adapter
+template <typename T>
+ring_vertex_adapter<T>::ring_vertex_adapter(linear_ring<T> const& ring)
+    : ring_(ring),
+      current_index_(0),
+      end_index_(ring_.size()),
+      start_loop_(true) {}
+
+template <typename T>
+void ring_vertex_adapter<T>::rewind(unsigned) const
+{
+    current_index_ = 0;
+    end_index_ = ring_.size();
+    start_loop_ = true;
+}
+
+template <typename T>
+unsigned ring_vertex_adapter<T>::vertex(value_type * x, value_type * y) const
+{
+    if (current_index_ < end_index_)
+    {
+        auto const& coord = ring_[current_index_++];
+        *x = coord.x;
+        *y = coord.y;
+        if (start_loop_)
+        {
+            start_loop_= false;
+            return mapnik::SEG_MOVETO;
+        }
+        if (current_index_ == end_index_)
+        {
+            *x = 0;
+            *y = 0;
+            return mapnik::SEG_CLOSE;
+        }
+        return mapnik::SEG_LINETO;
+    }
+    return mapnik::SEG_END;
+}
+template <typename T>
+geometry_types ring_vertex_adapter<T>::type () const
+{
+    return geometry_types::Polygon;
+}
+
+template struct point_vertex_adapter<double>;
+template struct line_string_vertex_adapter<double>;
+template struct polygon_vertex_adapter<double>;
+template struct ring_vertex_adapter<double>;
+
+}}
diff --git a/src/warp.cpp b/src/warp.cpp
index 4a468a8..29cfa44 100644
--- a/src/warp.cpp
+++ b/src/warp.cpp
@@ -31,7 +31,8 @@
 #include <mapnik/raster.hpp>
 #include <mapnik/proj_transform.hpp>
 
-// agg
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_image_filters.h"
 #include "agg_trans_bilinear.h"
 #include "agg_span_interpolator_linear.h"
@@ -45,6 +46,7 @@
 #include "agg_span_allocator.h"
 #include "agg_image_accessors.h"
 #include "agg_renderer_scanline.h"
+#pragma GCC diagnostic pop
 
 namespace mapnik {
 
diff --git a/src/well_known_srs.cpp b/src/well_known_srs.cpp
index d3296ef..445d84a 100644
--- a/src/well_known_srs.cpp
+++ b/src/well_known_srs.cpp
@@ -25,8 +25,10 @@
 #include <mapnik/util/trim.hpp>
 #include <mapnik/enumeration.hpp>
 
-// boost
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/optional.hpp>
+#pragma GCC diagnostic pop
 
 namespace mapnik {
 
diff --git a/src/wkb.cpp b/src/wkb.cpp
index 19b31ca..94c1fcc 100644
--- a/src/wkb.cpp
+++ b/src/wkb.cpp
@@ -103,13 +103,13 @@ public:
         switch (format_)
         {
         case wkbSpatiaLite:
-            byteOrder_ = (wkbByteOrder) wkb_[1];
+            byteOrder_ = static_cast<wkbByteOrder>(wkb_[1]);
             pos_ = 39;
             break;
 
         case wkbGeneric:
         default:
-            byteOrder_ = (wkbByteOrder) wkb_[0];
+            byteOrder_ = static_cast<wkbByteOrder>(wkb_[0]);
             pos_ = 1;
             break;
         }
@@ -124,8 +124,12 @@ public:
         switch (type)
         {
         case wkbPoint:
-            geom = read_point();
+        {
+            auto pt = read_point();
+            if (!std::isnan(pt.x) && !std::isnan(pt.y))
+                geom = std::move(pt);
             break;
+        }
         case wkbLineString:
             geom = read_linestring();
             break;
@@ -146,11 +150,19 @@ public:
             break;
         case wkbPointZ:
         case wkbPointM:
-            geom = read_point<true>();
+        {
+            auto pt = read_point<true>();
+            if (!std::isnan(pt.x) && !std::isnan(pt.y))
+                geom = std::move(pt);
             break;
+        }
         case wkbPointZM:
-            geom = read_point<true,true>();
+        {
+            auto pt = read_point<true,true>();
+            if (!std::isnan(pt.x) && !std::isnan(pt.y))
+                geom = std::move(pt);
             break;
+        }
         case wkbLineStringZ:
         case wkbLineStringM:
             geom = read_linestring<true>();
diff --git a/test/build.py b/test/build.py
index c600d01..78fd934 100644
--- a/test/build.py
+++ b/test/build.py
@@ -9,6 +9,8 @@ test_env = env.Clone()
 if not env['CPP_TESTS']:
     for cpp_test_bin in glob.glob('./*/*-bin'):
         os.unlink(cpp_test_bin)
+    if os.path.exists('./unit/run'): os.unlink('./unit/run')
+    if os.path.exists('./visual/run'): os.unlink('./visual/run')
 else:
     test_env['LIBS'] = [env['MAPNIK_NAME']]
     test_env.AppendUnique(LIBS='mapnik-wkt')
diff --git a/test/cleanup.hpp b/test/cleanup.hpp
index f175e72..c775915 100644
--- a/test/cleanup.hpp
+++ b/test/cleanup.hpp
@@ -1,6 +1,9 @@
 #ifndef TEST_MEMORY_CLEANUP
 #define TEST_MEMORY_CLEANUP
 
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
+
 #if defined(HAVE_LIBXML2)
 #include <libxml/parser.h>
 #include <libxml/entities.h>
@@ -16,6 +19,8 @@
 #include <proj_api.h>
 #endif
 
+#pragma GCC diagnostic pop
+
 namespace testing {
 
 inline void run_cleanup()
diff --git a/test/run b/test/run
index cd45c68..f623609 100755
--- a/test/run
+++ b/test/run
@@ -9,30 +9,48 @@ source ./localize.sh
 function run_step    { >&2 echo -e "\033[1m\033[34m* $1\033[0m"; }
 function run_substep { >&2 echo -e "\033[1m\033[36m* $1\033[0m"; }
 function run_success { >&2 echo -e "\033[1m\033[32m* $1\033[0m"; }
+function run_warn    { >&2 echo -e "\033[1m\033[31m* $1\033[0m"; }
 
 run_step "Starting Mapnik tests"
 
+ran_a_test=false
 if [ -d "test/data" ]; then
 
     run_substep "Running C++ Unit tests..."
-    ./test/unit/run
-    failures=$((failures+$?))
+    if [[ -f ./test/unit/run ]]; then
+        ./test/unit/run
+        failures=$((failures+$?))
+        ran_a_test=true
+    else
+        run_warn "Skipping unit tests since they were not built"
+    fi
 
     run_substep "Running standalone C++ tests..."
+    found_test=false
     if [ -n "$(find test/standalone/ -maxdepth 1 -name '*-bin' -print -quit)" ]; then
         for FILE in test/standalone/*-bin; do
-            ${FILE};
+          found_test=true
+          ran_a_test=true
+          ${FILE};
           failures=$((failures+$?))
         done
     fi
+    if [[ $found_test == false ]]; then
+        run_warn "Skipping standalone tests since they were not built"
+    fi
 
     if [ -d "test/data-visual/styles" ]; then
         run_substep "Running visual tests..."
         if [ -z "$JOBS" ]; then
             JOBS=1
         fi
-        ./test/visual/run -j $JOBS
-        failures=$((failures+$?))
+        if [[ -f ./test/visual/run ]]; then
+            ./test/visual/run -j $JOBS
+            ran_a_test=true
+            failures=$((failures+$?))
+        else
+            run_warn "Skipping visual tests since they were not built"
+        fi
     else
         echo "Notice: Skipping visual tests, the visual tests data are not present under the standard directory \"test/data-visual\"."
     fi
@@ -41,4 +59,8 @@ else
     echo "Notice: Skipping all tests, the test data are not present under the standard directory \"test/data\"."
 fi
 
+if [[ $ran_a_test == false ]]; then
+    run_warn "**** WARNING: no tests were run ****"
+fi
+
 exit $failures
diff --git a/test/unit/color/css_color.cpp b/test/unit/color/css_color.cpp
index 54c90e7..f1bc171 100644
--- a/test/unit/color/css_color.cpp
+++ b/test/unit/color/css_color.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 #include <mapnik/css_color_grammar.hpp>
 #include <mapnik/css_color_grammar_impl.hpp>
diff --git a/test/unit/core/box2d_test.cpp b/test/unit/core/box2d_test.cpp
index 14cbb48..8385bba 100644
--- a/test/unit/core/box2d_test.cpp
+++ b/test/unit/core/box2d_test.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 #include <mapnik/coord.hpp>
diff --git a/test/unit/core/comparison_test.cpp b/test/unit/core/comparison_test.cpp
index 41b524c..7e8e8e4 100644
--- a/test/unit/core/comparison_test.cpp
+++ b/test/unit/core/comparison_test.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 #include <mapnik/value_types.hpp>
diff --git a/test/unit/core/conversions_test.cpp b/test/unit/core/conversions_test.cpp
index ba0c223..43592af 100644
--- a/test/unit/core/conversions_test.cpp
+++ b/test/unit/core/conversions_test.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 #include <mapnik/value_types.hpp>
diff --git a/test/unit/core/exceptions_test.cpp b/test/unit/core/exceptions_test.cpp
index 46abcce..16ed519 100644
--- a/test/unit/core/exceptions_test.cpp
+++ b/test/unit/core/exceptions_test.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 #include <iostream>
diff --git a/test/unit/core/expressions_test.cpp b/test/unit/core/expressions_test.cpp
index 72490a2..64cdd9e 100644
--- a/test/unit/core/expressions_test.cpp
+++ b/test/unit/core/expressions_test.cpp
@@ -1,3 +1,4 @@
+
 #include "catch_ext.hpp"
 
 #include <mapnik/expression.hpp>
@@ -87,6 +88,7 @@ TEST_CASE("expressions")
     // integer
     TRY_CHECK(parse_and_dump("123") == "123");
     // unicode
+    TRY_CHECK(parse_and_dump("''") == "''");
     TRY_CHECK(parse_and_dump("'single-quoted string'") == "'single-quoted string'");
     TRY_CHECK(parse_and_dump("\"double-quoted string\"") == "'double-quoted string'");
     TRY_CHECK(parse_and_dump("'escaped \\' apostrophe'") == "'escaped \\' apostrophe'");
@@ -180,4 +182,10 @@ TEST_CASE("expressions")
     // 'Québec' =~ m:^Q\S*$:
     TRY_CHECK(eval(" [name].match('^Q\\S*$') ") == true);
     TRY_CHECK(parse_and_dump(" [name].match('^Q\\S*$') ") == "[name].match('^Q\\S*$')");
+
+    // string & value concatenation
+    // this should evaluate as two strings concatenating, but currently fails
+    TRY_CHECK(eval("Hello + '!'") == eval("'Hello!'"));
+    // this should evaulate as a combination of an int value and string, but fails
+    TRY_CHECK(eval("[int]+m") == eval("'123m'"));
 }
diff --git a/test/unit/core/params_test.cpp b/test/unit/core/params_test.cpp
index 677de7a..3131f0c 100644
--- a/test/unit/core/params_test.cpp
+++ b/test/unit/core/params_test.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 #include <iostream>
diff --git a/test/unit/core/value_test.cpp b/test/unit/core/value_test.cpp
index 0480154..cdb64db 100644
--- a/test/unit/core/value_test.cpp
+++ b/test/unit/core/value_test.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 #include <mapnik/value_types.hpp>
diff --git a/test/unit/data/well-known-geometries.test b/test/unit/data/well-known-geometries.test
new file mode 100644
index 0000000..1c6273b
--- /dev/null
+++ b/test/unit/data/well-known-geometries.test
@@ -0,0 +1,13 @@
+POINT (30 10);\x01010000000000000000003e400000000000002440;\x01003c14
+LINESTRING (30 10, 10 30, 40 40);\x0102000000030000000000000000003e40000000000000244000000000000024400000000000003e4000000000000044400000000000004440;\x0200033c1427283c14
+POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10));\x010300000001000000050000000000000000003e4000000000000024400000000000004440000000000000444000000000000034400000000000004440000000000000244000000000000034400000000000003e400000000000002440;\x030001053c14143c270013272813
+POLYGON ((35 10, 45 45, 15 40, 10 20, 35 10),(20 30, 35 35, 30 20, 20 30));\x0103000000020000000500000000000000008041400000000000002440000000000080464000000000008046400000000000002e40000000000000444000000000000024400000000000003440000000000080414000000000000024400400000000000000000034400000000000003e40000000000080414000000000008041400000000000003e40000000000000344000000000000034400000000000003e40;\x03000205461414463b0909273213041d281e0a091d1314
+MULTIPOINT ((10 40), (40 30), (20 20), (30 10));\x010400000004000000010100000000000000000024400000000000004440010100000000000000000044400000000000003e4001010000000000000000003440000000000000344001010000000000000000003e400000000000002440;\x04000414503c1327131413
+MULTIPOINT (10 40, 40 30, 20 20, 30 10);\x010400000004000000010100000000000000000024400000000000004440010100000000000000000044400000000000003e4001010000000000000000003440000000000000344001010000000000000000003e400000000000002440;\x04000414503c1327131413
+MULTILINESTRING ((10 10, 20 20, 10 40),(40 40, 30 30, 40 20, 30 10));\x010500000002000000010200000003000000000000000000244000000000000024400000000000003440000000000000344000000000000024400000000000004440010200000004000000000000000000444000000000000044400000000000003e400000000000003e40000000000000444000000000000034400000000000003e400000000000002440;\x05000203141414141328043c00131314131313
+MULTIPOLYGON (((30 20, 45 40, 10 40, 30 20)),((15 5, 40 10, 10 20, 5 10, 15 5)));\x010600000002000000010300000001000000040000000000000000003e40000000000000344000000000008046400000000000004440000000000000244000000000000044400000000000003e400000000000003440010300000001000000050000000000000000002e4000000000000014400000000000004440000000000000244000000000000024400000000000003440000000000000144000000000000024400000000000002e400000000000001440;\x06000201043c281e284500282701051d1d320a3b1409131409
+MULTIPOLYGON (((40 40, 20 45, 45 30, 40 40)),((20 35, 10 30, 10 10, 30 5, 45 20, 20 35),(30 20, 20 15, 20 25, 30 20)));\x01060000000200000001030000000100000004000000000000000000444000000000000044400000000000003440000000000080464000000000008046400000000000003e4000000000000044400000000000004440010300000002000000060000000000000000003440000000000080414000000000000024400000000000003e40000000000000244000000000000024400000000000003e400000000000001440000000000080464000000000000034400000000000003 [...]
+GEOMETRYCOLLECTION(POINT(4 6),LINESTRING(4 6,7 10));\x010700000002000000010100000000000000000010400000000000001840010200000002000000000000000000104000000000000018400000000000001c400000000000002440;\x0700020100080c020002080c0608
+POINT EMPTY;\x0101000000000000000000f87f000000000000f87f;\x0110
+LINESTRING EMPTY;\x010200000000000000;\x0210
+POLYGON EMPTY;\x010300000000000000;\x0310
diff --git a/test/unit/datasource/csv.cpp b/test/unit/datasource/csv.cpp
index 3f466ff..6142185 100644
--- a/test/unit/datasource/csv.cpp
+++ b/test/unit/datasource/csv.cpp
@@ -24,6 +24,7 @@
 #include "ds_test_util.hpp"
 
 #include <mapnik/map.hpp>
+#include <mapnik/unicode.hpp>
 #include <mapnik/datasource.hpp>
 #include <mapnik/datasource_cache.hpp>
 #include <mapnik/geometry.hpp>
@@ -79,31 +80,11 @@ mapnik::datasource_ptr get_csv_ds(std::string const& file_name, bool strict = tr
     return ds;
 }
 
-int create_disk_index(std::string const& filename, bool silent = true)
-{
-    std::string cmd;
-    if (std::getenv("DYLD_LIBRARY_PATH") != nullptr)
-    {
-        cmd += std::string("DYLD_LIBRARY_PATH=") + std::getenv("DYLD_LIBRARY_PATH") + " ";
-    }
-    cmd += "mapnik-index " + filename;
-    if (silent)
-    {
-#ifndef _WINDOWS
-        cmd += " 2>/dev/null";
-#else
-        cmd += " 2> nul";
-#endif
-    }
-    return std::system(cmd.c_str());
-}
-
 } // anonymous namespace
 
-static const std::string csv_plugin("./plugins/input/csv.input");
-
 TEST_CASE("csv") {
 
+    std::string csv_plugin("./plugins/input/csv.input");
     if (mapnik::util::exists(csv_plugin))
     {
         // make the tests silent since we intentionally test error conditions that are noisy
@@ -161,7 +142,7 @@ TEST_CASE("csv") {
                             int ret_posix = (ret >> 8) & 0x000000ff;
                             INFO(ret);
                             INFO(ret_posix);
-                            require_fail = (path == "test/data/csv/warns/feature_id_counting.csv") ? false : true;
+                            require_fail = (boost::iends_with(path,"feature_id_counting.csv")) ? false : true;
                             if (!require_fail)
                             {
                                 REQUIRE(mapnik::util::exists(path + ".index"));
@@ -208,7 +189,7 @@ TEST_CASE("csv") {
                             int ret_posix = (ret >> 8) & 0x000000ff;
                             INFO(ret);
                             INFO(ret_posix);
-                            if (path != "test/data/csv/more_headers_than_column_values.csv") // mapnik-index won't create *.index for 0 features
+                            if (!boost::iends_with(path,"more_headers_than_column_values.csv")) // mapnik-index won't create *.index for 0 features
                             {
                                 CHECK(mapnik::util::exists(path + ".index"));
                             }
@@ -896,7 +877,15 @@ TEST_CASE("csv") {
                 auto feature = all_features(ds)->next();
                 REQUIRE(bool(feature));
                 REQUIRE(feature->has_key("Name"));
-                CHECK(feature->get("Name") == ustring(name.c_str()));
+                std::string utf8;
+                mapnik::transcoder tr("utf-8");
+                ustring expected_string = tr.transcode(name.c_str());
+                mapnik::value val(expected_string);
+                mapnik::to_utf8(expected_string,utf8);
+                INFO(feature->get("Name"));
+                INFO(utf8);
+                INFO(val);
+                CHECK(feature->get("Name") == val);
             }
         } // END SECTION
 
diff --git a/test/unit/datasource/ds_test_util.hpp b/test/unit/datasource/ds_test_util.hpp
index bfa5b17..6e1c222 100644
--- a/test/unit/datasource/ds_test_util.hpp
+++ b/test/unit/datasource/ds_test_util.hpp
@@ -20,6 +20,10 @@
  *
  *****************************************************************************/
 
+
+#ifndef MAPNIK_UNIT_DATSOURCE_UTIL
+#define MAPNIK_UNIT_DATSOURCE_UTIL
+
 #include "catch.hpp"
 
 #include <mapnik/datasource.hpp>
@@ -176,4 +180,25 @@ inline void require_geometry(mapnik::feature_ptr feature,
     CHECK(feature_count(feature->get_geometry()) == num_parts);
 }
 
+inline int create_disk_index(std::string const& filename, bool silent = true)
+{
+    std::string cmd;
+    if (std::getenv("DYLD_LIBRARY_PATH") != nullptr)
+    {
+        cmd += std::string("DYLD_LIBRARY_PATH=") + std::getenv("DYLD_LIBRARY_PATH") + " ";
+    }
+    cmd += "mapnik-index " + filename;
+    if (silent)
+    {
+#ifndef _WINDOWS
+        cmd += " 2>/dev/null";
+#else
+        cmd += " 2> nul";
+#endif
+    }
+    return std::system(cmd.c_str());
+}
+
 }
+
+#endif // MAPNIK_UNIT_DATSOURCE_UTIL
diff --git a/test/unit/datasource/geojson.cpp b/test/unit/datasource/geojson.cpp
index e8c0a90..0b0f205 100644
--- a/test/unit/datasource/geojson.cpp
+++ b/test/unit/datasource/geojson.cpp
@@ -62,25 +62,6 @@ std::pair<mapnik::datasource_ptr,mapnik::feature_ptr> fetch_first_feature(std::s
     return std::make_pair(ds,feature);
 }
 
-int create_disk_index(std::string const& filename, bool silent = true)
-{
-    std::string cmd;
-    if (std::getenv("DYLD_LIBRARY_PATH") != nullptr)
-    {
-        cmd += std::string("DYLD_LIBRARY_PATH=") + std::getenv("DYLD_LIBRARY_PATH") + " ";
-    }
-    cmd += "mapnik-index " + filename;
-    if (silent)
-    {
-#ifndef _WINDOWS
-        cmd += " 2>/dev/null";
-#else
-        cmd += " 2> nul";
-#endif
-    }
-    return std::system(cmd.c_str());
-}
-
 }
 
 TEST_CASE("geojson") {
diff --git a/test/unit/datasource/topojson.cpp b/test/unit/datasource/topojson.cpp
new file mode 100644
index 0000000..25f9ffd
--- /dev/null
+++ b/test/unit/datasource/topojson.cpp
@@ -0,0 +1,75 @@
+/*****************************************************************************
+ *
+ * This file is part of Mapnik (c++ mapping toolkit)
+ *
+ * Copyright (C) 2016 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 "catch.hpp"
+
+#include <mapnik/util/fs.hpp>
+#include <mapnik/util/file_io.hpp>
+#include <mapnik/json/topology.hpp>
+#include <mapnik/json/topojson_grammar.hpp>
+#include <mapnik/json/topojson_utils.hpp>
+
+namespace {
+
+using iterator_type = std::string::const_iterator;
+const mapnik::topojson::topojson_grammar<iterator_type> grammar;
+
+bool parse_topology(std::string const& filename, mapnik::topojson::topology & topo)
+{
+    mapnik::util::file file(filename);
+    std::string buffer;
+    buffer.resize(file.size());
+    std::fread(&buffer[0], buffer.size(), 1, file.get());
+    if (!file) return false;
+    boost::spirit::standard::space_type space;
+    iterator_type itr = buffer.begin();
+    iterator_type end = buffer.end();
+    bool result = boost::spirit::qi::phrase_parse(itr, end, grammar, space, topo);
+    return (result && (itr == end));
+}
+
+
+}
+
+TEST_CASE("topology")
+{
+    SECTION("geometry parsing")
+    {
+        mapnik::value_integer feature_id = 0;
+        mapnik::context_ptr ctx = std::make_shared<mapnik::context_type>();
+        mapnik::transcoder tr("utf8");
+        for (auto const& path : mapnik::util::list_directory("test/data/topojson/"))
+        {
+            mapnik::topojson::topology topo;
+            REQUIRE(parse_topology(path, topo));
+            for (auto const& geom : topo.geometries)
+            {
+                mapnik::box2d<double> bbox = mapnik::util::apply_visitor(mapnik::topojson::bounding_box_visitor(topo), geom);
+                CHECK(bbox.valid());
+                mapnik::topojson::feature_generator<mapnik::context_ptr> visitor(ctx, tr, topo, feature_id++);
+                mapnik::feature_ptr feature = mapnik::util::apply_visitor(visitor, geom);
+                CHECK(feature);
+                CHECK(feature->envelope() == bbox);
+            }
+        }
+    }
+}
diff --git a/test/unit/font/fontset_runtime_test.cpp b/test/unit/font/fontset_runtime_test.cpp
index e5a6211..bfbae27 100644
--- a/test/unit/font/fontset_runtime_test.cpp
+++ b/test/unit/font/fontset_runtime_test.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 #include <mapnik/memory_datasource.hpp>
diff --git a/test/unit/geometry/centroid.cpp b/test/unit/geometry/centroid.cpp
index 1e58aad..cdfbd6e 100644
--- a/test/unit/geometry/centroid.cpp
+++ b/test/unit/geometry/centroid.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 #include <mapnik/geometry_centroid.hpp>
diff --git a/test/unit/geometry/geometry.cpp b/test/unit/geometry/geometry.cpp
index 556f6ca..53c1e2e 100644
--- a/test/unit/geometry/geometry.cpp
+++ b/test/unit/geometry/geometry.cpp
@@ -9,7 +9,7 @@ TEST_CASE("geometry") {
 
 SECTION("json point") {
     mapnik::util::file input("./test/data/json/point1.json");
-    REQUIRE( input.open() );
+    REQUIRE( input );
     mapnik::geometry::geometry<double> geom;
     REQUIRE( input.data() );
     std::string json_string(input.data().get(), input.size());
@@ -24,7 +24,7 @@ SECTION("json point") {
 
 SECTION("json point reversed") {
     mapnik::util::file input("./test/data/json/point2.json");
-    REQUIRE( input.open() );
+    REQUIRE( input );
     mapnik::geometry::geometry<double> geom;
     REQUIRE( input.data() );
     std::string json_string(input.data().get(), input.size());
@@ -37,7 +37,7 @@ SECTION("json point reversed") {
 
 SECTION("json point reversed + extra attributes") {
     mapnik::util::file input("./test/data/json/point3.json");
-    REQUIRE( input.open() );
+    REQUIRE( input );
     mapnik::geometry::geometry<double> geom;
     REQUIRE( input.data() );
     std::string json_string(input.data().get(), input.size());
diff --git a/test/unit/geometry/geometry_envelope_test.cpp b/test/unit/geometry/geometry_envelope_test.cpp
index d23c976..fd5d78f 100644
--- a/test/unit/geometry/geometry_envelope_test.cpp
+++ b/test/unit/geometry/geometry_envelope_test.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 #include <mapnik/geometry.hpp>
diff --git a/test/unit/geometry/geometry_equal.hpp b/test/unit/geometry/geometry_equal.hpp
index 3907149..f8ebc4d 100644
--- a/test/unit/geometry/geometry_equal.hpp
+++ b/test/unit/geometry/geometry_equal.hpp
@@ -1,3 +1,7 @@
+
+#ifndef MAPNIK_UNIT_GEOMETRY_EQUAL
+#define MAPNIK_UNIT_GEOMETRY_EQUAL
+
 #include "catch.hpp"
 
 // boost
@@ -214,3 +218,5 @@ void assert_g_equal(T const& g1, T const& g2)
 {
     return geometry_equal_visitor()(g1,g2);
 }
+
+#endif // MAPNIK_UNIT_GEOMETRY_EQUAL
diff --git a/test/unit/geometry/geometry_hit_test.cpp b/test/unit/geometry/geometry_hit_test.cpp
index 7552d01..3b21407 100644
--- a/test/unit/geometry/geometry_hit_test.cpp
+++ b/test/unit/geometry/geometry_hit_test.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 #include <mapnik/geometry.hpp>
diff --git a/test/unit/geometry/geometry_is_simple.cpp b/test/unit/geometry/geometry_is_simple.cpp
index 1170350..5548058 100644
--- a/test/unit/geometry/geometry_is_simple.cpp
+++ b/test/unit/geometry/geometry_is_simple.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 #include <boost/version.hpp>
diff --git a/test/unit/geometry/geometry_is_valid.cpp b/test/unit/geometry/geometry_is_valid.cpp
index c36549b..de1ee4c 100644
--- a/test/unit/geometry/geometry_is_valid.cpp
+++ b/test/unit/geometry/geometry_is_valid.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 #include <mapnik/geometry.hpp>
diff --git a/test/unit/geometry/geometry_reprojection.cpp b/test/unit/geometry/geometry_reprojection.cpp
index dad9e29..c8ec362 100644
--- a/test/unit/geometry/geometry_reprojection.cpp
+++ b/test/unit/geometry/geometry_reprojection.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 #include "geometry_equal.hpp"
 
diff --git a/test/unit/geometry/geometry_strategy_test.cpp b/test/unit/geometry/geometry_strategy_test.cpp
index 50acb72..c08e828 100644
--- a/test/unit/geometry/geometry_strategy_test.cpp
+++ b/test/unit/geometry/geometry_strategy_test.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 #include "geometry_equal.hpp"
 
diff --git a/test/unit/geometry/has_empty.cpp b/test/unit/geometry/has_empty.cpp
index a240c6f..b7fcab1 100644
--- a/test/unit/geometry/has_empty.cpp
+++ b/test/unit/geometry/has_empty.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 #include <mapnik/geometry_is_empty.hpp>
diff --git a/test/unit/geometry/is_empty.cpp b/test/unit/geometry/is_empty.cpp
index bb6a634..949b2b2 100644
--- a/test/unit/geometry/is_empty.cpp
+++ b/test/unit/geometry/is_empty.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 #include <mapnik/geometry_is_empty.hpp>
diff --git a/test/unit/geometry/remove_empty.cpp b/test/unit/geometry/remove_empty.cpp
index 1523754..93881c8 100644
--- a/test/unit/geometry/remove_empty.cpp
+++ b/test/unit/geometry/remove_empty.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 #include <mapnik/geometry_remove_empty.hpp>
diff --git a/test/unit/imaging/image.cpp b/test/unit/imaging/image.cpp
index 9800860..2024953 100644
--- a/test/unit/imaging/image.cpp
+++ b/test/unit/imaging/image.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 // mapnik
diff --git a/test/unit/imaging/image_apply_opacity.cpp b/test/unit/imaging/image_apply_opacity.cpp
index 09f8dd1..512097c 100644
--- a/test/unit/imaging/image_apply_opacity.cpp
+++ b/test/unit/imaging/image_apply_opacity.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 // mapnik
diff --git a/test/unit/imaging/image_filter.cpp b/test/unit/imaging/image_filter.cpp
index 2b43c4d..5329ea4 100644
--- a/test/unit/imaging/image_filter.cpp
+++ b/test/unit/imaging/image_filter.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 // mapnik
diff --git a/test/unit/imaging/image_io_test.cpp b/test/unit/imaging/image_io_test.cpp
index f2463f8..c562148 100644
--- a/test/unit/imaging/image_io_test.cpp
+++ b/test/unit/imaging/image_io_test.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 #include <iostream>
@@ -13,7 +14,15 @@
 #include <mapnik/cairo/cairo_image_util.hpp>
 #endif
 
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/format.hpp>
+#include <boost/filesystem/convenience.hpp>
+#pragma GCC diagnostic pop
+
+inline void make_directory(std::string const& dir) {
+    boost::filesystem::create_directories(dir);
+}
 
 TEST_CASE("image io") {
 
@@ -143,25 +152,33 @@ SECTION("image_util : save_to_file/save_to_stream/save_to_string")
     supported_types.push_back(std::make_tuple("webp","webp"));
 #endif
 
+    std::string directory_name("/tmp/mapnik-tests/");
+    make_directory(directory_name);
+    REQUIRE(mapnik::util::exists(directory_name));
+
     for (auto const& info : supported_types)
     {
         std::string extension;
         std::string format;
         std::tie(extension, format) = info;
-        std::string filename = (boost::format("/tmp/mapnik-%1%.%2%") % named_color % extension).str();
+        std::string filename = (boost::format(directory_name + "mapnik-%1%.%2%") % named_color % extension).str();
         mapnik::save_to_file(im, filename);
         std::string str = mapnik::save_to_string(im, format);
         std::ostringstream ss;
         mapnik::save_to_stream(im, ss, format);
         CHECK(str.length() == ss.str().length());
-        std::unique_ptr<mapnik::image_reader> reader(mapnik::get_image_reader(filename, extension));
-        unsigned w = reader->width();
-        unsigned h = reader->height();
-        auto im2 = reader->read(0, 0, w, h);
-        CHECK(im2.size() == im.size());
-        if (extension == "png" || extension == "tiff")
+        // wrap reader in scope to ensure the file handle is
+        // released before we try to remove the file
         {
-            CHECK(0 == std::memcmp(im2.bytes(), im.bytes(), im.width() * im.height()));
+            std::unique_ptr<mapnik::image_reader> reader(mapnik::get_image_reader(filename, extension));
+            unsigned w = reader->width();
+            unsigned h = reader->height();
+            auto im2 = reader->read(0, 0, w, h);
+            CHECK(im2.size() == im.size());
+            if (extension == "png" || extension == "tiff")
+            {
+                CHECK(0 == std::memcmp(im2.bytes(), im.bytes(), im.width() * im.height()));
+            }
         }
         if (mapnik::util::exists(filename))
         {
diff --git a/test/unit/imaging/image_is_solid.cpp b/test/unit/imaging/image_is_solid.cpp
index 5bc8217..ffc527e 100644
--- a/test/unit/imaging/image_is_solid.cpp
+++ b/test/unit/imaging/image_is_solid.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 // mapnik
diff --git a/test/unit/imaging/image_painted_test.cpp b/test/unit/imaging/image_painted_test.cpp
index 5d0b403..3705f2e 100644
--- a/test/unit/imaging/image_painted_test.cpp
+++ b/test/unit/imaging/image_painted_test.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 #include <iostream>
diff --git a/test/unit/imaging/image_premultiply.cpp b/test/unit/imaging/image_premultiply.cpp
index 3a5e2a1..813d21c 100644
--- a/test/unit/imaging/image_premultiply.cpp
+++ b/test/unit/imaging/image_premultiply.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 // mapnik
diff --git a/test/unit/imaging/image_set_pixel.cpp b/test/unit/imaging/image_set_pixel.cpp
index 3488e00..d234765 100644
--- a/test/unit/imaging/image_set_pixel.cpp
+++ b/test/unit/imaging/image_set_pixel.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 // mapnik
diff --git a/test/unit/imaging/image_view.cpp b/test/unit/imaging/image_view.cpp
index 25dbacf..db129d7 100644
--- a/test/unit/imaging/image_view.cpp
+++ b/test/unit/imaging/image_view.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 // mapnik
diff --git a/test/unit/numerics/enumeration.cpp b/test/unit/numerics/enumeration.cpp
index 3c15993..64a6afc 100644
--- a/test/unit/numerics/enumeration.cpp
+++ b/test/unit/numerics/enumeration.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 #include <mapnik/enumeration.hpp>
 #include <mapnik/symbolizer_enumerations.hpp>
diff --git a/test/unit/numerics/safe_cast.cpp b/test/unit/numerics/safe_cast.cpp
index b6cba62..cb743df 100644
--- a/test/unit/numerics/safe_cast.cpp
+++ b/test/unit/numerics/safe_cast.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 #include <mapnik/safe_cast.hpp>
 
diff --git a/test/unit/pixel/agg_blend_src_over_test.cpp b/test/unit/pixel/agg_blend_src_over_test.cpp
index 60846f7..f457703 100644
--- a/test/unit/pixel/agg_blend_src_over_test.cpp
+++ b/test/unit/pixel/agg_blend_src_over_test.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 #include <iostream>
diff --git a/test/unit/pixel/palette.cpp b/test/unit/pixel/palette.cpp
index c45d068..a1e74d2 100644
--- a/test/unit/pixel/palette.cpp
+++ b/test/unit/pixel/palette.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 #include <mapnik/palette.hpp>
diff --git a/test/unit/projection/proj_transform.cpp b/test/unit/projection/proj_transform.cpp
index d2a3789..95c9595 100644
--- a/test/unit/projection/proj_transform.cpp
+++ b/test/unit/projection/proj_transform.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 #include <mapnik/projection.hpp>
diff --git a/include/mapnik/util/geometry_to_geojson.hpp b/test/unit/serialization/parse_hex.hpp
similarity index 63%
copy from include/mapnik/util/geometry_to_geojson.hpp
copy to test/unit/serialization/parse_hex.hpp
index 5cccb09..48c70a5 100644
--- a/include/mapnik/util/geometry_to_geojson.hpp
+++ b/test/unit/serialization/parse_hex.hpp
@@ -2,7 +2,7 @@
  *
  * This file is part of Mapnik (c++ mapping toolkit)
  *
- * Copyright (C) 2015 Artem Pavlenko
+ * Copyright (C) 2016 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,23 +20,25 @@
  *
  *****************************************************************************/
 
-#ifndef MAPNIK_GEOMETRY_TO_GEOJSON_HPP
-#define MAPNIK_GEOMETRY_TO_GEOJSON_HPP
+#ifndef MAPNIK_PARSE_HEX_HPP
+#define MAPNIK_PARSE_HEX_HPP
 
-// mapnik
-
-#include <mapnik/json/geometry_generator_grammar.hpp>
+#include <boost/spirit/include/qi.hpp>
+#include <boost/spirit/include/qi_char_.hpp>
 
 namespace mapnik { namespace util {
 
-inline bool to_geojson(std::string & json, mapnik::geometry::geometry<double> const& geom)
+template <typename Out>
+bool parse_hex(std::string const& input, Out & output)
 {
-    using sink_type = std::back_insert_iterator<std::string>;
-    static const mapnik::json::geometry_generator_grammar<sink_type, mapnik::geometry::geometry<double> > grammar;
-    sink_type sink(json);
-    return boost::spirit::karma::generate(sink, grammar, geom);
+    boost::spirit::qi::lit_type lit;
+    auto itr = input.begin();
+    auto end = input.end();
+    using hex2 = boost::spirit::qi::uint_parser< unsigned, 16, 2, 2 >;
+    return boost::spirit::qi::parse(itr, end, -(lit("\\x") | lit("0x")) > *hex2(), output);
 }
 
 }}
 
-#endif // MAPNIK_GEOMETRY_TO_GEOJSON_HPP
+
+#endif // MAPNIK_PARSE_HEX_HPP
diff --git a/test/unit/serialization/wkb_formats_test.cpp b/test/unit/serialization/wkb_formats_test.cpp
index 1f3a82e..bc0c171 100644
--- a/test/unit/serialization/wkb_formats_test.cpp
+++ b/test/unit/serialization/wkb_formats_test.cpp
@@ -2,11 +2,9 @@
 
 #include <iostream>
 #include <mapnik/wkb.hpp>
-#include <mapnik/feature.hpp>
 #include <mapnik/geometry_is_valid.hpp>
 #include <mapnik/geometry_is_simple.hpp>
 #include <mapnik/geometry_correct.hpp>
-#include <mapnik/feature_factory.hpp>
 #include <boost/version.hpp>
 
 TEST_CASE("geometry formats") {
@@ -55,9 +53,6 @@ SECTION("wkb") {
     unsigned char sq_invalid_blob[] = {
         0x23, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40, 0x23 };
 
-    mapnik::context_ptr ctx(new mapnik::context_type);
-    mapnik::feature_ptr feature = mapnik::feature_factory::create(ctx, 1);
-
     // test of parsing wkb geometries
     try {
 
diff --git a/test/unit/serialization/wkb_test.cpp b/test/unit/serialization/wkb_test.cpp
new file mode 100644
index 0000000..f82c4f3
--- /dev/null
+++ b/test/unit/serialization/wkb_test.cpp
@@ -0,0 +1,113 @@
+#include "catch.hpp"
+// mapnik
+#include <mapnik/wkb.hpp>
+#include <mapnik/geometry.hpp>
+#include <mapnik/geometry_adapters.hpp>
+#include <mapnik/geometry_is_empty.hpp>
+#include <mapnik/util/geometry_to_wkt.hpp>
+// bool
+#include <boost/version.hpp>
+#include <boost/geometry/algorithms/equals.hpp>
+#include <boost/geometry/policies/compare.hpp>
+// stl
+#include "parse_hex.hpp"
+#include <iostream>
+#include <string>
+#include <vector>
+#include <fstream>
+
+namespace  {
+
+struct spatially_equal_visitor
+{
+    using result_type = bool;
+
+    result_type operator() (mapnik::geometry::geometry_empty, mapnik::geometry::geometry_empty) const
+    {
+        return true;
+    }
+
+    result_type operator() (mapnik::geometry::geometry_collection<double> const& lhs, mapnik::geometry::geometry_collection<double> const& rhs) const
+    {
+        std::size_t size0 = lhs.size();
+        std::size_t size1 = rhs.size();
+        if (size0 != size1) return false;
+        for (std::size_t index = 0; index < size0 ; ++index)
+        {
+            if (!mapnik::util::apply_visitor(*this, lhs[index], rhs[index]))
+                return false;
+        }
+        return true;
+    }
+
+    result_type operator() (mapnik::geometry::multi_point<double> const& lhs, mapnik::geometry::multi_point<double> const& rhs) const
+    {
+        std::size_t size0 = lhs.size();
+        std::size_t size1 = rhs.size();
+        if (size0 != size1) return false;
+        auto tmp0 = lhs;
+        auto tmp1 = rhs;
+        std::sort(tmp0.begin(), tmp0.end(), boost::geometry::less<mapnik::geometry::point<double>>());
+        std::sort(tmp1.begin(), tmp1.end(), boost::geometry::less<mapnik::geometry::point<double>>());
+        for (std::size_t index = 0; index < size0 ; ++index)
+        {
+            if (!boost::geometry::equals(tmp0[index], tmp1[index])) return false;
+        }
+        return true;
+    }
+
+    template <typename T>
+    result_type operator() (T const& lhs, T const& rhs) const
+    {
+        if (mapnik::geometry::is_empty(lhs) && mapnik::geometry::is_empty(rhs))
+            return true; //Empty geometries of the same type are considered to be spatially equal
+        return boost::geometry::equals(lhs, rhs);
+    }
+
+    template <typename T0, typename T1>
+    result_type operator() (T0 const& lhs, T1 const& rhs) const
+    {
+        return false;
+    }
+
+};
+
+template <typename T>
+bool spatially_equal(mapnik::geometry::geometry<T> const& g0, mapnik::geometry::geometry<T> const& g1)
+{
+    return mapnik::util::apply_visitor(spatially_equal_visitor(), g0, g1);
+}
+
+}
+
+TEST_CASE("Well-known-geometries")
+{
+    SECTION("wkb")
+    {
+        std::string filename("test/unit/data/well-known-geometries.test");
+        std::ifstream is(filename.c_str(),std::ios_base::in | std::ios_base::binary);
+        if (!is) throw std::runtime_error("could not open: '" + filename + "'");
+
+        for (std::string line; std::getline(is, line,'\n');)
+        {
+            std::vector<std::string> columns;
+            boost::split(columns, line, boost::is_any_of(";"));
+            REQUIRE(columns.size() == 3);
+            std::vector<char> wkb, twkb;
+            REQUIRE(mapnik::util::parse_hex(columns[1], wkb));
+            REQUIRE(mapnik::util::parse_hex(columns[2], twkb));
+            mapnik::geometry::geometry<double> geom_0 = mapnik::geometry_utils::from_wkb(wkb.data(), wkb.size(), mapnik::wkbAuto);
+            mapnik::geometry::geometry<double> geom_1 = mapnik::geometry_utils::from_twkb(twkb.data(), twkb.size());
+            // compare WKTs
+            std::string wkt0, wkt1;
+            REQUIRE(mapnik::util::to_wkt(wkt0, geom_0));
+            REQUIRE(mapnik::util::to_wkt(wkt1, geom_1));
+            if (!mapnik::geometry::is_empty(geom_0) && !mapnik::geometry::is_empty(geom_1))
+            {
+                REQUIRE(wkt0 == wkt1);
+                // compare spatially (NOTE: GeometryCollection comparison also enforces strict order)
+                REQUIRE(spatially_equal(geom_0, geom_1));
+            }
+        }
+    }
+}
diff --git a/test/unit/serialization/xml_parser_trim.cpp b/test/unit/serialization/xml_parser_trim.cpp
index afd2824..0a556e9 100644
--- a/test/unit/serialization/xml_parser_trim.cpp
+++ b/test/unit/serialization/xml_parser_trim.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 #include <mapnik/xml_tree.hpp>
diff --git a/test/unit/svg/svg_parser_test.cpp b/test/unit/svg/svg_parser_test.cpp
index 3fee6a4..0e38304 100644
--- a/test/unit/svg/svg_parser_test.cpp
+++ b/test/unit/svg/svg_parser_test.cpp
@@ -317,7 +317,7 @@ TEST_CASE("SVG parser") {
                                                                     std::make_tuple(0, 10,2),
                                                                     std::make_tuple(0, 10,95)};
 
-        REQUIRE(std::equal(expected.begin(),expected.end(), vec.begin(),detail::vertex_equal<3>()));
+        REQUIRE(std::equal(expected.begin(),expected.end(), vec.begin(),vertex_equal<3>()));
     }
 
     SECTION("SVG viewbox fallback")
@@ -377,7 +377,7 @@ TEST_CASE("SVG parser") {
                                                                     std::make_tuple(0, 10,2),
                                                                     std::make_tuple(0, 10,95)};
 
-        REQUIRE(std::equal(expected.begin(),expected.end(), vec.begin(),detail::vertex_equal<3>()));
+        REQUIRE(std::equal(expected.begin(),expected.end(), vec.begin(),vertex_equal<3>()));
     }
 
     SECTION("SVG beveled <rect>")
diff --git a/test/unit/svg/svg_path_parser_test.cpp b/test/unit/svg/svg_path_parser_test.cpp
index db13d2b..21a094c 100644
--- a/test/unit/svg/svg_path_parser_test.cpp
+++ b/test/unit/svg/svg_path_parser_test.cpp
@@ -50,7 +50,7 @@ void test_path_parser(std::string const& str, Expected const& expected)
         vec.emplace_back(x, y, cmd);
         //std::cerr << "std::make_tuple(" << x << ", " << y << ", " << cmd  << ")," << std::endl;
     }
-    REQUIRE(std::equal(expected.begin(),expected.end(), vec.begin(), detail::vertex_equal<3>()));
+    REQUIRE(std::equal(expected.begin(),expected.end(), vec.begin(), vertex_equal<3>()));
 }
 } // anonymous ns
 
diff --git a/test/unit/svg/util.hpp b/test/unit/svg/util.hpp
index f8d9b5f..bbfcc11 100644
--- a/test/unit/svg/util.hpp
+++ b/test/unit/svg/util.hpp
@@ -25,7 +25,7 @@
 
 #include <cmath>
 
-namespace detail {
+namespace {
 
 template <int N = 6>
 struct vertex_equal
diff --git a/test/unit/symbolizer/symbolizer_test.cpp b/test/unit/symbolizer/symbolizer_test.cpp
index 3af0532..1b7c269 100644
--- a/test/unit/symbolizer/symbolizer_test.cpp
+++ b/test/unit/symbolizer/symbolizer_test.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 #include <iostream>
diff --git a/test/unit/text/shaping.cpp b/test/unit/text/shaping.cpp
index 2e2701b..d9da17e 100644
--- a/test/unit/text/shaping.cpp
+++ b/test/unit/text/shaping.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 #include <mapnik/text/icu_shaper.hpp>
 #include <mapnik/text/harfbuzz_shaper.hpp>
diff --git a/test/unit/vertex_adapter/clipping_test.cpp b/test/unit/vertex_adapter/clipping_test.cpp
index 29a3e42..2239e26 100644
--- a/test/unit/vertex_adapter/clipping_test.cpp
+++ b/test/unit/vertex_adapter/clipping_test.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 // mapnik
diff --git a/test/unit/vertex_adapter/line_offset_test.cpp b/test/unit/vertex_adapter/line_offset_test.cpp
index eba472f..dcb8dc6 100644
--- a/test/unit/vertex_adapter/line_offset_test.cpp
+++ b/test/unit/vertex_adapter/line_offset_test.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 // mapnik
diff --git a/test/unit/vertex_adapter/offset_converter.cpp b/test/unit/vertex_adapter/offset_converter.cpp
index 8c2780d..9255f7d 100644
--- a/test/unit/vertex_adapter/offset_converter.cpp
+++ b/test/unit/vertex_adapter/offset_converter.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 // mapnik
diff --git a/test/unit/vertex_adapter/simplify_converters_test.cpp b/test/unit/vertex_adapter/simplify_converters_test.cpp
index a86f8d5..b43bb93 100644
--- a/test/unit/vertex_adapter/simplify_converters_test.cpp
+++ b/test/unit/vertex_adapter/simplify_converters_test.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 //#include <mapnik/wkt/wkt_factory.hpp>
diff --git a/test/unit/vertex_adapter/vertex_adapter.cpp b/test/unit/vertex_adapter/vertex_adapter.cpp
index 4505faa..da3e815 100644
--- a/test/unit/vertex_adapter/vertex_adapter.cpp
+++ b/test/unit/vertex_adapter/vertex_adapter.cpp
@@ -1,3 +1,4 @@
+
 #include "catch.hpp"
 
 #include <mapnik/vertex_adapters.hpp>
diff --git a/utils/mapnik-config/build.py b/utils/mapnik-config/build.py
index bf3e5b3..e4178ba 100644
--- a/utils/mapnik-config/build.py
+++ b/utils/mapnik-config/build.py
@@ -131,11 +131,6 @@ mapnik_bundled_gdal_data = ''
 mapnik_bundled_proj_data = ''
 mapnik_bundled_icu_data = ''
 
-if config_env.get('MAPNIK_BUNDLED_SHARE_DIRECTORY'):
-    mapnik_bundled_gdal_data = 'lib/mapnik/share/gdal'
-    mapnik_bundled_proj_data = 'lib/mapnik/share/proj'
-    mapnik_bundled_icu_data = 'lib/mapnik/share/icu'
-
 configuration = {
     "git_revision": git_revision,
     "git_describe": git_describe,
diff --git a/utils/mapnik-index/build.py b/utils/mapnik-index/build.py
index 5bb1770..358ce5f 100644
--- a/utils/mapnik-index/build.py
+++ b/utils/mapnik-index/build.py
@@ -24,18 +24,19 @@ import glob
 from copy import copy
 
 Import ('env')
+Import ('plugin_base')
 
-program_env = env.Clone()
+program_env = plugin_base.Clone()
 
 source = Split(
     """
     mapnik-index.cpp
     process_csv_file.cpp
     process_geojson_file.cpp
+    ../../plugins/input/csv/csv_utils.cpp
     """
     )
 
-#headers = ['#plugins/input/shape'] + env['CPPPATH']
 headers = env['CPPPATH']
 
 boost_program_options = 'boost_program_options%s' % env['BOOST_APPEND']
diff --git a/utils/mapnik-index/mapnik-index.cpp b/utils/mapnik-index/mapnik-index.cpp
index f6f72be..3e1b8bb 100644
--- a/utils/mapnik-index/mapnik-index.cpp
+++ b/utils/mapnik-index/mapnik-index.cpp
@@ -163,7 +163,7 @@ int main (int argc, char** argv)
     std::clog << "max tree depth:" << depth << std::endl;
     std::clog << "split ratio:" << ratio << std::endl;
 
-    using box_type = mapnik::box2d<double>;
+    using box_type = mapnik::box2d<float>;
     using item_type = std::pair<box_type, std::pair<std::size_t, std::size_t>>;
 
     for (auto const& filename : files_to_process)
@@ -175,7 +175,7 @@ int main (int argc, char** argv)
         }
 
         std::vector<item_type> boxes;
-        mapnik::box2d<double> extent;
+        box_type extent;
         if (mapnik::detail::is_csv(filename))
         {
             std::clog << "processing '" << filename << "' as CSV\n";
@@ -198,10 +198,12 @@ int main (int argc, char** argv)
         if (extent.valid())
         {
             std::clog << extent << std::endl;
-            mapnik::quad_tree<std::pair<std::size_t, std::size_t>> tree(extent, depth, ratio);
+            mapnik::box2d<double> extent_d(extent.minx(), extent.miny(), extent.maxx(), extent.maxy());
+            mapnik::quad_tree<std::pair<std::size_t, std::size_t>> tree(extent_d, depth, ratio);
             for (auto const& item : boxes)
             {
-                tree.insert(std::get<1>(item), std::get<0>(item));
+                auto ext_f = std::get<0>(item);
+                tree.insert(std::get<1>(item), mapnik::box2d<double>(ext_f.minx(), ext_f.miny(), ext_f.maxx(), ext_f.maxy()));
             }
 
             std::fstream file((filename + ".index").c_str(),
diff --git a/utils/mapnik-index/process_csv_file.cpp b/utils/mapnik-index/process_csv_file.cpp
index 92c0728..b9834ce 100644
--- a/utils/mapnik-index/process_csv_file.cpp
+++ b/utils/mapnik-index/process_csv_file.cpp
@@ -21,13 +21,16 @@
  *****************************************************************************/
 
 #include "process_csv_file.hpp"
+#include "../../plugins/input/csv/csv_getline.hpp"
 #include "../../plugins/input/csv/csv_utils.hpp"
+#include <mapnik/datasource.hpp>
 #include <mapnik/geometry_envelope.hpp>
 #include <mapnik/util/utf_conv_win.hpp>
 
 #if defined(MAPNIK_MEMORY_MAPPED_FILE)
 #pragma GCC diagnostic push
 #include <mapnik/warning_ignore.hpp>
+#include <boost/algorithm/string.hpp>
 #include <boost/interprocess/mapped_region.hpp>
 #include <boost/interprocess/streams/bufferstream.hpp>
 #pragma GCC diagnostic pop
@@ -35,13 +38,19 @@
 #endif
 
 #include <fstream>
+#include <iostream>
+#include <sstream>
 
 namespace mapnik { namespace detail {
 
 template <typename T>
-std::pair<bool,box2d<double>> process_csv_file(T & boxes, std::string const& filename, std::string const& manual_headers, char separator, char quote)
+std::pair<bool,typename T::value_type::first_type> process_csv_file(T & boxes, std::string const& filename, std::string const& manual_headers, char separator, char quote)
 {
-    mapnik::box2d<double> extent;
+    csv_utils::csv_file_parser p;
+    p.manual_headers_ = manual_headers;
+    p.separator_ = separator;
+    p.quote_ = quote;
+
 #if defined(MAPNIK_MEMORY_MAPPED_FILE)
     using file_source_type = boost::interprocess::ibufferstream;
     file_source_type csv_file;
@@ -56,7 +65,7 @@ std::pair<bool,box2d<double>> process_csv_file(T & boxes, std::string const& fil
     else
     {
         std::clog << "Error : cannot mmap " << filename << std::endl;
-        return std::make_pair(false, extent);
+        return std::make_pair(false, box2d<float>(p.extent_));
     }
 #else
  #if defined(_WINDOWS)
@@ -67,182 +76,24 @@ std::pair<bool,box2d<double>> process_csv_file(T & boxes, std::string const& fil
     if (!csv_file.is_open())
     {
         std::clog << "Error : cannot open " << filename << std::endl;
-        return std::make_pair(false, extent);
+        return std::make_pair(false, box2d<float>(p.extent_));
     }
 #endif
-    auto file_length = ::detail::file_length(csv_file);
-    // set back to start
-    csv_file.seekg(0, std::ios::beg);
-    char newline;
-    bool has_newline;
-    char detected_quote;
-    char detected_separator;
-    std::tie(newline, has_newline, detected_separator, detected_quote) = ::detail::autodect_csv_flavour(csv_file, file_length);
-    if (quote == 0) quote = detected_quote;
-    if (separator == 0) separator = detected_separator;
-    // set back to start
-    csv_file.seekg(0, std::ios::beg);
-    std::string csv_line;
-    csv_utils::getline_csv(csv_file, csv_line, newline, quote);
-    csv_file.seekg(0, std::ios::beg);
-    int line_number = 0;
-
-    ::detail::geometry_column_locator locator;
-    std::vector<std::string> headers;
-    std::clog << "Parsing CSV using SEPARATOR=" << separator << " QUOTE=" << quote << std::endl;
-    if (!manual_headers.empty())
-    {
-        std::size_t index = 0;
-        headers = csv_utils::parse_line(manual_headers, separator, quote);
-        for (auto const& header : headers)
-        {
-            ::detail::locate_geometry_column(header, index++, locator);
-            headers.push_back(header);
-        }
-    }
-    else // parse first line as headers
-    {
-        while (csv_utils::getline_csv(csv_file,csv_line,newline, quote))
-        {
-            try
-            {
-                headers = csv_utils::parse_line(csv_line, separator, quote);
-                // skip blank lines
-                if (headers.size() > 0 && headers[0].empty()) ++line_number;
-                else
-                {
-                    std::size_t index = 0;
-                    for (auto & header : headers)
-                    {
-                        mapnik::util::trim(header);
-                        if (header.empty())
-                        {
-                            // create a placeholder for the empty header
-                            std::ostringstream s;
-                            s << "_" << index;
-                            header = s.str();
-                        }
-                        else
-                        {
-                            ::detail::locate_geometry_column(header, index, locator);
-                        }
-                        ++index;
-                    }
-                    ++line_number;
-                    break;
-                }
-            }
-            catch (std::exception const& ex)
-            {
-                std::string s("CSV index: error parsing headers: ");
-                s += ex.what();
-                std::clog << s << std::endl;
-                return std::make_pair(false, extent);
-            }
-        }
-    }
-
-    std::size_t num_headers = headers.size();
-    if (!::detail::valid(locator, num_headers))
-    {
-        std::clog << "CSV index: could not detect column(s) with the name(s) of wkt, geojson, x/y, or "
-                  << "latitude/longitude in:\n"
-                  << csv_line
-                  << "\n - this is required for reading geometry data"
-                  << std::endl;
-        return std::make_pair(false, extent);
-    }
-
-    auto pos = csv_file.tellg();
-
-    // handle rare case of a single line of data and user-provided headers
-    // where a lack of a newline will mean that csv_utils::getline_csv returns false
-    bool is_first_row = false;
-    if (!has_newline)
+    try
     {
-        csv_file.setstate(std::ios::failbit);
-        pos = 0;
-        if (!csv_line.empty())
-        {
-            is_first_row = true;
-        }
+        p.parse_csv_and_boxes(csv_file, boxes);
+        return std::make_pair(true, box2d<float>(p.extent_));
     }
-    while (is_first_row || csv_utils::getline_csv(csv_file, csv_line, newline, quote))
+    catch (std::exception const& ex)
     {
-        ++line_number;
-        auto record_offset = pos;
-        auto record_size = csv_line.length();
-        pos = csv_file.tellg();
-        is_first_row = false;
-        // skip blank lines
-        if (record_size <= 10)
-        {
-            std::string trimmed = csv_line;
-            boost::trim_if(trimmed, boost::algorithm::is_any_of("\",'\r\n "));
-            if (trimmed.empty())
-            {
-                std::clog << "CSV index: empty row encountered at line: " << line_number << std::endl;
-                continue;
-            }
-        }
-        try
-        {
-            auto const* start_line = csv_line.data();
-            auto const* end_line = start_line + csv_line.size();
-            auto values = csv_utils::parse_line(start_line, end_line, separator, quote, num_headers);
-            unsigned num_fields = values.size();
-            if (num_fields != num_headers)
-            {
-                std::ostringstream s;
-                s << "CSV Plugin: # of columns(" << num_fields << ")";
-                if (num_fields > num_headers)
-                {
-                    s << " > ";
-                }
-                else
-                {
-                    s << " < ";
-                }
-                s << "# of headers(" << num_headers << ") parsed";
-                throw mapnik::datasource_exception(s.str());
-            }
-
-            auto geom = ::detail::extract_geometry(values, locator);
-            if (!geom.is<mapnik::geometry::geometry_empty>())
-            {
-                auto box = mapnik::geometry::envelope(geom);
-                if (!extent.valid()) extent = box;
-                else extent.expand_to_include(box);
-                boxes.emplace_back(std::move(box), make_pair(record_offset, record_size));
-            }
-            else
-            {
-                std::ostringstream s;
-                s << "CSV Index: expected geometry column: could not parse row "
-                  << line_number << " "
-                  << values[locator.index] << "'";
-                throw mapnik::datasource_exception(s.str());
-            }
-        }
-        catch (mapnik::datasource_exception const& ex )
-        {
-            std::clog << ex.what() << " at line: " << line_number << std::endl;
-        }
-        catch (std::exception const& ex)
-        {
-            std::ostringstream s;
-            s << "CSV Index: unexpected error parsing line: " << line_number
-              << " - found " << headers.size() << " with values like: " << csv_line << "\n"
-              << " and got error like: " << ex.what();
-            std::clog << s.str() << std::endl;
-        }
+        std::clog << ex.what() << std::endl;
+        return std::make_pair(false, box2d<float>(p.extent_));
     }
-    return std::make_pair(true, extent);;
 }
 
-using box_type = mapnik::box2d<double>;
+using box_type = mapnik::box2d<float>;
 using item_type = std::pair<box_type, std::pair<std::size_t, std::size_t>>;
 using boxes_type = std::vector<item_type>;
-template std::pair<bool,box2d<double>> process_csv_file(boxes_type&, std::string const&, std::string const&, char, char);
+template std::pair<bool,box_type> process_csv_file(boxes_type&, std::string const&, std::string const&, char, char);
 
 }}
diff --git a/utils/mapnik-index/process_csv_file.hpp b/utils/mapnik-index/process_csv_file.hpp
index f84393d..395bf55 100644
--- a/utils/mapnik-index/process_csv_file.hpp
+++ b/utils/mapnik-index/process_csv_file.hpp
@@ -29,7 +29,7 @@
 namespace mapnik { namespace detail {
 
 template <typename T>
-std::pair<bool, box2d<double>> process_csv_file(T & boxes, std::string const& filename, std::string const& manual_headers, char separator, char quote);
+std::pair<bool, typename T::value_type::first_type> process_csv_file(T & boxes, std::string const& filename, std::string const& manual_headers, char separator, char quote);
 
 }}
 
diff --git a/utils/mapnik-index/process_geojson_file.cpp b/utils/mapnik-index/process_geojson_file.cpp
index ac0fa92..4455318 100644
--- a/utils/mapnik-index/process_geojson_file.cpp
+++ b/utils/mapnik-index/process_geojson_file.cpp
@@ -21,11 +21,6 @@
  *****************************************************************************/
 
 #include "process_geojson_file.hpp"
-#include <mapnik/geometry.hpp>
-#include <mapnik/geometry_envelope.hpp>
-#include <mapnik/geometry_adapters.hpp>
-#include <mapnik/util/file_io.hpp>
-#include <mapnik/util/utf_conv_win.hpp>
 
 #if defined(MAPNIK_MEMORY_MAPPED_FILE)
 #pragma GCC diagnostic push
@@ -35,40 +30,46 @@
 #include <boost/spirit/include/qi.hpp>
 #pragma GCC diagnostic pop
 #include <mapnik/mapped_memory_cache.hpp>
+#else
+#include <mapnik/util/file_io.hpp>
 #endif
 
-#include <mapnik/json/positions_grammar.hpp>
 #include <mapnik/json/extract_bounding_box_grammar_impl.hpp>
 #include <mapnik/json/feature_collection_grammar_impl.hpp>
 
 namespace {
+
+template <typename T>
 struct feature_validate_callback
 {
-    feature_validate_callback(mapnik::box2d<double> const& box)
+    feature_validate_callback(mapnik::box2d<T> const& box)
         : box_(box) {}
 
     void operator() (mapnik::feature_ptr const& f) const
     {
-        if (box_ != f->envelope())
+        if (box_ != box_)
         {
             throw std::runtime_error("Bounding boxes mismatch validation feature");
         }
     }
-    mapnik::box2d<double> const& box_;
+    mapnik::box2d<T> const& box_;
 };
 
+using box_type = mapnik::box2d<float>;
+using boxes_type = std::vector<std::pair<box_type, std::pair<std::size_t, std::size_t>>>;
 using base_iterator_type = char const*;
-const mapnik::json::extract_bounding_box_grammar<base_iterator_type> geojson_datasource_static_bbox_grammar;
+const mapnik::json::extract_bounding_box_grammar<base_iterator_type, boxes_type> geojson_datasource_static_bbox_grammar;
 const mapnik::transcoder tr("utf8");
-const mapnik::json::feature_grammar_callback<base_iterator_type, mapnik::feature_impl, feature_validate_callback> fc_grammar(tr);
+const mapnik::json::feature_grammar_callback<base_iterator_type, mapnik::feature_impl, feature_validate_callback<float>> fc_grammar(tr);
 }
 
 namespace mapnik { namespace detail {
 
 template <typename T>
-std::pair<bool,box2d<double>> process_geojson_file(T & boxes, std::string const& filename, bool validate_features, bool verbose)
+std::pair<bool,typename T::value_type::first_type> process_geojson_file(T & boxes, std::string const& filename, bool validate_features, bool verbose)
 {
-    mapnik::box2d<double> extent;
+    using box_type = typename T::value_type::first_type;
+    box_type extent;
 #if defined(MAPNIK_MEMORY_MAPPED_FILE)
     mapnik::mapped_region_ptr mapped_region;
     boost::optional<mapnik::mapped_region_ptr> memory =
@@ -86,7 +87,7 @@ std::pair<bool,box2d<double>> process_geojson_file(T & boxes, std::string const&
     char const* end = start + mapped_region->get_size();
 #else
     mapnik::util::file file(filename);
-    if (!file.open())
+    if (!file)
     {
         std::clog << "Error : cannot open " << filename << std::endl;
         return std::make_pair(false, extent);
@@ -125,7 +126,7 @@ std::pair<bool,box2d<double>> process_geojson_file(T & boxes, std::string const&
             {
                 base_iterator_type feat_itr = start + item.second.first;
                 base_iterator_type feat_end = feat_itr + item.second.second;
-                feature_validate_callback callback(item.first);
+                feature_validate_callback<float> callback(item.first);
                 bool result = boost::spirit::qi::phrase_parse(feat_itr, feat_end, (fc_grammar)
                                                               (boost::phoenix::ref(ctx), boost::phoenix::ref(start_id), boost::phoenix::ref(callback)),
                                                               space);
@@ -140,9 +141,6 @@ std::pair<bool,box2d<double>> process_geojson_file(T & boxes, std::string const&
     return std::make_pair(true, extent);
 }
 
-using box_type = mapnik::box2d<double>;
-using item_type = std::pair<box_type, std::pair<std::size_t, std::size_t>>;
-using boxes_type = std::vector<item_type>;
-template std::pair<bool,box2d<double>> process_geojson_file(boxes_type&, std::string const&, bool, bool);
+template std::pair<bool,box_type> process_geojson_file(boxes_type&, std::string const&, bool, bool);
 
 }}
diff --git a/utils/mapnik-index/process_geojson_file.hpp b/utils/mapnik-index/process_geojson_file.hpp
index aba4911..a377d23 100644
--- a/utils/mapnik-index/process_geojson_file.hpp
+++ b/utils/mapnik-index/process_geojson_file.hpp
@@ -29,7 +29,7 @@
 namespace mapnik { namespace detail {
 
 template <typename T>
-std::pair<bool, box2d<double>> process_geojson_file(T & boxes, std::string const& filename, bool validate_features, bool verbose);
+std::pair<bool, typename T::value_type::first_type> process_geojson_file(T & boxes, std::string const& filename, bool validate_features, bool verbose);
 
 }}
 
diff --git a/utils/pgsql2sqlite/main.cpp b/utils/pgsql2sqlite/main.cpp
index 39ced62..81eff63 100644
--- a/utils/pgsql2sqlite/main.cpp
+++ b/utils/pgsql2sqlite/main.cpp
@@ -26,10 +26,13 @@
 #include <mapnik/wkb.hpp>
 #include "connection_manager.hpp"
 
-// boost
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <boost/optional.hpp>
-#include <memory>
 #include <boost/program_options.hpp>
+#pragma GCC diagnostic pop
+
+#include <memory>
 
 //stl
 #include <iostream>
diff --git a/utils/pgsql2sqlite/sqlite.hpp b/utils/pgsql2sqlite/sqlite.hpp
index 07d2128..be4e4a3 100644
--- a/utils/pgsql2sqlite/sqlite.hpp
+++ b/utils/pgsql2sqlite/sqlite.hpp
@@ -24,8 +24,11 @@
 #include <mapnik/util/variant.hpp>
 // boost
 #include <memory>
-//sqlite3
+
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore.hpp>
 #include <sqlite3.h>
+#pragma GCC diagnostic pop
 
 //stl
 #ifdef MAPNIK_DEBUG
diff --git a/utils/shapeindex/build.py b/utils/shapeindex/build.py
index 9f7de74..2a4c2ab 100644
--- a/utils/shapeindex/build.py
+++ b/utils/shapeindex/build.py
@@ -25,7 +25,9 @@ from copy import copy
 
 Import ('env')
 
-program_env = env.Clone()
+Import ('plugin_base')
+
+program_env = plugin_base.Clone()
 
 source = Split(
     """
diff --git a/utils/shapeindex/shapeindex.cpp b/utils/shapeindex/shapeindex.cpp
index f54508c..9dcff11 100644
--- a/utils/shapeindex/shapeindex.cpp
+++ b/utils/shapeindex/shapeindex.cpp
@@ -72,13 +72,13 @@ int main (int argc,char** argv)
         if (vm.count("version"))
         {
             std::clog << "version 0.3.0" <<std::endl;
-            return 1;
+            return EXIT_FAILURE;
         }
 
         if (vm.count("help"))
         {
             std::clog << desc << std::endl;
-            return 1;
+            return EXIT_FAILURE;
         }
         if (vm.count("verbose"))
         {
@@ -105,7 +105,7 @@ int main (int argc,char** argv)
     catch (std::exception const& ex)
     {
         std::clog << "Error: " << ex.what() << std::endl;
-        return -1;
+        return EXIT_FAILURE;
     }
 
     std::clog << "max tree depth:" << depth << std::endl;
@@ -114,7 +114,7 @@ int main (int argc,char** argv)
     if (shape_files.size() == 0)
     {
         std::clog << "no shape files to index" << std::endl;
-        return 0;
+        return EXIT_FAILURE;
     }
     for (auto const& filename : shape_files)
     {
@@ -164,6 +164,11 @@ int main (int argc,char** argv)
         std::clog << "type=" << shape_type << std::endl;
         std::clog << "extent:" << extent << std::endl;
 
+        if (!extent.valid() || std::isnan(extent.width()) || std::isnan(extent.height()))
+        {
+            std::clog << "Invalid extent aborting..." << std::endl;
+            return EXIT_FAILURE;
+        }
         int pos = 50;
         shx.seek(pos * 2);
         mapnik::quad_tree<mapnik::detail::node> tree(extent, depth, ratio);
@@ -278,5 +283,5 @@ int main (int argc,char** argv)
     }
 
     std::clog << "done!" << std::endl;
-    return 0;
+    return EXIT_SUCCESS;
 }
diff --git a/utils/svg2png/svg2png.cpp b/utils/svg2png/svg2png.cpp
index c7fe797..b78f53b 100644
--- a/utils/svg2png/svg2png.cpp
+++ b/utils/svg2png/svg2png.cpp
@@ -40,12 +40,16 @@
 #include <boost/program_options.hpp>
 #pragma GCC diagnostic pop
 
+#pragma GCC diagnostic push
+#include <mapnik/warning_ignore_agg.hpp>
 #include "agg_rasterizer_scanline_aa.h"
 #include "agg_basics.h"
 #include "agg_rendering_buffer.h"
 #include "agg_renderer_base.h"
 #include "agg_pixfmt_rgba.h"
 #include "agg_scanline_u.h"
+#pragma GCC diagnostic pop
+
 
 struct main_marker_visitor
 {

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/mapnik.git



More information about the Pkg-grass-devel mailing list