diff --git a/binding.gyp b/binding.gyp
index 10ca1d18fe..a71afc7d15 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -100,7 +100,7 @@
               'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
               'MACOSX_DEPLOYMENT_TARGET':'10.8',
               'CLANG_CXX_LIBRARY': 'libc++',
-              'CLANG_CXX_LANGUAGE_STANDARD':'c++11',
+              'CLANG_CXX_LANGUAGE_STANDARD':'c++14',
               'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0'
             }
           },
diff --git a/common.gypi b/common.gypi
index 5c0d62a878..8d7b555120 100644
--- a/common.gypi
+++ b/common.gypi
@@ -5,7 +5,7 @@
     'msbuild_toolset':'v140',
     'msvs_disabled_warnings': [ 4503, 4068,4244,4005,4506,4345,4804,4805,4661 ],
     'cflags_cc' : [
-      '-std=c++11',
+      '-std=c++14',
     ],
     'cflags_cc!': ['-std=gnu++0x','-fno-rtti', '-fno-exceptions'],
     'configurations': {
diff --git a/deps/geometry b/deps/geometry
index b0d64e6e8d..b0e41cc563 160000
--- a/deps/geometry
+++ b/deps/geometry
@@ -1 +1 @@
-Subproject commit b0d64e6e8d55026781325df1068e8043ff880aff
+Subproject commit b0e41cc5635ff8d50e7e1edb73cadf1d2a7ddc83
diff --git a/deps/wagyu b/deps/wagyu
index 82ee129399..0ff3b5f829 160000
--- a/deps/wagyu
+++ b/deps/wagyu
@@ -1 +1 @@
-Subproject commit 82ee12939927cdd4e4104a047e4de4b9425882b7
+Subproject commit 0ff3b5f82908af45f32266b8cb5f107c86147d87
diff --git a/install_mason.sh b/install_mason.sh
index eabde5f4c1..201266c4b8 100755
--- a/install_mason.sh
+++ b/install_mason.sh
@@ -12,7 +12,7 @@ ICU_VERSION="57.1"
 
 if [ ! -f ./mason/mason.sh ]; then
     mkdir -p ./mason
-    curl -sSfL https://github.com/mapbox/mason/archive/e319a75b05838ca99bce1745f9d6c2fde1139b16.tar.gz | tar --gunzip --extract --strip-components=1 --exclude="*md" --exclude="test*" --directory=./mason
+    curl -sSfL https://github.com/mapbox/mason/archive/841eedd6e3ed2b53e16e630fac8918257b6a5fd7.tar.gz | tar --gunzip --extract --strip-components=1 --exclude="*md" --exclude="test*" --directory=./mason
 fi
 
 if [ ! -f ./mason_packages/.link/bin/mapnik-config ]; then
@@ -38,5 +38,5 @@ if [ ! -f ./mason_packages/.link/bin/mapnik-config ]; then
     # NOTE: sync this version with the `mapnik_version` in package.json (which is used for windows builds)
     # In the future we could pull from that version automatically if mason were to support knowing the right dep
     # versions to install automatically. Until then there is not much point since the deps are still hardcoded here.
-    install mapnik 249d6cc
+    install mapnik 304cce8ef
 fi
diff --git a/package.json b/package.json
index 998a2863cc..546de4a6ab 100644
--- a/package.json
+++ b/package.json
@@ -4,8 +4,8 @@
   "url": "http://github.com/mapnik/node-mapnik",
   "homepage": "http://mapnik.org",
   "author": "Dane Springmeyer <dane@mapbox.com> (mapnik.org)",
-  "version": "3.6.2-dev-249d6cc",
-  "mapnik_version":"249d6cc",
+  "version": "3.7.0-dev-304cce8ef",
+  "mapnik_version": "304cce8ef",
   "main": "./lib/mapnik.js",
   "binary": {
     "module_name": "mapnik",
@@ -36,16 +36,16 @@
   ],
   "license": "BSD-3-Clause",
   "dependencies": {
-    "mapnik-vector-tile": "1.4.0",
+    "mapnik-vector-tile": "https://github.com/mapbox/mapnik-vector-tile/tarball/make-strict-an-option-master",
     "protozero": "1.5.1",
     "nan": "~2.5.0",
     "node-pre-gyp": "~0.6.30"
   },
   "bundledDependencies": [
-      "node-pre-gyp"
+    "node-pre-gyp"
   ],
   "bin": {
-    "mapnik-index.js": "./bin/mapnik-index.js", 
+    "mapnik-index.js": "./bin/mapnik-index.js",
     "mapnik-inspect.js": "./bin/mapnik-inspect.js",
     "mapnik-render.js": "./bin/mapnik-render.js",
     "mapnik-shapeindex.js": "./bin/mapnik-shapeindex.js"
diff --git a/src/mapnik_datasource.cpp b/src/mapnik_datasource.cpp
index 3973527fe6..2b465c2478 100644
--- a/src/mapnik_datasource.cpp
+++ b/src/mapnik_datasource.cpp
@@ -5,7 +5,7 @@
 
 // mapnik
 #include <mapnik/attribute_descriptor.hpp>  // for attribute_descriptor
-#include <mapnik/box2d.hpp>             // for box2d
+#include <mapnik/geometry/box2d.hpp>             // for box2d
 #include <mapnik/datasource.hpp>        // for datasource, datasource_ptr, etc
 #include <mapnik/datasource_cache.hpp>  // for datasource_cache
 #include <mapnik/feature_layer_desc.hpp>  // for layer_descriptor
diff --git a/src/mapnik_feature.cpp b/src/mapnik_feature.cpp
index 03258e97f4..33ca4168c8 100644
--- a/src/mapnik_feature.cpp
+++ b/src/mapnik_feature.cpp
@@ -7,7 +7,7 @@
 #include <mapnik/unicode.hpp>
 #include <mapnik/feature_factory.hpp>
 #include <mapnik/json/feature_parser.hpp>
-#include <mapnik/value_types.hpp>
+#include <mapnik/value/types.hpp>
 #include <mapnik/util/feature_to_geojson.hpp>
 
 Nan::Persistent<v8::FunctionTemplate> Feature::constructor;
diff --git a/src/mapnik_geometry.cpp b/src/mapnik_geometry.cpp
index 24d7b08d45..ad340836dc 100644
--- a/src/mapnik_geometry.cpp
+++ b/src/mapnik_geometry.cpp
@@ -3,7 +3,7 @@
 #include "mapnik_projection.hpp"
 
 #include <mapnik/datasource.hpp>
-#include <mapnik/geometry_reprojection.hpp>
+#include <mapnik/geometry/reprojection.hpp>
 #include <mapnik/util/geometry_to_geojson.hpp>
 #include <mapnik/util/geometry_to_wkt.hpp>
 #include <mapnik/util/geometry_to_wkb.hpp>
diff --git a/src/mapnik_image.cpp b/src/mapnik_image.cpp
index f4ed8474ed..6bcc7e3a04 100644
--- a/src/mapnik_image.cpp
+++ b/src/mapnik_image.cpp
@@ -1727,11 +1727,11 @@ v8::Local<v8::Value> Image::_copySync(Nan::NAN_METHOD_ARGS_TYPE info)
     try
     {
         image_ptr imagep = std::make_shared<mapnik::image_any>(
-                                                       mapnik::image_copy(*(im->this_),
-                                                                            type,
-                                                                            offset,
-                                                                            scaling)
-                                                    );
+            mapnik::image_copy(*(im->this_),
+                               type,
+                               offset,
+                               scaling)
+            );
         Image* new_im = new Image(imagep);
         v8::Local<v8::Value> ext = Nan::New<v8::External>(new_im);
         v8::MaybeLocal<v8::Object> maybe_local = Nan::NewInstance(Nan::New(constructor)->GetFunction(), 1, &ext);
@@ -2588,6 +2588,7 @@ v8::Local<v8::Value> Image::_fromSVGSync(bool fromFile, Nan::NAN_METHOD_ARGS_TYP
 
     double scale = 1.0;
     std::uint32_t max_size = 2048;
+    bool strict = false;
     if (info.Length() >= 2)
     {
         if (!info[1]->IsObject())
@@ -2616,16 +2617,26 @@ v8::Local<v8::Value> Image::_fromSVGSync(bool fromFile, Nan::NAN_METHOD_ARGS_TYP
             v8::Local<v8::Value> opt = options->Get(Nan::New("max_size").ToLocalChecked());
             if (!opt->IsNumber())
             {
-                Nan::ThrowTypeError("max_size must be a positive integer");
+                Nan::ThrowTypeError("'max_size' must be a positive integer");
                 return scope.Escape(Nan::Undefined());
             }
             auto max_size_val = opt->IntegerValue();
             if (max_size_val < 0 || max_size_val > 65535) {
-                Nan::ThrowTypeError("max_size must be a positive integer between 0 and 65535");
+                Nan::ThrowTypeError("'max_size' must be a positive integer between 0 and 65535");
                 return scope.Escape(Nan::Undefined());
             }
             max_size = static_cast<std::uint32_t>(max_size_val);
         }
+        if (options->Has(Nan::New("strict").ToLocalChecked()))
+        {
+            v8::Local<v8::Value> opt = options->Get(Nan::New("strict").ToLocalChecked());
+            if (!opt->IsBoolean())
+            {
+                Nan::ThrowTypeError("'strict' must be a boolean value");
+                return scope.Escape(Nan::Undefined());
+            }
+            strict = opt->BooleanValue();
+        }
     }
 
     try
@@ -2635,12 +2646,13 @@ v8::Local<v8::Value> Image::_fromSVGSync(bool fromFile, Nan::NAN_METHOD_ARGS_TYP
         vertex_stl_adapter<svg_path_storage> stl_storage(marker_path->source());
         svg_path_adapter svg_path(stl_storage);
         svg_converter_type svg(svg_path, marker_path->attributes());
-        svg_parser p(svg);
+        svg_parser p(svg, strict);
         if (fromFile)
         {
-            if (!p.parse(TOSTR(info[0])))
+            p.parse(TOSTR(info[0]));
+            if (!p.err_handler().error_messages().empty())
             {
-                std::ostringstream errorMessage("");
+                std::ostringstream errorMessage;
                 errorMessage << "SVG parse error:" << std::endl;
                 for (auto const& error : p.err_handler().error_messages()) {
                     errorMessage <<  error << std::endl;
@@ -2658,9 +2670,10 @@ v8::Local<v8::Value> Image::_fromSVGSync(bool fromFile, Nan::NAN_METHOD_ARGS_TYP
                 return scope.Escape(Nan::Undefined());
             }
             std::string svg_buffer(node::Buffer::Data(obj),node::Buffer::Length(obj));
-            if (!p.parse_from_string(svg_buffer))
+            p.parse_from_string(svg_buffer);
+            if (!p.err_handler().error_messages().empty())
             {
-                std::ostringstream errorMessage("");
+                std::ostringstream errorMessage;
                 errorMessage << "SVG parse error:" << std::endl;
                 for (auto const& error : p.err_handler().error_messages()) {
                     errorMessage <<  error << std::endl;
@@ -2748,6 +2761,7 @@ typedef struct {
     bool error;
     double scale;
     std::uint32_t max_size;
+    bool strict;
     std::string error_name;
     Nan::Persistent<v8::Function> cb;
 } svg_file_ptr_baton_t;
@@ -2760,6 +2774,7 @@ typedef struct {
     bool error;
     double scale;
     std::uint32_t max_size;
+    bool strict;
     std::string error_name;
     Nan::Persistent<v8::Object> buffer;
     Nan::Persistent<v8::Function> cb;
@@ -2807,6 +2822,7 @@ NAN_METHOD(Image::fromSVG)
 
     double scale = 1.0;
     std::uint32_t max_size = 2048;
+    bool strict = false;
     if (info.Length() >= 3)
     {
         if (!info[1]->IsObject())
@@ -2835,16 +2851,26 @@ NAN_METHOD(Image::fromSVG)
             v8::Local<v8::Value> opt = options->Get(Nan::New("max_size").ToLocalChecked());
             if (!opt->IsNumber())
             {
-                Nan::ThrowTypeError("max_size must be a positive integer");
+                Nan::ThrowTypeError("'max_size' must be a positive integer");
                 return;
             }
             auto max_size_val = opt->IntegerValue();
             if (max_size_val < 0 || max_size_val > 65535) {
-                Nan::ThrowTypeError("max_size must be a positive integer between 0 and 65535");
+                Nan::ThrowTypeError("'max_size' must be a positive integer between 0 and 65535");
                 return;
             }
             max_size = static_cast<std::uint32_t>(max_size_val);
         }
+        if (options->Has(Nan::New("strict").ToLocalChecked()))
+        {
+            v8::Local<v8::Value> opt = options->Get(Nan::New("strict").ToLocalChecked());
+            if (!opt->IsBoolean())
+            {
+                Nan::ThrowTypeError("'strict' must be a boolean value");
+                return;
+            }
+            strict = opt->BooleanValue();
+        }
     }
 
     svg_file_ptr_baton_t *closure = new svg_file_ptr_baton_t();
@@ -2853,6 +2879,7 @@ NAN_METHOD(Image::fromSVG)
     closure->error = false;
     closure->scale = scale;
     closure->max_size = max_size;
+    closure->strict = strict;
     closure->cb.Reset(callback.As<v8::Function>());
     uv_queue_work(uv_default_loop(), &closure->request, EIO_FromSVG, (uv_after_work_cb)EIO_AfterFromSVG);
     return;
@@ -2869,10 +2896,11 @@ void Image::EIO_FromSVG(uv_work_t* req)
         vertex_stl_adapter<svg_path_storage> stl_storage(marker_path->source());
         svg_path_adapter svg_path(stl_storage);
         svg_converter_type svg(svg_path, marker_path->attributes());
-        svg_parser p(svg);
-        if (!p.parse(closure->filename))
+        svg_parser p(svg, closure->strict);
+        p.parse(closure->filename);
+        if (!p.err_handler().error_messages().empty())
         {
-            std::ostringstream errorMessage("");
+            std::ostringstream errorMessage;
             errorMessage << "SVG parse error:" << std::endl;
             for (auto const& error : p.err_handler().error_messages()) {
                 errorMessage <<  error << std::endl;
@@ -2945,7 +2973,7 @@ void Image::EIO_FromSVG(uv_work_t* req)
         // it is a good idea to keep this. Therefore, any exceptions thrown will fail gracefully.
         // LCOV_EXCL_START
         closure->error = true;
-        closure->error_name = "Failed to load: " + closure->filename;
+        closure->error_name = ex.what();
         // LCOV_EXCL_STOP
     }
 }
@@ -2982,12 +3010,13 @@ void Image::EIO_AfterFromSVG(uv_work_t* req)
  * @param {number} [options.scale] - scale the image. For example passing `0.5` as scale would render
  * your SVG at 50% the original size.
  * @param {number} [options.max_size] - the maximum allowed size of the svg dimensions * scale. The default is 2048.
+ * @param {boolean} [options.strict] - enable `strict` parsing mode e.g throw on unsupported element/attribute. The default is `false`.
  * This option can be passed a smaller or larger size in order to control the final size of the image allocated for
  * rasterizing the SVG.
  * @param {Function} callback = `function(err, img)`
  * @example
  * var buffer = fs.readFileSync('./path/to/image.svg');
- * mapnik.Image.fromSVGBytesSync(buffer, function(err, img) {
+ * mapnik.Image.fromSVGBytes(buffer, function(err, img) {
  *   if (err) throw err;
  *   // your custom code with `img`
  * });
@@ -3019,6 +3048,7 @@ NAN_METHOD(Image::fromSVGBytes)
 
     double scale = 1.0;
     std::uint32_t max_size = 2048;
+    bool strict = true;
     if (info.Length() >= 3)
     {
         if (!info[1]->IsObject())
@@ -3047,16 +3077,26 @@ NAN_METHOD(Image::fromSVGBytes)
             v8::Local<v8::Value> opt = options->Get(Nan::New("max_size").ToLocalChecked());
             if (!opt->IsNumber())
             {
-                Nan::ThrowTypeError("max_size must be a positive integer");
+                Nan::ThrowTypeError("'max_size' must be a positive integer");
                 return;
             }
             auto max_size_val = opt->IntegerValue();
             if (max_size_val < 0 || max_size_val > 65535) {
-                Nan::ThrowTypeError("max_size must be a positive integer between 0 and 65535");
+                Nan::ThrowTypeError("'max_size' must be a positive integer between 0 and 65535");
                 return;
             }
             max_size = static_cast<std::uint32_t>(max_size_val);
         }
+        if (options->Has(Nan::New("strict").ToLocalChecked()))
+        {
+            v8::Local<v8::Value> opt = options->Get(Nan::New("strict").ToLocalChecked());
+            if (!opt->IsBoolean())
+            {
+                Nan::ThrowTypeError("'strict' must be a boolean value");
+                return;
+            }
+            strict = opt->BooleanValue();
+        }
     }
 
     svg_mem_ptr_baton_t *closure = new svg_mem_ptr_baton_t();
@@ -3067,6 +3107,7 @@ NAN_METHOD(Image::fromSVGBytes)
     closure->data = node::Buffer::Data(obj);
     closure->scale = scale;
     closure->max_size = max_size;
+    closure->strict = strict;
     closure->dataLength = node::Buffer::Length(obj);
     uv_queue_work(uv_default_loop(), &closure->request, EIO_FromSVGBytes, (uv_after_work_cb)EIO_AfterFromSVGBytes);
     return;
@@ -3083,12 +3124,13 @@ void Image::EIO_FromSVGBytes(uv_work_t* req)
         vertex_stl_adapter<svg_path_storage> stl_storage(marker_path->source());
         svg_path_adapter svg_path(stl_storage);
         svg_converter_type svg(svg_path, marker_path->attributes());
-        svg_parser p(svg);
+        svg_parser p(svg, closure->strict);
 
         std::string svg_buffer(closure->data,closure->dataLength);
-        if (!p.parse_from_string(svg_buffer))
+        p.parse_from_string(svg_buffer);
+        if (!p.err_handler().error_messages().empty())
         {
-            std::ostringstream errorMessage("");
+            std::ostringstream errorMessage;
             errorMessage << "SVG parse error:" << std::endl;
             for (auto const& error : p.err_handler().error_messages()) {
                 errorMessage <<  error << std::endl;
@@ -3178,8 +3220,9 @@ void Image::EIO_AfterFromSVGBytes(uv_work_t* req)
     {
         Image* im = new Image(closure->im);
         v8::Local<v8::Value> ext = Nan::New<v8::External>(im);
-        v8::Local<v8::Object> image_obj = Nan::New(constructor)->GetFunction()->NewInstance(1, &ext);
-        v8::Local<v8::Value> argv[2] = { Nan::Null(), image_obj };
+        v8::MaybeLocal<v8::Object> maybe_local = Nan::NewInstance(Nan::New(constructor)->GetFunction(), 1, &ext);
+        if (maybe_local.IsEmpty()) Nan::ThrowError("Could not create new Image instance");
+        v8::Local<v8::Value> argv[2] = { Nan::Null(), maybe_local.ToLocalChecked() };
         Nan::MakeCallback(Nan::GetCurrentContext()->Global(), Nan::New(closure->cb), 2, argv);
     }
     closure->cb.Reset();
diff --git a/src/mapnik_map.cpp b/src/mapnik_map.cpp
index ec4f91f682..2434023147 100644
--- a/src/mapnik_map.cpp
+++ b/src/mapnik_map.cpp
@@ -16,7 +16,7 @@
 
 // mapnik
 #include <mapnik/agg_renderer.hpp>      // for agg_renderer
-#include <mapnik/box2d.hpp>             // for box2d
+#include <mapnik/geometry/box2d.hpp>             // for box2d
 #include <mapnik/color.hpp>             // for color
 #include <mapnik/attribute.hpp>        // for attributes
 #include <mapnik/featureset.hpp>        // for featureset_ptr
@@ -2057,7 +2057,7 @@ NAN_METHOD(Map::render)
                     return;
                 }
                 closure->fill_type = static_cast<mapnik::vector_tile_impl::polygon_fill_type>(param_val->IntegerValue());
-                if (closure->fill_type < 0 || closure->fill_type >= mapnik::vector_tile_impl::polygon_fill_type_max)
+                if (closure->fill_type >= mapnik::vector_tile_impl::polygon_fill_type_max)
                 {
                     delete closure;
                     Nan::ThrowTypeError("optional arg 'fill_type' out of possible range");
diff --git a/src/mapnik_memory_datasource.cpp b/src/mapnik_memory_datasource.cpp
index cb87e2a082..f46cac5328 100644
--- a/src/mapnik_memory_datasource.cpp
+++ b/src/mapnik_memory_datasource.cpp
@@ -3,7 +3,7 @@
 #include <mapnik/unicode.hpp>
 #include <mapnik/feature_factory.hpp>
 #include <mapnik/memory_datasource.hpp>
-#include <mapnik/value_types.hpp>
+#include <mapnik/value/types.hpp>
 
 #include "mapnik_memory_datasource.hpp"
 #include "mapnik_featureset.hpp"
diff --git a/src/mapnik_projection.cpp b/src/mapnik_projection.cpp
index e047e2eef4..b4962a4d9c 100644
--- a/src/mapnik_projection.cpp
+++ b/src/mapnik_projection.cpp
@@ -1,7 +1,7 @@
 #include "mapnik_projection.hpp"
 #include "utils.hpp"
 
-#include <mapnik/box2d.hpp>
+#include <mapnik/geometry/box2d.hpp>
 #include <mapnik/proj_transform.hpp>
 #include <mapnik/projection.hpp>
 #include <sstream>
diff --git a/src/mapnik_vector_tile.cpp b/src/mapnik_vector_tile.cpp
index dfeee99d39..73b650c0b8 100644
--- a/src/mapnik_vector_tile.cpp
+++ b/src/mapnik_vector_tile.cpp
@@ -23,13 +23,14 @@
 // mapnik
 #include <mapnik/agg_renderer.hpp>      // for agg_renderer
 #include <mapnik/datasource_cache.hpp>
-#include <mapnik/box2d.hpp>
+#include <mapnik/geometry/box2d.hpp>
 #include <mapnik/feature.hpp>
 #include <mapnik/featureset.hpp>
 #include <mapnik/feature_kv_iterator.hpp>
-#include <mapnik/geometry_is_simple.hpp>
-#include <mapnik/geometry_is_valid.hpp>
-#include <mapnik/geometry_reprojection.hpp>
+#include <mapnik/geometry/is_simple.hpp>
+#include <mapnik/geometry/is_valid.hpp>
+#include <mapnik/geometry/reprojection.hpp>
+#include <mapnik/geometry/closest_point.hpp>
 #include <mapnik/geom_util.hpp>
 #include <mapnik/hit_test_filter.hpp>
 #include <mapnik/image_any.hpp>
@@ -64,191 +65,19 @@
 // protozero
 #include <protozero/pbf_reader.hpp>
 
-namespace detail
+mapnik::geometry::closest_point_result path_to_point_distance(mapnik::geometry::geometry<double> const& geom, double x, double y)
 {
-
-struct p2p_result
-{
-    explicit p2p_result() :
-      distance(-1),
-      x_hit(0),
-      y_hit(0) {}
-
-    double distance;
-    double x_hit;
-    double y_hit;
-};
-
-struct p2p_distance
-{
-    p2p_distance(double x, double y)
-     : x_(x),
-       y_(y) {}
-
-    p2p_result operator() (mapnik::geometry::geometry_empty const& ) const
-    {
-        p2p_result p2p;
-        return p2p;
-    }
-
-    p2p_result operator() (mapnik::geometry::point<double> const& geom) const
-    {
-        p2p_result p2p;
-        p2p.x_hit = geom.x;
-        p2p.y_hit = geom.y;
-        p2p.distance = mapnik::distance(geom.x, geom.y, x_, y_);
-        return p2p;
-    }
-    p2p_result operator() (mapnik::geometry::multi_point<double> const& geom) const
-    {
-        p2p_result p2p;
-        for (auto const& pt : geom)
-        {
-            p2p_result p2p_sub = operator()(pt);
-            if (p2p_sub.distance >= 0 && (p2p.distance < 0 || p2p_sub.distance < p2p.distance))
-            {
-                p2p.x_hit = p2p_sub.x_hit;
-                p2p.y_hit = p2p_sub.y_hit;
-                p2p.distance = p2p_sub.distance;
-            }
-        }
-        return p2p;
-    }
-    p2p_result operator() (mapnik::geometry::line_string<double> const& geom) const
-    {
-        p2p_result p2p;
-        std::size_t num_points = geom.num_points();
-        if (num_points > 1)
-        {
-            for (std::size_t i = 1; i < num_points; ++i)
-            {
-                auto const& pt0 = geom[i-1];
-                auto const& pt1 = geom[i];
-                double dist = mapnik::point_to_segment_distance(x_,y_,pt0.x,pt0.y,pt1.x,pt1.y);
-                if (dist >= 0 && (p2p.distance < 0 || dist < p2p.distance))
-                {
-                    p2p.x_hit = pt0.x;
-                    p2p.y_hit = pt0.y;
-                    p2p.distance = dist;
-                }
-            }
-        }
-        return p2p;
-    }
-    p2p_result operator() (mapnik::geometry::multi_line_string<double> const& geom) const
-    {
-        p2p_result p2p;
-        for (auto const& line: geom)
-        {
-            p2p_result p2p_sub = operator()(line);
-            if (p2p_sub.distance >= 0 && (p2p.distance < 0 || p2p_sub.distance < p2p.distance))
-            {
-                p2p.x_hit = p2p_sub.x_hit;
-                p2p.y_hit = p2p_sub.y_hit;
-                p2p.distance = p2p_sub.distance;
-            }
-        }
-        return p2p;
-    }
-    p2p_result operator() (mapnik::geometry::polygon<double> const& geom) const
-    {
-        auto const& exterior = geom.exterior_ring;
-        std::size_t num_points = exterior.num_points();
-        p2p_result p2p;
-        if (num_points < 4)
-        {
-            return p2p;
-        }
-        bool inside = false;
-        for (std::size_t i = 1; i < num_points; ++i)
-        {
-            auto const& pt0 = exterior[i-1];
-            auto const& pt1 = exterior[i];
-            // todo - account for tolerance
-            if (mapnik::detail::pip(pt0.x,pt0.y,pt1.x,pt1.y,x_,y_))
-            {
-                inside = !inside;
-            }
-        }
-        if (!inside)
-        {
-            return p2p;
-        }
-        for (auto const& ring :  geom.interior_rings)
-        {
-            std::size_t num_interior_points = ring.size();
-            if (num_interior_points < 4)
-            {
-                continue;
-            }
-            for (std::size_t j = 1; j < num_interior_points; ++j)
-            {
-                auto const& pt0 = ring[j-1];
-                auto const& pt1 = ring[j];
-                if (mapnik::detail::pip(pt0.x,pt0.y,pt1.x,pt1.y,x_,y_))
-                {
-                    inside=!inside;
-                }
-            }
-        }
-        if (inside)
-        {
-            p2p.distance = 0;
-        }
-        return p2p;
-    }
-    p2p_result operator() (mapnik::geometry::multi_polygon<double> const& geom) const
-    {
-        p2p_result p2p;
-        for (auto const& poly: geom)
-        {
-            p2p_result p2p_sub = operator()(poly);
-            if (p2p_sub.distance >= 0 && (p2p.distance < 0 || p2p_sub.distance < p2p.distance))
-            {
-                p2p.x_hit = p2p_sub.x_hit;
-                p2p.y_hit = p2p_sub.y_hit;
-                p2p.distance = p2p_sub.distance;
-            }
-        }
-        return p2p;
-    }
-    p2p_result operator() (mapnik::geometry::geometry_collection<double> const& collection) const
-    {
-        // There is no current way that a geometry collection could be returned from a vector tile.
-        /* LCOV_EXCL_START */
-        p2p_result p2p;
-        for (auto const& geom: collection)
-        {
-            p2p_result p2p_sub = mapnik::util::apply_visitor((*this),geom);
-            if (p2p_sub.distance >= 0 && (p2p.distance < 0 || p2p_sub.distance < p2p.distance))
-            {
-                p2p.x_hit = p2p_sub.x_hit;
-                p2p.y_hit = p2p_sub.y_hit;
-                p2p.distance = p2p_sub.distance;
-            }
-        }
-        return p2p;
-        /* LCOV_EXCL_STOP */
-    }
-
-    double x_;
-    double y_;
-};
-
-}
-
-detail::p2p_result path_to_point_distance(mapnik::geometry::geometry<double> const& geom, double x, double y)
-{
-    return mapnik::util::apply_visitor(detail::p2p_distance(x,y), geom);
+    mapnik::geometry::point<double> pt(x, y);
+    return mapnik::geometry::closest_point(geom, pt);
 }
 
 Nan::Persistent<v8::FunctionTemplate> VectorTile::constructor;
 
 /**
- * **`mapnik.VectorTile`** 
+ * **`mapnik.VectorTile`**
 
  * A tile generator built according to the [Mapbox Vector Tile](https://github.com/mapbox/vector-tile-spec)
- * specification for compressed and simplified tiled vector data. 
+ * specification for compressed and simplified tiled vector data.
  * Learn more about vector tiles [here](https://www.mapbox.com/developers/vector-tiles/).
  *
  * @class VectorTile
@@ -314,16 +143,16 @@ void VectorTile::Initialize(v8::Local<v8::Object> target)
     ATTR(lcons, "z", get_tile_z, set_tile_z);
     ATTR(lcons, "tileSize", get_tile_size, set_tile_size);
     ATTR(lcons, "bufferSize", get_buffer_size, set_buffer_size);
-    
+
     Nan::SetMethod(lcons->GetFunction().As<v8::Object>(), "info", info);
-    
+
     target->Set(Nan::New("VectorTile").ToLocalChecked(),lcons->GetFunction());
     constructor.Reset(lcons);
 }
 
-VectorTile::VectorTile(std::uint64_t z, 
-                       std::uint64_t x, 
-                       std::uint64_t y, 
+VectorTile::VectorTile(std::uint64_t z,
+                       std::uint64_t x,
+                       std::uint64_t y,
                        std::uint32_t tile_size,
                        std::int32_t buffer_size) :
     Nan::ObjectWrap(),
@@ -335,7 +164,7 @@ VectorTile::VectorTile(std::uint64_t z,
 // I have tested it and it does print
 /* LCOV_EXCL_START */
 VectorTile::~VectorTile()
-{ 
+{
 }
 /* LCOV_EXCL_STOP */
 
@@ -346,7 +175,7 @@ NAN_METHOD(VectorTile::New)
         Nan::ThrowError("Cannot call constructor as function, you need to use 'new' keyword");
         return;
     }
-    
+
     if (info[0]->IsExternal())
     {
         v8::Local<v8::External> ext = info[0].As<v8::External>();
@@ -362,7 +191,7 @@ NAN_METHOD(VectorTile::New)
         Nan::ThrowError("please provide a z, x, y");
         return;
     }
-    
+
     if (!info[0]->IsNumber() ||
         !info[1]->IsNumber() ||
         !info[2]->IsNumber())
@@ -370,7 +199,7 @@ NAN_METHOD(VectorTile::New)
         Nan::ThrowTypeError("required parameters (z, x, and y) must be a integers");
         return;
     }
-    
+
     std::int64_t z = info[0]->IntegerValue();
     std::int64_t x = info[1]->IntegerValue();
     std::int64_t y = info[2]->IntegerValue();
@@ -513,7 +342,7 @@ void _composite(VectorTile* target_vt,
  * var vt2 = new mapnik.VectorTile(0,0,0);
  * var options = { ... };
  * vt1.compositeSync([vt2], options);
- * 
+ *
  */
 NAN_METHOD(VectorTile::compositeSync)
 {
@@ -623,7 +452,7 @@ v8::Local<v8::Value> VectorTile::_compositeSync(Nan::NAN_METHOD_ARGS_TYPE info)
                 return scope.Escape(Nan::Undefined());
             }
             fill_type = static_cast<mapnik::vector_tile_impl::polygon_fill_type>(ft->IntegerValue());
-            if (fill_type < 0 || fill_type >= mapnik::vector_tile_impl::polygon_fill_type_max)
+            if (fill_type >= mapnik::vector_tile_impl::polygon_fill_type_max)
             {
                 Nan::ThrowTypeError("optional arg 'fill_type' out of possible range");
                 return scope.Escape(Nan::Undefined());
@@ -638,8 +467,8 @@ v8::Local<v8::Value> VectorTile::_compositeSync(Nan::NAN_METHOD_ARGS_TYPE info)
                 return scope.Escape(Nan::Undefined());
             }
             threading_mode = static_cast<std::launch>(param_val->IntegerValue());
-            if (threading_mode != std::launch::async && 
-                threading_mode != std::launch::deferred && 
+            if (threading_mode != std::launch::async &&
+                threading_mode != std::launch::deferred &&
                 threading_mode != (std::launch::async | std::launch::deferred))
             {
                 Nan::ThrowTypeError("optional arg 'threading_mode' is invalid");
@@ -821,7 +650,7 @@ v8::Local<v8::Value> VectorTile::_compositeSync(Nan::NAN_METHOD_ARGS_TYPE info)
     return scope.Escape(Nan::Undefined());
 }
 
-typedef struct 
+typedef struct
 {
     uv_work_t request;
     VectorTile* d;
@@ -857,28 +686,28 @@ typedef struct
  * @param {float} [options.scale_factor=1.0]
  * @param {number} [options.offset_x=0]
  * @param {number} [options.offset_y=0]
- * @param {float} [options.area_threshold=0.1] - used to discard small polygons. 
- * If a value is greater than `0` it will trigger polygons with an area smaller 
+ * @param {float} [options.area_threshold=0.1] - used to discard small polygons.
+ * If a value is greater than `0` it will trigger polygons with an area smaller
  * than the value to be discarded. Measured in grid integers, not spherical mercator
  * coordinates.
  * @param {boolean} [options.strictly_simple=true] - ensure all geometry is valid according to
  * OGC Simple definition
  * @param {boolean} [options.multi_polygon_union=false] - union all multipolygons
  * @param {Object<mapnik.polygonFillType>} [options.fill_type=mapnik.polygonFillType.positive]
- * the fill type used in determining what are holes and what are outer rings. See the 
+ * the fill type used in determining what are holes and what are outer rings. See the
  * [Clipper documentation](http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Types/PolyFillType.htm)
  * to learn more about fill types.
  * @param {float} [options.scale_denominator=0.0]
  * @param {boolean} [options.reencode=false]
  * @param {Array<number>} [options.max_extent=minx,miny,maxx,maxy]
- * @param {float} [options.simplify_distance=0.0] - Simplification works to generalize 
- * geometries before encoding into vector tiles.simplification distance The 
+ * @param {float} [options.simplify_distance=0.0] - Simplification works to generalize
+ * geometries before encoding into vector tiles.simplification distance The
  * `simplify_distance` value works in integer space over a 4096 pixel grid and uses
  * the [Douglas-Peucker algorithm](https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm).
- * @param {boolean} [options.process_all_rings=false] - if `true`, don't assume winding order and ring order of 
+ * @param {boolean} [options.process_all_rings=false] - if `true`, don't assume winding order and ring order of
  * polygons are correct according to the [`2.0` Mapbox Vector Tile specification](https://github.com/mapbox/vector-tile-spec)
  * @param {string} [options.image_format=webp] or `jpeg`, `png`, `tiff`
- * @param {string} [options.scaling_method=bilinear] - can be any 
+ * @param {string} [options.scaling_method=bilinear] - can be any
  * of the <mapnik.imageScaling> methods
  * @param {string} [options.threading_mode=deferred]
  * @param {Function} callback - `function(err)`
@@ -902,7 +731,7 @@ typedef struct
  *   if (err) throw err;
  *   // your custom code with `vt1`
  * });
- * 
+ *
  */
 NAN_METHOD(VectorTile::composite)
 {
@@ -997,7 +826,7 @@ NAN_METHOD(VectorTile::composite)
                 return;
             }
             fill_type = static_cast<mapnik::vector_tile_impl::polygon_fill_type>(ft->IntegerValue());
-            if (fill_type < 0 || fill_type >= mapnik::vector_tile_impl::polygon_fill_type_max)
+            if (fill_type >= mapnik::vector_tile_impl::polygon_fill_type_max)
             {
                 Nan::ThrowTypeError("optional arg 'fill_type' out of possible range");
                 return;
@@ -1012,7 +841,7 @@ NAN_METHOD(VectorTile::composite)
                 return;
             }
             threading_mode = static_cast<std::launch>(param_val->IntegerValue());
-            if (threading_mode != std::launch::async && 
+            if (threading_mode != std::launch::async &&
                 threading_mode != std::launch::deferred &&
                 threading_mode != (std::launch::async | std::launch::deferred))
             {
@@ -1020,7 +849,7 @@ NAN_METHOD(VectorTile::composite)
                 return;
             }
         }
-        if (options->Has(Nan::New("simplify_distance").ToLocalChecked())) 
+        if (options->Has(Nan::New("simplify_distance").ToLocalChecked()))
         {
             v8::Local<v8::Value> param_val = options->Get(Nan::New("simplify_distance").ToLocalChecked());
             if (!param_val->IsNumber())
@@ -1035,7 +864,7 @@ NAN_METHOD(VectorTile::composite)
                 return;
             }
         }
-        if (options->Has(Nan::New("scale").ToLocalChecked())) 
+        if (options->Has(Nan::New("scale").ToLocalChecked()))
         {
             v8::Local<v8::Value> bind_opt = options->Get(Nan::New("scale").ToLocalChecked());
             if (!bind_opt->IsNumber())
@@ -1358,7 +1187,7 @@ NAN_METHOD(VectorTile::names)
  */
 NAN_METHOD(VectorTile::layer)
 {
-    if (info.Length() < 1) 
+    if (info.Length() < 1)
     {
         Nan::ThrowError("first argument must be either a layer name");
         return;
@@ -1430,7 +1259,7 @@ NAN_METHOD(VectorTile::emptyLayers)
 }
 
 /**
- * Get the names of all of the painted layers in this vector tile. "Painted" is 
+ * Get the names of all of the painted layers in this vector tile. "Painted" is
  * a check to see if data exists in the source dataset in a tile.
  *
  * @memberof VectorTile
@@ -1477,7 +1306,7 @@ NAN_METHOD(VectorTile::empty)
 }
 
 /**
- * Get whether the vector tile has been painted. "Painted" is 
+ * Get whether the vector tile has been painted. "Painted" is
  * a check to see if data exists in the source dataset in a tile.
  *
  * @memberof VectorTile
@@ -1495,7 +1324,7 @@ NAN_METHOD(VectorTile::painted)
     info.GetReturnValue().Set(Nan::New(d->tile_->is_painted()));
 }
 
-typedef struct 
+typedef struct
 {
     uv_work_t request;
     VectorTile* d;
@@ -1513,26 +1342,26 @@ typedef struct
  * Query a vector tile by longitude and latitude and get an array of
  * features in the vector tile that exist in relation to those coordinates.
  *
- * A note on `tolerance`: If you provide a positive value for tolerance you 
- * are saying that you'd like features returned in the query results that might 
- * not exactly intersect with a given lon/lat. The higher the tolerance the 
- * slower the query will run because it will do more work by comparing your query 
- * lon/lat against more potential features. However, this is an important parameter 
- * because vector tile storage, by design, results in reduced precision of coordinates. 
- * The amount of precision loss depends on the zoom level of a given vector tile 
- * and how aggressively it was simplified during encoding. So if you want at 
- * least one match - say the closest single feature to your query lon/lat - is is 
- * not possible to know the smallest tolerance that will work without experimentation. 
- * In general be prepared to provide a high tolerance (1-100) for low zoom levels 
- * while you should be okay with a low tolerance (1-10) at higher zoom levels and 
- * with vector tiles that are storing less simplified geometries. The units tolerance 
- * should be expressed in depend on the coordinate system of the underlying data. 
- * In the case of vector tiles this is spherical mercator so the units are meters. 
- * For points any features will be returned that contain a point which is, by distance 
- * in meters, not greater than the tolerance value. For lines any features will be 
- * returned that have a segment which is, by distance in meters, not greater than 
- * the tolerance value. For polygons tolerance is not supported which means that 
- * your lon/lat must fall inside a feature's polygon otherwise that feature will 
+ * A note on `tolerance`: If you provide a positive value for tolerance you
+ * are saying that you'd like features returned in the query results that might
+ * not exactly intersect with a given lon/lat. The higher the tolerance the
+ * slower the query will run because it will do more work by comparing your query
+ * lon/lat against more potential features. However, this is an important parameter
+ * because vector tile storage, by design, results in reduced precision of coordinates.
+ * The amount of precision loss depends on the zoom level of a given vector tile
+ * and how aggressively it was simplified during encoding. So if you want at
+ * least one match - say the closest single feature to your query lon/lat - is is
+ * not possible to know the smallest tolerance that will work without experimentation.
+ * In general be prepared to provide a high tolerance (1-100) for low zoom levels
+ * while you should be okay with a low tolerance (1-10) at higher zoom levels and
+ * with vector tiles that are storing less simplified geometries. The units tolerance
+ * should be expressed in depend on the coordinate system of the underlying data.
+ * In the case of vector tiles this is spherical mercator so the units are meters.
+ * For points any features will be returned that contain a point which is, by distance
+ * in meters, not greater than the tolerance value. For lines any features will be
+ * returned that have a segment which is, by distance in meters, not greater than
+ * the tolerance value. For polygons tolerance is not supported which means that
+ * your lon/lat must fall inside a feature's polygon otherwise that feature will
  * not be matched.
  *
  * @memberof VectorTile
@@ -1541,10 +1370,10 @@ typedef struct
  * @param {number} longitude - longitude
  * @param {number} latitude - latitude
  * @param {Object} [options]
- * @param {number} [options.tolerance=0] include features a specific distance from the 
+ * @param {number} [options.tolerance=0] include features a specific distance from the
  * lon/lat query in the response
- * @param {string} [options.layer] layer - Pass a layer name to restrict 
- * the query results to a single layer in the vector tile. Get all possible 
+ * @param {string} [options.layer] layer - Pass a layer name to restrict
+ * the query results to a single layer in the vector tile. Get all possible
  * layer names in the vector tile with {@link VectorTile#names}
  * @param {Function} callback(err, features)
  * @returns {Array<mapnik.Feature>} an array of {@link mapnik.Feature} objects
@@ -1606,7 +1435,7 @@ NAN_METHOD(VectorTile::query)
     // If last argument is not a function go with sync call.
     if (!info[info.Length()-1]->IsFunction())
     {
-        try  
+        try
         {
             std::vector<query_result> result = _query(d, lon, lat, tolerance, layer_name);
             v8::Local<v8::Array> arr = _queryResultToV8(result);
@@ -1618,8 +1447,8 @@ NAN_METHOD(VectorTile::query)
             Nan::ThrowError(ex.what());
             return;
         }
-    } 
-    else 
+    }
+    else
     {
         v8::Local<v8::Value> callback = info[info.Length()-1];
         vector_tile_query_baton_t *closure = new vector_tile_query_baton_t();
@@ -1715,7 +1544,7 @@ std::vector<query_result> VectorTile::_query(VectorTile* d, double lon, double l
                 {
                     auto const& geom = feature->get_geometry();
                     auto p2p = path_to_point_distance(geom,x,y);
-                    if (!tr.backward(p2p.x_hit,p2p.y_hit,z))
+                    if (!tr.backward(p2p.x, p2p.y, z))
                     {
                         /* LCOV_EXCL_START */
                         throw std::runtime_error("could not reproject lon/lat to mercator");
@@ -1724,8 +1553,8 @@ std::vector<query_result> VectorTile::_query(VectorTile* d, double lon, double l
                     if (p2p.distance >= 0 && p2p.distance <= tolerance)
                     {
                         query_result res;
-                        res.x_hit = p2p.x_hit;
-                        res.y_hit = p2p.y_hit;
+                        res.x_hit = p2p.x;
+                        res.y_hit = p2p.y;
                         res.distance = p2p.distance;
                         res.layer = layer_name;
                         res.feature = feature;
@@ -1754,7 +1583,7 @@ std::vector<query_result> VectorTile::_query(VectorTile* d, double lon, double l
                 {
                     auto const& geom = feature->get_geometry();
                     auto p2p = path_to_point_distance(geom,x,y);
-                    if (!tr.backward(p2p.x_hit,p2p.y_hit,z))
+                    if (!tr.backward(p2p.x, p2p.y ,z))
                     {
                         /* LCOV_EXCL_START */
                         throw std::runtime_error("could not reproject lon/lat to mercator");
@@ -1763,8 +1592,8 @@ std::vector<query_result> VectorTile::_query(VectorTile* d, double lon, double l
                     if (p2p.distance >= 0 && p2p.distance <= tolerance)
                     {
                         query_result res;
-                        res.x_hit = p2p.x_hit;
-                        res.y_hit = p2p.y_hit;
+                        res.x_hit = p2p.x;
+                        res.y_hit = p2p.y;
                         res.distance = p2p.distance;
                         res.layer = ds->get_name();
                         res.feature = feature;
@@ -1815,7 +1644,7 @@ typedef struct
 } vector_tile_queryMany_baton_t;
 
 /**
- * Query a vector tile by multiple sets of latitude/longitude pairs. 
+ * Query a vector tile by multiple sets of latitude/longitude pairs.
  * Just like <mapnik.VectorTile.query> but with more points to search.
  *
  * @memberof VectorTile
@@ -1823,22 +1652,22 @@ typedef struct
  * @name queryMany
  * @param {array<number>} array - `longitude` and `latitude` array pairs [[lon1,lat1], [lon2,lat2]]
  * @param {Object} options
- * @param {number} [options.tolerance=0] include features a specific distance from the 
+ * @param {number} [options.tolerance=0] include features a specific distance from the
  * lon/lat query in the response. Read more about tolerance at {@link VectorTile#query}.
  * @param {string} options.layer - layer name
  * @param {Array<string>} [options.fields] - array of field names
  * @param {Function} [callback] - `function(err, results)`
- * @returns {Object} The response has contains two main objects: `hits` and `features`. 
- * The number of hits returned will correspond to the number of lon/lats queried and will 
- * be returned in the order of the query. Each hit returns 1) a `distance` and a 2) `feature_id`. 
- * The `distance` is number of meters the queried lon/lat is from the object in the vector tile. 
- * The `feature_id` is the corresponding object in features object. 
- * 
+ * @returns {Object} The response has contains two main objects: `hits` and `features`.
+ * The number of hits returned will correspond to the number of lon/lats queried and will
+ * be returned in the order of the query. Each hit returns 1) a `distance` and a 2) `feature_id`.
+ * The `distance` is number of meters the queried lon/lat is from the object in the vector tile.
+ * The `feature_id` is the corresponding object in features object.
+ *
  * The values for the query is contained in the features object. Use attributes() to extract a value.
  * @example
  * vt.queryMany([[139.61, 37.17], [140.64, 38.1]], {tolerance: 0}, function(err, results) {
  *   if (err) throw err;
- *   console.log(results.hits); // 
+ *   console.log(results.hits); //
  *   console.log(results.features); // array of feature objects
  *   if (features.length) {
  *     console.log(results.features[0].layer); // 'layer-name'
@@ -1981,11 +1810,11 @@ NAN_METHOD(VectorTile::queryMany)
     }
 }
 
-void VectorTile::_queryMany(queryMany_result & result, 
-                            VectorTile* d, 
-                            std::vector<query_lonlat> const& query, 
-                            double tolerance, 
-                            std::string const& layer_name, 
+void VectorTile::_queryMany(queryMany_result & result,
+                            VectorTile* d,
+                            std::vector<query_lonlat> const& query,
+                            double tolerance,
+                            std::string const& layer_name,
                             std::vector<std::string> const& fields)
 {
     protozero::pbf_reader layer_msg;
@@ -1993,7 +1822,7 @@ void VectorTile::_queryMany(queryMany_result & result,
     {
         throw std::runtime_error("Could not find layer in vector tile");
     }
-    
+
     std::map<unsigned,query_result> features;
     std::map<unsigned,std::vector<query_hit> > hits;
 
@@ -2255,7 +2084,7 @@ struct geometry_array_visitor
         // therefore no known tests reach this point
         // LCOV_EXCL_START
         Nan::EscapableHandleScope scope;
-        return scope.Escape(Nan::New<v8::Array>());   
+        return scope.Escape(Nan::New<v8::Array>());
         // LCOV_EXCL_STOP
     }
 
@@ -2354,23 +2183,15 @@ struct geometry_array_visitor
     }
 
     template <typename T>
-    v8::Local<v8::Array> operator() (mapnik::geometry::polygon<T> const & geom)
+    v8::Local<v8::Array> operator() (mapnik::geometry::polygon<T> const & poly)
     {
         Nan::EscapableHandleScope scope;
-        if (geom.exterior_ring.empty())
-        {
-            // Removed as it should be a bug if a vector tile has reached this point
-            // therefore no known tests reach this point
-            // LCOV_EXCL_START
-            return scope.Escape(Nan::New<v8::Array>());
-            // LCOV_EXCL_STOP
-        }
-        v8::Local<v8::Array> arr = Nan::New<v8::Array>(1 + geom.interior_rings.size());
-        std::uint32_t c = 0;
-        arr->Set(c++, (*this)(geom.exterior_ring));
-        for (auto const & pt : geom.interior_rings)
+        v8::Local<v8::Array> arr = Nan::New<v8::Array>(poly.size());
+        std::uint32_t index = 0;
+
+        for (auto const & ring : poly)
         {
-            arr->Set(c++, (*this)(pt));
+            arr->Set(index++, (*this)(ring));
         }
         return scope.Escape(arr);
     }
@@ -2424,7 +2245,7 @@ struct geometry_array_visitor
         {
             arr->Set(c++, (*this)(pt));
         }
-        return scope.Escape(arr);   
+        return scope.Escape(arr);
         // LCOV_EXCL_STOP
     }
 };
@@ -2445,7 +2266,7 @@ struct json_value_visitor
                        std::string const& name)
         : att_obj_(att_obj),
           name_(name) {}
-    
+
     void operator() (std::string const& val)
     {
         att_obj_->Set(Nan::New(name_).ToLocalChecked(), Nan::New(val).ToLocalChecked());
@@ -2495,10 +2316,10 @@ struct json_value_visitor
  * var buffer = fs.readFileSync('./path/to/data.mvt');
  * vt.setData(buffer);
  * var json = vectorTile.toJSON();
- * console.log(json); 
- * // { 
+ * console.log(json);
+ * // {
  * //   name: 'layer-name',
- * //   extent: 4096, 
+ * //   extent: 4096,
  * //   version: 2,
  * //   features: [ ... ] // array of objects
  * // }
@@ -2557,7 +2378,7 @@ NAN_METHOD(VectorTile::toJSON)
                         break;
                     case mapnik::vector_tile_impl::Layer_Encoding::VALUES:
                         val_msg = layer_msg.get_message();
-                        while (val_msg.next()) 
+                        while (val_msg.next())
                         {
                             switch(val_msg.tag())
                             {
@@ -2623,7 +2444,7 @@ NAN_METHOD(VectorTile::toJSON)
                 {
                     switch (feature_msg.tag())
                     {
-                        case mapnik::vector_tile_impl::Feature_Encoding::ID: 
+                        case mapnik::vector_tile_impl::Feature_Encoding::ID:
                             feature_obj->Set(Nan::New("id").ToLocalChecked(),Nan::New<v8::Number>(feature_msg.get_uint64()));
                             break;
                         case mapnik::vector_tile_impl::Feature_Encoding::TAGS:
@@ -2651,7 +2472,7 @@ NAN_METHOD(VectorTile::toJSON)
                             feature_msg.skip();
                             break;
                             // LCOV_EXCL_STOP
-                    }   
+                    }
                 }
                 v8::Local<v8::Object> att_obj = Nan::New<v8::Object>();
                 if (has_tags)
@@ -2710,7 +2531,7 @@ NAN_METHOD(VectorTile::toJSON)
         info.GetReturnValue().Set(arr);
         return;
     }
-    catch (std::exception const& ex) 
+    catch (std::exception const& ex)
     {
         // LCOV_EXCL_START
         Nan::ThrowError(ex.what());
@@ -2779,10 +2600,10 @@ bool layer_to_geojson(protozero::pbf_reader const& layer,
  * @memberof VectorTile
  * @instance
  * @name toGeoJSONSync
- * @param {string | number} [layer=__all__] Can be a zero-index integer representing 
- * a layer or the string keywords `__array__` or `__all__` to get all layers in the form 
- * of an array of GeoJSON `FeatureCollection`s or in the form of a single GeoJSON 
- * `FeatureCollection` with all layers smooshed inside 
+ * @param {string | number} [layer=__all__] Can be a zero-index integer representing
+ * a layer or the string keywords `__array__` or `__all__` to get all layers in the form
+ * of an array of GeoJSON `FeatureCollection`s or in the form of a single GeoJSON
+ * `FeatureCollection` with all layers smooshed inside
  * @returns {string} stringified GeoJSON of all the features in this tile.
  * @example
  * var geojson = vectorTile.toGeoJSONSync();
@@ -2806,7 +2627,7 @@ void write_geojson_array(std::string & result,
         {
             first = false;
         }
-        else 
+        else
         {
             result += ",";
         }
@@ -2856,7 +2677,7 @@ void write_geojson_all(std::string & result,
             {
                 first = false;
             }
-            else 
+            else
             {
                 result += ",";
             }
@@ -2877,8 +2698,8 @@ bool write_geojson_layer_index(std::string & result,
         std::string layer_name = v->get_tile()->get_layers()[layer_idx];
         result += "{\"type\":\"FeatureCollection\",";
         result += "\"name\":\"" + layer_name + "\",\"features\":[";
-        layer_to_geojson(layer_msg, 
-                         result, 
+        layer_to_geojson(layer_msg,
+                         result,
                          v->get_tile()->x(),
                          v->get_tile()->y(),
                          v->get_tile()->z());
@@ -2899,8 +2720,8 @@ bool write_geojson_layer_name(std::string & result,
     {
         result += "{\"type\":\"FeatureCollection\",";
         result += "\"name\":\"" + name + "\",\"features\":[";
-        layer_to_geojson(layer_msg, 
-                         result, 
+        layer_to_geojson(layer_msg,
+                         result,
                          v->get_tile()->x(),
                          v->get_tile()->y(),
                          v->get_tile()->z());
@@ -2913,7 +2734,7 @@ bool write_geojson_layer_name(std::string & result,
 v8::Local<v8::Value> VectorTile::_toGeoJSONSync(Nan::NAN_METHOD_ARGS_TYPE info)
 {
     Nan::EscapableHandleScope scope;
-    if (info.Length() < 1) 
+    if (info.Length() < 1)
     {
         Nan::ThrowError("first argument must be either a layer name (string) or layer index (integer)");
         return scope.Escape(Nan::Undefined());
@@ -3008,11 +2829,11 @@ struct to_geojson_baton
  * @memberof VectorTile
  * @instance
  * @name toGeoJSON
- * @param {string | number} [layer=__all__] Can be a zero-index integer representing 
- * a layer or the string keywords `__array__` or `__all__` to get all layers in the form 
- * of an array of GeoJSON `FeatureCollection`s or in the form of a single GeoJSON 
- * `FeatureCollection` with all layers smooshed inside  
- * @param {Function} callback - `function(err, geojson)`: a stringified 
+ * @param {string | number} [layer=__all__] Can be a zero-index integer representing
+ * a layer or the string keywords `__array__` or `__all__` to get all layers in the form
+ * of an array of GeoJSON `FeatureCollection`s or in the form of a single GeoJSON
+ * `FeatureCollection` with all layers smooshed inside
+ * @param {Function} callback - `function(err, geojson)`: a stringified
  * GeoJSON of all the features in this tile
  * @example
  * vectorTile.toGeoJSON(function(err, geojson) {
@@ -3158,22 +2979,22 @@ void VectorTile::after_to_geojson(uv_work_t* req)
  * @param {string} geojson as a string
  * @param {string} name of the layer to be added
  * @param {Object} [options]
- * @param {number} [options.area_threshold=0.1] used to discard small polygons. 
- * If a value is greater than `0` it will trigger polygons with an area smaller 
+ * @param {number} [options.area_threshold=0.1] used to discard small polygons.
+ * If a value is greater than `0` it will trigger polygons with an area smaller
  * than the value to be discarded. Measured in grid integers, not spherical mercator
  * coordinates.
- * @param {number} [options.simplify_distance=0.0] Simplification works to generalize 
- * geometries before encoding into vector tiles.simplification distance The 
+ * @param {number} [options.simplify_distance=0.0] Simplification works to generalize
+ * geometries before encoding into vector tiles.simplification distance The
  * `simplify_distance` value works in integer space over a 4096 pixel grid and uses
  * the [Douglas-Peucker algorithm](https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm).
  * @param {boolean} [options.strictly_simple=true] ensure all geometry is valid according to
  * OGC Simple definition
  * @param {boolean} [options.multi_polygon_union=false] union all multipolygons
- * @param {Object<mapnik.polygonFillType>} [options.fill_type=mapnik.polygonFillType.positive] 
- * the fill type used in determining what are holes and what are outer rings. See the 
+ * @param {Object<mapnik.polygonFillType>} [options.fill_type=mapnik.polygonFillType.positive]
+ * the fill type used in determining what are holes and what are outer rings. See the
  * [Clipper documentation](http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Types/PolyFillType.htm)
  * to learn more about fill types.
- * @param {boolean} [options.process_all_rings=false] if `true`, don't assume winding order and ring order of 
+ * @param {boolean} [options.process_all_rings=false] if `true`, don't assume winding order and ring order of
  * polygons are correct according to the [`2.0` Mapbox Vector Tile specification](https://github.com/mapbox/vector-tile-spec)
  * @example
  * var geojson = { ... };
@@ -3214,7 +3035,7 @@ NAN_METHOD(VectorTile::addGeoJSON)
         }
 
         options = info[2]->ToObject();
-        if (options->Has(Nan::New("area_threshold").ToLocalChecked())) 
+        if (options->Has(Nan::New("area_threshold").ToLocalChecked()))
         {
             v8::Local<v8::Value> param_val = options->Get(Nan::New("area_threshold").ToLocalChecked());
             if (!param_val->IsNumber())
@@ -3229,7 +3050,7 @@ NAN_METHOD(VectorTile::addGeoJSON)
                 return;
             }
         }
-        if (options->Has(Nan::New("strictly_simple").ToLocalChecked())) 
+        if (options->Has(Nan::New("strictly_simple").ToLocalChecked()))
         {
             v8::Local<v8::Value> param_val = options->Get(Nan::New("strictly_simple").ToLocalChecked());
             if (!param_val->IsBoolean())
@@ -3249,7 +3070,7 @@ NAN_METHOD(VectorTile::addGeoJSON)
             }
             multi_polygon_union = mpu->BooleanValue();
         }
-        if (options->Has(Nan::New("fill_type").ToLocalChecked())) 
+        if (options->Has(Nan::New("fill_type").ToLocalChecked()))
         {
             v8::Local<v8::Value> ft = options->Get(Nan::New("fill_type").ToLocalChecked());
             if (!ft->IsNumber())
@@ -3258,13 +3079,13 @@ NAN_METHOD(VectorTile::addGeoJSON)
                 return;
             }
             fill_type = static_cast<mapnik::vector_tile_impl::polygon_fill_type>(ft->IntegerValue());
-            if (fill_type < 0 || fill_type >= mapnik::vector_tile_impl::polygon_fill_type_max)
+            if (fill_type >= mapnik::vector_tile_impl::polygon_fill_type_max)
             {
                 Nan::ThrowTypeError("optional arg 'fill_type' out of possible range");
                 return;
             }
         }
-        if (options->Has(Nan::New("simplify_distance").ToLocalChecked())) 
+        if (options->Has(Nan::New("simplify_distance").ToLocalChecked()))
         {
             v8::Local<v8::Value> param_val = options->Get(Nan::New("simplify_distance").ToLocalChecked());
             if (!param_val->IsNumber())
@@ -3279,7 +3100,7 @@ NAN_METHOD(VectorTile::addGeoJSON)
                 return;
             }
         }
-        if (options->Has(Nan::New("process_all_rings").ToLocalChecked())) 
+        if (options->Has(Nan::New("process_all_rings").ToLocalChecked()))
         {
             v8::Local<v8::Value> param_val = options->Get(Nan::New("process_all_rings").ToLocalChecked());
             if (!param_val->IsBoolean())
@@ -3301,7 +3122,7 @@ NAN_METHOD(VectorTile::addGeoJSON)
         mapnik::layer lyr(geojson_name,"+init=epsg:4326");
         lyr.set_datasource(mapnik::datasource_cache::instance().create(p));
         map.add_layer(lyr);
-        
+
         mapnik::vector_tile_impl::processor ren(map);
         ren.set_area_threshold(area_threshold);
         ren.set_strictly_simple(strictly_simple);
@@ -3328,7 +3149,7 @@ NAN_METHOD(VectorTile::addGeoJSON)
  * @param {mapnik.Image} image
  * @param {string} name of the layer to be added
  * @param {Object} options
- * @param {string} [options.image_scaling=bilinear] can be any 
+ * @param {string} [options.image_scaling=bilinear] can be any
  * of the <mapnik.imageScaling> methods
  * @param {string} [options.image_format=webp] or `jpeg`, `png`, `tiff`
  * @example
@@ -3362,8 +3183,8 @@ v8::Local<v8::Value> VectorTile::_addImageSync(Nan::NAN_METHOD_ARGS_TYPE info)
     }
     std::string layer_name = TOSTR(info[1]);
     v8::Local<v8::Object> obj = info[0]->ToObject();
-    if (obj->IsNull() || 
-        obj->IsUndefined() || 
+    if (obj->IsNull() ||
+        obj->IsUndefined() ||
         !Nan::New(Image::constructor)->HasInstance(obj))
     {
         Nan::ThrowError("first argument must be an Image object");
@@ -3378,28 +3199,28 @@ v8::Local<v8::Value> VectorTile::_addImageSync(Nan::NAN_METHOD_ARGS_TYPE info)
 
     std::string image_format = "webp";
     mapnik::scaling_method_e scaling_method = mapnik::SCALING_BILINEAR;
-    
-    if (info.Length() > 2) 
+
+    if (info.Length() > 2)
     {
         // options object
-        if (!info[2]->IsObject()) 
+        if (!info[2]->IsObject())
         {
             Nan::ThrowError("optional third argument must be an options object");
             return scope.Escape(Nan::Undefined());
         }
 
         v8::Local<v8::Object> options = info[2]->ToObject();
-        if (options->Has(Nan::New("image_scaling").ToLocalChecked())) 
+        if (options->Has(Nan::New("image_scaling").ToLocalChecked()))
         {
             v8::Local<v8::Value> param_val = options->Get(Nan::New("image_scaling").ToLocalChecked());
-            if (!param_val->IsString()) 
+            if (!param_val->IsString())
             {
                 Nan::ThrowTypeError("option 'image_scaling' must be a string");
                 return scope.Escape(Nan::Undefined());
             }
             std::string image_scaling = TOSTR(param_val);
             boost::optional<mapnik::scaling_method_e> method = mapnik::scaling_method_from_string(image_scaling);
-            if (!method) 
+            if (!method)
             {
                 Nan::ThrowTypeError("option 'image_scaling' must be a string and a valid scaling method (e.g 'bilinear')");
                 return scope.Escape(Nan::Undefined());
@@ -3407,10 +3228,10 @@ v8::Local<v8::Value> VectorTile::_addImageSync(Nan::NAN_METHOD_ARGS_TYPE info)
             scaling_method = *method;
         }
 
-        if (options->Has(Nan::New("image_format").ToLocalChecked())) 
+        if (options->Has(Nan::New("image_format").ToLocalChecked()))
         {
             v8::Local<v8::Value> param_val = options->Get(Nan::New("image_format").ToLocalChecked());
-            if (!param_val->IsString()) 
+            if (!param_val->IsString())
             {
                 Nan::ThrowTypeError("option 'image_format' must be a string");
                 return scope.Escape(Nan::Undefined());
@@ -3434,7 +3255,7 @@ v8::Local<v8::Value> VectorTile::_addImageSync(Nan::NAN_METHOD_ARGS_TYPE info)
         mapnik::layer lyr(layer_name,"+init=epsg:3857");
         lyr.set_datasource(ds);
         map.add_layer(lyr);
-        
+
         mapnik::vector_tile_impl::processor ren(map);
         ren.set_scaling_method(scaling_method);
         ren.set_image_format(image_format);
@@ -3471,7 +3292,7 @@ typedef struct
  * @param {mapnik.Image} image
  * @param {string} name of the layer to be added
  * @param {Object} [options]
- * @param {string} [options.image_scaling=bilinear] can be any 
+ * @param {string} [options.image_scaling=bilinear] can be any
  * of the <mapnik.imageScaling> methods
  * @param {string} [options.image_format=webp] other options include `jpeg`, `png`, `tiff`
  * @example
@@ -3484,7 +3305,7 @@ typedef struct
  *   image_scaling: 'gaussian'
  * }, function(err) {
  *   if (err) throw err;
- *   // your custom code using `vt`  
+ *   // your custom code using `vt`
  * });
  */
 NAN_METHOD(VectorTile::addImage)
@@ -3514,8 +3335,8 @@ NAN_METHOD(VectorTile::addImage)
     }
     std::string layer_name = TOSTR(info[1]);
     v8::Local<v8::Object> obj = info[0]->ToObject();
-    if (obj->IsNull() || 
-        obj->IsUndefined() || 
+    if (obj->IsNull() ||
+        obj->IsUndefined() ||
         !Nan::New(Image::constructor)->HasInstance(obj))
     {
         Nan::ThrowError("first argument must be an Image object");
@@ -3530,28 +3351,28 @@ NAN_METHOD(VectorTile::addImage)
 
     std::string image_format = "webp";
     mapnik::scaling_method_e scaling_method = mapnik::SCALING_BILINEAR;
-    
-    if (info.Length() > 3) 
+
+    if (info.Length() > 3)
     {
         // options object
-        if (!info[2]->IsObject()) 
+        if (!info[2]->IsObject())
         {
             Nan::ThrowError("optional third argument must be an options object");
             return;
         }
 
         v8::Local<v8::Object> options = info[2]->ToObject();
-        if (options->Has(Nan::New("image_scaling").ToLocalChecked())) 
+        if (options->Has(Nan::New("image_scaling").ToLocalChecked()))
         {
             v8::Local<v8::Value> param_val = options->Get(Nan::New("image_scaling").ToLocalChecked());
-            if (!param_val->IsString()) 
+            if (!param_val->IsString())
             {
                 Nan::ThrowTypeError("option 'image_scaling' must be a string");
                 return;
             }
             std::string image_scaling = TOSTR(param_val);
             boost::optional<mapnik::scaling_method_e> method = mapnik::scaling_method_from_string(image_scaling);
-            if (!method) 
+            if (!method)
             {
                 Nan::ThrowTypeError("option 'image_scaling' must be a string and a valid scaling method (e.g 'bilinear')");
                 return;
@@ -3559,10 +3380,10 @@ NAN_METHOD(VectorTile::addImage)
             scaling_method = *method;
         }
 
-        if (options->Has(Nan::New("image_format").ToLocalChecked())) 
+        if (options->Has(Nan::New("image_format").ToLocalChecked()))
         {
             v8::Local<v8::Value> param_val = options->Get(Nan::New("image_format").ToLocalChecked());
-            if (!param_val->IsString()) 
+            if (!param_val->IsString())
             {
                 Nan::ThrowTypeError("option 'image_format' must be a string");
                 return;
@@ -3605,7 +3426,7 @@ void VectorTile::EIO_AddImage(uv_work_t* req)
         mapnik::layer lyr(closure->layer_name,"+init=epsg:3857");
         lyr.set_datasource(ds);
         map.add_layer(lyr);
-        
+
         mapnik::vector_tile_impl::processor ren(map);
         ren.set_scaling_method(closure->scaling_method);
         ren.set_image_format(closure->image_format);
@@ -3688,7 +3509,7 @@ v8::Local<v8::Value> VectorTile::_addImageBufferSync(Nan::NAN_METHOD_ARGS_TYPE i
     }
     try
     {
-        add_image_buffer_as_tile_layer(*d->get_tile(), layer_name, node::Buffer::Data(obj), buffer_size); 
+        add_image_buffer_as_tile_layer(*d->get_tile(), layer_name, node::Buffer::Data(obj), buffer_size);
     }
     catch (std::exception const& ex)
     {
@@ -3791,7 +3612,7 @@ void VectorTile::EIO_AddImageBuffer(uv_work_t* req)
 
     try
     {
-        add_image_buffer_as_tile_layer(*closure->d->get_tile(), closure->layer_name, closure->data, closure->dataLength); 
+        add_image_buffer_as_tile_layer(*closure->d->get_tile(), closure->layer_name, closure->data, closure->dataLength);
     }
     catch (std::exception const& ex)
     {
@@ -4258,7 +4079,7 @@ NAN_METHOD(VectorTile::setData)
 void VectorTile::EIO_SetData(uv_work_t* req)
 {
     vector_tile_setdata_baton_t *closure = static_cast<vector_tile_setdata_baton_t *>(req->data);
-    
+
     if (closure->dataLength <= 0)
     {
         closure->error = true;
@@ -4768,19 +4589,19 @@ struct baton_guard
  * @param {number} [options.buffer_size] the size of the tile's buffer
  * @param {number} [options.scale] floating point scale factor size to used
  * for rendering
- * @param {number} [options.scale_denominator] An floating point `scale_denominator` 
- * to be used by Mapnik when matching zoom filters. If provided this overrides the 
- * auto-calculated scale_denominator that is based on the map dimensions and bbox. 
+ * @param {number} [options.scale_denominator] An floating point `scale_denominator`
+ * to be used by Mapnik when matching zoom filters. If provided this overrides the
+ * auto-calculated scale_denominator that is based on the map dimensions and bbox.
  * Do not set this option unless you know what it means.
- * @param {Object} [options.variables] Mapnik 3.x ONLY: A javascript object 
- * containing key value pairs that should be passed into Mapnik as variables 
- * for rendering and for datasource queries. For example if you passed 
+ * @param {Object} [options.variables] Mapnik 3.x ONLY: A javascript object
+ * containing key value pairs that should be passed into Mapnik as variables
+ * for rendering and for datasource queries. For example if you passed
  * `vtile.render(map,image,{ variables : {zoom:1} },cb)` then the `@zoom`
  * variable would be usable in Mapnik symbolizers like `line-width:"@zoom"`
- * and as a token in Mapnik postgis sql sub-selects like 
+ * and as a token in Mapnik postgis sql sub-selects like
  * `(select * from table where some_field > @zoom)` as tmp
  * @param {string} [options.renderer] must be `cairo` or `svg`
- * @param {string|number} [options.layer] option required for grid rendering 
+ * @param {string|number} [options.layer] option required for grid rendering
  * and must be either a layer name (string) or layer index (integer)
  * @param {Array<string>} [options.fields] must be an array of strings
  * @param {Function} callback
@@ -4789,7 +4610,7 @@ struct baton_guard
  * var tileSize = vt.tileSize;
  * var map = new mapnik.Map(tileSize, tileSize);
  * vt.render(map, new mapnik.Image(256,256), function(err, image) {
- *   if (err) throw err;   
+ *   if (err) throw err;
  *   // save the rendered image to an existing image file somewhere
  *   // see mapnik.Image for available methods
  *   image.save('./path/to/image/file.png', 'png32');
@@ -5002,7 +4823,7 @@ NAN_METHOD(VectorTile::render)
             Nan::ThrowTypeError("'layer' option required for grid rendering and must be either a layer name(string) or layer index (integer)");
             return;
         }
-        else 
+        else
         {
             std::vector<mapnik::layer> const& layers = m->get()->layers();
             v8::Local<v8::Value> layer_id = options->Get(Nan::New("layer").ToLocalChecked());
@@ -5149,8 +4970,8 @@ void VectorTile::EIO_RenderTile(uv_work_t* req)
         if (closure->zxy_override)
         {
             merc.xyz(closure->x,closure->y,closure->z,minx,miny,maxx,maxy);
-        } 
-        else 
+        }
+        else
         {
             merc.xyz(closure->d->get_tile()->x(),
                      closure->d->get_tile()->y(),
@@ -5377,7 +5198,7 @@ typedef struct
  * @example
  * vt.clear(function(err) {
  *   if (err) throw err;
- *   console.log(vt.getData().length); // 0   
+ *   console.log(vt.getData().length); // 0
  * });
  */
 NAN_METHOD(VectorTile::clear)
@@ -5524,10 +5345,10 @@ struct visitor_geom_valid
           feature(feature_),
           layer_name(layer_name_),
           split_multi_features(split_multi_features_) {}
-    
+
     void operator() (mapnik::geometry::geometry_empty const&) {}
-          
-    template <typename T> 
+
+    template <typename T>
     void operator() (mapnik::geometry::point<T> const& geom)
     {
         std::string message;
@@ -5556,8 +5377,8 @@ struct visitor_geom_valid
             }
         }
     }
-    
-    template <typename T> 
+
+    template <typename T>
     void operator() (mapnik::geometry::multi_point<T> const& geom)
     {
         std::string message;
@@ -5586,8 +5407,8 @@ struct visitor_geom_valid
             }
         }
     }
-    
-    template <typename T> 
+
+    template <typename T>
     void operator() (mapnik::geometry::line_string<T> const& geom)
     {
         std::string message;
@@ -5616,8 +5437,8 @@ struct visitor_geom_valid
             }
         }
     }
-    
-    template <typename T> 
+
+    template <typename T>
     void operator() (mapnik::geometry::multi_line_string<T> const& geom)
     {
         if (split_multi_features)
@@ -5674,8 +5495,8 @@ struct visitor_geom_valid
             }
         }
     }
-    
-    template <typename T> 
+
+    template <typename T>
     void operator() (mapnik::geometry::polygon<T> const& geom)
     {
         std::string message;
@@ -5704,8 +5525,8 @@ struct visitor_geom_valid
             }
         }
     }
-    
-    template <typename T> 
+
+    template <typename T>
     void operator() (mapnik::geometry::multi_polygon<T> const& geom)
     {
         if (split_multi_features)
@@ -5762,8 +5583,8 @@ struct visitor_geom_valid
             }
         }
     }
-    
-    template <typename T> 
+
+    template <typename T>
     void operator() (mapnik::geometry::geometry_collection<T> const& geom)
     {
         // This should never be able to be reached.
@@ -5810,13 +5631,13 @@ void layer_not_valid(protozero::pbf_reader & layer_msg,
                     mapnik::proj_transform prj_trans(merc,wgs84);
                     unsigned int n_err = 0;
                     mapnik::util::apply_visitor(
-                            visitor_geom_valid(errors, feature, ds.get_name(), split_multi_features), 
+                            visitor_geom_valid(errors, feature, ds.get_name(), split_multi_features),
                             mapnik::geometry::reproject_copy(feature->get_geometry(), prj_trans, n_err));
                 }
                 else
                 {
                     mapnik::util::apply_visitor(
-                            visitor_geom_valid(errors, feature, ds.get_name(), split_multi_features), 
+                            visitor_geom_valid(errors, feature, ds.get_name(), split_multi_features),
                             feature->get_geometry());
                 }
             }
@@ -5856,7 +5677,7 @@ void layer_not_valid(protozero::pbf_reader & layer_msg,
             {
                 switch (feature_msg.tag())
                 {
-                    case mapnik::vector_tile_impl::Feature_Encoding::ID: 
+                    case mapnik::vector_tile_impl::Feature_Encoding::ID:
                         feature_id = feature_msg.get_uint64();
                         break;
                     case mapnik::vector_tile_impl::Feature_Encoding::TYPE:
@@ -5870,7 +5691,7 @@ void layer_not_valid(protozero::pbf_reader & layer_msg,
                     default:
                         feature_msg.skip();
                         break;
-                }   
+                }
             }
             if (has_geom && has_geom_type)
             {
@@ -5880,7 +5701,7 @@ void layer_not_valid(protozero::pbf_reader & layer_msg,
                 mapnik::vector_tile_impl::GeometryPBF geoms(geom_itr);
                 feature->set_geometry(mapnik::vector_tile_impl::decode_geometry<double>(geoms, geom_type_enum, version, 0.0, 0.0, 1.0, 1.0));
                 mapnik::util::apply_visitor(
-                        visitor_geom_valid(errors, feature, layer_name, split_multi_features), 
+                        visitor_geom_valid(errors, feature, layer_name, split_multi_features),
                         feature->get_geometry());
             }
         }
@@ -6209,7 +6030,7 @@ void VectorTile::EIO_AfterReportGeometrySimplicity(uv_work_t* req)
  * @example
  * vectorTile.reportGeometryValidity(function(err, valid) {
  *   console.log(valid); // array of invalid geometries and their layer info
- *   console.log(valid.length); // number    
+ *   console.log(valid.length); // number
  * });
  */
 NAN_METHOD(VectorTile::reportGeometryValidity)
@@ -6361,8 +6182,8 @@ NAN_SETTER(VectorTile::set_tile_x)
     if (!value->IsNumber())
     {
         Nan::ThrowError("Must provide a number");
-    } 
-    else 
+    }
+    else
     {
         int val = value->IntegerValue();
         if (val < 0)
@@ -6380,8 +6201,8 @@ NAN_SETTER(VectorTile::set_tile_y)
     if (!value->IsNumber())
     {
         Nan::ThrowError("Must provide a number");
-    } 
-    else 
+    }
+    else
     {
         int val = value->IntegerValue();
         if (val < 0)
@@ -6399,8 +6220,8 @@ NAN_SETTER(VectorTile::set_tile_z)
     if (!value->IsNumber())
     {
         Nan::ThrowError("Must provide a number");
-    } 
-    else 
+    }
+    else
     {
         int val = value->IntegerValue();
         if (val < 0)
@@ -6418,8 +6239,8 @@ NAN_SETTER(VectorTile::set_tile_size)
     if (!value->IsNumber())
     {
         Nan::ThrowError("Must provide a number");
-    } 
-    else 
+    }
+    else
     {
         int val = value->IntegerValue();
         if (val <= 0)
@@ -6437,8 +6258,8 @@ NAN_SETTER(VectorTile::set_buffer_size)
     if (!value->IsNumber())
     {
         Nan::ThrowError("Must provide a number");
-    } 
-    else 
+    }
+    else
     {
         int val = value->IntegerValue();
         if (static_cast<int>(d->tile_size()) + (2 * val) <= 0)
@@ -6454,7 +6275,7 @@ typedef struct {
     uv_work_t request;
     const char *data;
     size_t dataLength;
-    v8::Local<v8::Object> obj; 
+    v8::Local<v8::Object> obj;
     bool error;
     std::string error_str;
     Nan::Persistent<v8::Object> buffer;
@@ -6475,7 +6296,7 @@ typedef struct {
  * var buffer = fs.readFileSync('./path/to/tile.mvt');
  * var info = mapnik.VectorTile.info(buffer);
  * console.log(info);
- * // { layers: 
+ * // { layers:
  * //   [ { name: 'world',
  * //      features: 1,
  * //      point_features: 0,
@@ -6554,17 +6375,17 @@ NAN_METHOD(VectorTile::info)
                             layer_errors.insert(mapnik::vector_tile_impl::LAYER_HAS_UNSUPPORTED_VERSION);
                         }
                         protozero::pbf_reader layer_msg(layer_view);
-                        mapnik::vector_tile_impl::layer_is_valid(layer_msg, 
-                                                                 layer_errors, 
+                        mapnik::vector_tile_impl::layer_is_valid(layer_msg,
+                                                                 layer_errors,
                                                                  point_feature_count,
                                                                  line_feature_count,
                                                                  polygon_feature_count,
                                                                  unknown_feature_count,
                                                                  raster_feature_count);
-                        std::uint64_t feature_count = point_feature_count + 
-                                                      line_feature_count + 
-                                                      polygon_feature_count + 
-                                                      unknown_feature_count + 
+                        std::uint64_t feature_count = point_feature_count +
+                                                      line_feature_count +
+                                                      polygon_feature_count +
+                                                      unknown_feature_count +
                                                       raster_feature_count;
                         if (!layer_name.empty())
                         {
diff --git a/src/object_to_container.hpp b/src/object_to_container.hpp
index e7c11c5850..1cafd97ce4 100644
--- a/src/object_to_container.hpp
+++ b/src/object_to_container.hpp
@@ -4,7 +4,7 @@
 #include <mapnik/version.hpp>
 #include <mapnik/attribute.hpp>
 #include <mapnik/unicode.hpp>
-#include <mapnik/value_types.hpp>
+#include <mapnik/value/types.hpp>
 
 static inline void object_to_container(mapnik::attributes & cont, v8::Local<v8::Object> const& vars)
 {
diff --git a/src/utils.hpp b/src/utils.hpp
index 643679e780..3dfe52f60e 100644
--- a/src/utils.hpp
+++ b/src/utils.hpp
@@ -13,7 +13,7 @@
 
 // core types
 #include <mapnik/unicode.hpp>
-#include <mapnik/value_types.hpp>
+#include <mapnik/value/types.hpp>
 #include <mapnik/value.hpp>
 #include <mapnik/version.hpp>
 #include <mapnik/params.hpp>
diff --git a/test/data/images/san-marino.svg b/test/data/images/san-marino.svg
new file mode 100644
index 0000000000..6ba011664b
--- /dev/null
+++ b/test/data/images/san-marino.svg
@@ -0,0 +1,92 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="480" width="640" viewBox="0 0 640 480">
+  <g fill-rule="evenodd" stroke-width="1pt">
+    <path fill="#19b6ef" d="M0 240h640v240H0z"/>
+    <path fill="#fff" d="M0 0h640v240H0z"/>
+  </g>
+  <path d="M317.07 339.221c52.45-39.239 108.96-119.306 42.74-161.41-12.336-2.388-26.107-1.672-32.713 3.582-3.501-1.99-6.288-1.83-9.79 1.91-2.466-3.025-4.935-4.379-10.028-2.865-10.188-5.173-19.42-6.288-31.517-3.105-57.623 34.622-22.366 116.76 41.308 161.888z" fill-rule="evenodd" stroke="#7d6c00" stroke-width="2.3686254" fill="#fd0"/>
+  <g stroke="#3a9d4f">
+    <path stroke-linejoin="round" d="M414.08 250.106s5.903-7.939 6.106-7.939c5.904-3.46 6.515-7.938 6.515-7.938 5.903-1.833 4.07-6.718 4.477-7.328 2.852-3.053 1.833-6.108 1.426-7.126 0-.812 2.036-8.345-.814-9.362.135-8.008-4.818-7.261-8.754-2.036-4.207 1.221-5.157 4.682-3.664 8.55-5.497 0-5.7 7.939-4.071 12.416-7.328-.203-3.257 7.939-3.461 8.347-2.442 1.221 1.832 12.824 2.24 12.416zM367.857 318.3l3.664 2.239c.746 2.781 3.325 4.547 5.294 4.072.95 4.274 5.563 3.665 8.956 1.221 2.714 3.936 6.04 4.005 10.586 2.647 4.07 2.985 9.364 1.696 12.824-1.426 3.731 3.053 6.243.815 8.142-2.442 2.917.746 5.224.272 6.31-2.647 5.7-.474 2.85-5.835-1.83-8.142 3.73-3.258 7.87-9.975 2.035-10.993-1.833-1.356-5.292-1.084-7.94.205-.677-2.987-4.818-3.733-9.364-.408-1.56-3.325-6.989-1.764-9.568.611-3.256-2.85-7.124-2.85-12.824.406L367.857 318.3zM367.857 309.555c.678-3.731-1.9-10.517 2.035-11.195-.746-6.243.34-13.3 7.532-12.621 1.155-5.903.883-11.4 7.736-12.215 0 0 5.497-19.134 11.197-5.903 2.239 3.87 1.832 10.177-2.647 8.956.883 4.751-.678 8.889-5.903 8.754 2.307 3.324 1.56 7.872-1.018 9.976-6.311 4.748-12.62 9.5-18.932 14.248zM401.037 285.735l5.904-1.22c6.106-4.071 8.55-5.7 11.603-1.223 5.089-1.086 9.974-.543 9.771 3.461 6.04.407 5.971 4.274 5.294 7.328.949 5.36-1.358 12.35-5.09 3.867-11.807-7.192-18.525-6.243-37.253-2.035l9.771-10.178zM404.102 279.822c.205-.203 17.507-4.682 15.675-9.974 4.885-.815 5.904-5.7 6.108-5.7 10.177-3.256 9.566-9.161 9.566-9.161 2.918-3.122 8.075-6.243 6.922-11.807.34-6.31.882-10.177-7.532-6.106-6.311-.612-8.55 3.053-10.382 8.55-2.985-3.528-7.802 2.104-8.345 7.124 0 0-7.736 7.532-7.736 7.735s-6.514 12.01-6.514 12.01l2.238 7.33z" fill-rule="evenodd" stroke-width="2.3686254" fill="#4fd46b"/>
+    <path stroke-linejoin="round" d="M404.502 266.397c-4.14-3.122-6.446-6.853-5.7-10.586-2.713-3.664-4.614-5.903-2.035-9.16 0 0-2.036-7.329-2.036-7.532-5.292-2.035-3.053-6.513-1.629-8.142-2.51-3.461-2.578-7.126-.203-10.382-.068-6.515 4.546-4.071 8.345 0 0 0 6.311 4.479 1.63 8.55 4.681 1.629 6.107 5.698 3.46 7.327 4.071 1.833 4.681 5.497 2.442 7.94 4.14 3.326 2.579 7.465 3.868 11.196l-8.142 10.789z" fill-rule="evenodd" stroke-width="2.3686254" fill="#4fd46b"/>
+    <path stroke-linejoin="round" d="M411.831 236.064c-.203-.203-6.92-8.753-5.089-9.364-.406-2.647-2.441-5.497-1.22-8.142-3.325-3.325-3.394-7.26-.815-10.38-2.239-3.054-1.221-7.125 1.832-9.772-.95-5.022 2.579-6.175 5.7-7.126 2.307-8.075 6.038-5.971 8.142.203 3.19 2.782 2.715 6.99 1.63 10.18 3.799 2.578 1.492 5.766-.204 7.124l-9.976 27.277z" fill-rule="evenodd" stroke-width="2.3686254" fill="#4fd46b"/>
+    <path stroke-linejoin="round" d="M410.815 193.106l-5.7-5.7c1.473-3.02 2.659-8.344-1.627-10.789-2.364-5.757-14.182-12.892-16.083.815-1.799-4.136-5.563-8.21-8.345-3.46-6.175-5.292-9.5-3.665-6.311 3.053 0 0-2.848 4.478 4.682 7.939.611.61-2.442 8.142 6.515 8.345-1.696 2.579 1.086 6.175 4.682 5.903-2.579 3.19 1.764 6.583 4.477 5.294-1.154 3.528-1.086 5.225 3.868 5.7l5.497 6.31 4.477 6.106 3.868-29.516z" fill-rule="evenodd" stroke-width="2.3686254" fill="#4fd46b"/>
+    <path d="M414.28 246.508c.288-.288 10.938-24.757 12.378-32.243M415.43 203.05s1.726 19.864-3.167 34.545M382.615 182.895s21.879 21.015 23.893 29.651M397.873 180.596s1.439 17.274 7.484 34.259M436.45 243.343s-21.879 18.425-32.53 34.545M415.712 307.84s-28.788 4.03-41.454 4.318M406.218 320.215s-35.698-.864-38.29-3.454M388.361 273.859c0 .287-18.136 30.226-18.712 40.015" stroke-linecap="round" stroke-width="2.2203781" fill="none"/>
+  </g>
+  <path d="M316.87 333.441c-37.768-35.624-76.454-102.482-37.972-136.27 6.84 3.88 14.903.409 26.03-3.98 3.368 3.674 7.654 4.594 11.942 1.837 4.797 2.042 8.37.408 10.718-2.144 10.922 6.33 24.906 9.596 28.172 3.37 37.87 35.93-.511 103.095-38.89 137.187z" fill-rule="evenodd" stroke="#7d6c00" stroke-width="2.3686254" fill="#65c7ff"/>
+  <path d="M317.086 332.408c-16.219-16.307-31.017-34.385-42.347-57.66 1.939-1.632 2.84-2.138 3.861-4.997 5.818.818 8.88 1.021 16.536-.306 1.53 5.717 1.837 10.514 5.511 15.311l7.656-15.005c5.205 1.226 11.637 1.533 16.535 0 3.165 4.288 2.042 10.72 7.656 15.618 3.368-9.9 6.738-10.615 10.106-15.924 5.002 1.736 8.167 1.021 12.25-.307 2.143 2.45 1.072 2.41 4.975 6.007-10.233 20.32-24.265 40.728-42.739 57.263z" fill-rule="evenodd" fill="#8fc753"/>
+  <path d="M272.65 164.304a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0zM269.158 156.594a3.346 3.346 0 1 1-6.691 0 3.346 3.346 0 0 1 6.691 0zM265.085 149.465a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0zM262.321 142.482a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0zM262.757 134.918a3.346 3.346 0 1 1-6.691 0 3.346 3.346 0 0 1 6.691 0zM280.42 122.407a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0z" fill-rule="evenodd" stroke="#000" stroke-width="1.1110219000000001" fill="#fff"/>
+  <path d="M273.814 123.571a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0zM266.54 127.935a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0zM288.943 122.552a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0zM298.254 123.28a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0zM306.546 122.843a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0z" fill-rule="evenodd" stroke="#000" stroke-width="1.1110219000000001" fill="#fff"/>
+  <path d="M325.874 117.504a8.583 8.583 0 1 1-17.166 0 8.583 8.583 0 0 1 17.166 0z" fill-rule="evenodd" stroke="#7d6c00" stroke-width="1.110941" fill="#fd0"/>
+  <path d="M334.913 122.698a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0zM343.642 123.425a3.346 3.346 0 1 1-6.691 0 3.346 3.346 0 0 1 6.691 0zM352.08 122.988a3.346 3.346 0 1 1-6.693 0 3.346 3.346 0 0 1 6.692 0zM359.207 122.698a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0zM368.082 123.716a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0zM375.064 128.08a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0z" fill-rule="evenodd" stroke="#000" stroke-width="1.1110219000000001" fill="#fff"/>
+  <path d="M269.414 151.697c2.85 5.42 5.698 11.05 8.548 16.47h79.23l9.174-15.846c-5.352-3.683-9.035-6.533-16.68-4.795-4.31-6.185-9.035-7.366-16.054-6.671-2.086-2.154-3.963-3.475-7.508-3.961l-16.678.416c-4.38.416-7.716 3.753-7.924 3.753-7.09-.835-13.552-.627-15.22 6.254-6.463-1.599-11.05.14-16.888 4.38z" fill-rule="evenodd" stroke="#ac0000" stroke-width="2.3686254" fill="#e40000"/>
+  <path d="M377.974 135.354a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0zM378.556 143.21a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0zM376.082 150.484a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0zM373.027 156.448a3.346 3.346 0 1 1-6.692 0 3.346 3.346 0 0 1 6.692 0zM369.39 164.013a3.346 3.346 0 1 1-6.69 0 3.346 3.346 0 0 1 6.69 0z" fill-rule="evenodd" stroke="#000" stroke-width="1.1110219000000001" fill="#fff"/>
+  <path d="M322.566 154.424a4.946 4.946 0 1 1-9.893 0 4.946 4.946 0 0 1 9.893 0z" fill-rule="evenodd" stroke="#000" stroke-width="1.1105424000000002" fill="#fff"/>
+  <path d="M323.546 143.045a5.964 5.964 0 1 1-11.93 0 5.964 5.964 0 0 1 11.93 0z" fill-rule="evenodd" stroke="#000" stroke-width="1.11051072" fill="#fff"/>
+  <path d="M322.685 131.995a5.383 5.383 0 1 1-10.765 0 5.383 5.383 0 0 1 10.765 0z" fill-rule="evenodd" stroke="#000" stroke-width="1.10935854" fill="#fff"/>
+  <path d="M315.487 109.055c0-.926-.028-4.165.037-4.295l-3.572-.064.102-3.175 3.1-.037.037-2.775h4.395v2.544h3.47l-.072 3.378-3.6-.037-.03 4.526-3.867-.065z" fill-rule="evenodd" stroke="#7d6c00" stroke-width="1.1110219000000001" fill="#fd0"/>
+  <path d="M277.56 168.17c-7.092-12.023-17.51-28.367-11.053-35.444 8.955-10.143 29.953-.973 43.367-6.881.972 11.468-2.224 30.44 2.92 34.403l-4.796 4.17c-2.92-3.753-8.418-8.782-15.22.208-3.892-3.403-8.316-2.805-10.4 1.72-1.982.267-1.867 1.06-4.819 1.824zM357.68 167.754c7.09-12.023 17.51-28.367 11.051-35.444-8.955-10.143-29.952-.973-43.366-6.882-.973 11.469 2.223 30.441-2.92 34.404l4.795 4.17c4.614-6.489 10.373-6.699 15.22.207 3.893-3.403 7.925-2.936 10.4 1.721 1.983.267 1.868 1.06 4.82 1.824z" stroke="#fd0" stroke-width="3.3314" fill="none"/>
+  <path d="M277.343 177.132c28.495-2.918 54.904-1.877 79.23 0l3.127-8.967c-27.66-5.003-46.773-5.628-82.982-.624l.625 9.59z" fill-rule="evenodd" stroke="#7d6c00" stroke-width="2.3686254" fill="#fd0"/>
+  <path d="M314.121 329.377c.205-1.43.408-2.762.613-4.191 2.834.763 4.996.468 7.35-.402.815-1.225 1.633-2.45 2.45-3.676l-1.838-2.142c-1.615.348-2.941 1.85-3.98 3.158-1.628.077-3.064-.71-4.595-1.016l-1.53-6.43c-1.52-1.795-4.671-1.668-3.982 1.531l.307 2.45c.613 1.531.841 3.639 1.837 4.785v2.511c1.123 1.141 2.246 2.28 3.368 3.422zM315.337 311.087c-2.13 1.056-4.659-.78-7.349-1.837-2.45-.168-4.419 1.872-7.349 1.224.535-1.59 1.837-1.837 2.757-2.756-.673-4.131 1.53-5.512 2.144-5.512.61 0 3.061.613 3.061.613l2.45.306c1.43 2.654 3.433 5.02 4.286 7.962z" fill-rule="evenodd" fill="#c76e2e"/>
+  <path d="M300.779 366.089c7.066-11.472 56.259-34.508 102.422-84.251-46.99 45.243-76.357 56.35-114.812 83.974l12.39.277z" fill-rule="evenodd" stroke="#e9bf00" stroke-width="2.3686254" fill="#ffe100"/>
+  <path d="M368.406 313.186a3.582 3.582 0 1 1-7.163 0 3.582 3.582 0 0 1 7.163 0zM402.786 278.323a4.06 4.06 0 1 1-8.118 0 4.06 4.06 0 0 1 8.118 0zM414.252 248.713a3.582 3.582 0 1 1-7.163 0 3.582 3.582 0 0 1 7.163 0zM403.02 210.28a3.582 3.582 0 1 1-7.164 0 3.582 3.582 0 0 1 7.164 0z" fill-rule="evenodd" stroke="#68300e" stroke-width="1.1110219000000001" fill="#9d4916"/>
+  <path d="M279.125 269.595v-15.148l-1.54-1.283v-3.594l2.824-.257.513-16.945-1.797-1.028-.257-2.823s2.054.77 2.054.257.513-3.339.513-3.339-1.282-.256-1.282-.77 1.539-1.796 1.539-1.796-.77-.772-1.026-1.285-.77-2.823-.77-2.823l.77-2.825-.513-1.54-1.285-2.311 1.798-1.797s-.513-2.31-.513-2.824 1.282-2.567 1.539-2.825c.258-.256 2.312-3.08 2.312-3.08l4.364-1.027 5.135.77 2.824 1.798.513 4.62s-.513 2.824-.77 2.824-2.31 1.028-2.31 1.028-2.569.256-2.825 0 .77 3.081.77 3.081v3.08l-.256 3.851s0 1.798-.258 2.054c-.256.257-.77 1.028-.77 1.028l-.256 3.851 4.108 1.026-.257 2.312-2.825.257.515 15.66 4.108.77v4.366l-1.798 1.026-.513 15.66h-14.378zM341.522 269.861v-15.148l-1.54-1.282v-3.595l2.824-.256.513-16.945-1.797-1.028-.257-2.823s2.054.77 2.054.256.513-3.338.513-3.338-1.282-.257-1.282-.77 1.539-1.797 1.539-1.797-.77-.771-1.026-1.284-.77-2.823-.77-2.823l.77-2.826-.513-1.54-1.285-2.31 1.798-1.798s-.513-2.31-.513-2.823 1.282-2.567 1.539-2.825c.258-.257 2.312-3.08 2.312-3.08l4.364-1.028 5.135.771 2.824 1.798.513 4.62s-.513 2.824-.77 2.824-2.31 1.027-2.31 1.027-2.569.257-2.825 0 .771 3.082.771 3.082V218l-.256 3.85s0 1.798-.259 2.055c-.256.256-.77 1.027-.77 1.027l-.256 3.852 4.108 1.026-.257 2.312-2.825.256.515 15.661 4.108.77v4.365l-1.798 1.026-.513 15.661h-14.378zM309.94 270.378V255.23l-1.54-1.283v-3.594l2.825-.257.513-16.945-1.798-1.028-.256-2.823s2.054.77 2.054.256.513-3.338.513-3.338-1.283-.256-1.283-.77 1.54-1.797 1.54-1.797-.77-.77-1.027-1.284-.77-2.823-.77-2.823l.77-2.825-.513-1.54-1.284-2.311 1.797-1.798s-.513-2.31-.513-2.823 1.283-2.567 1.54-2.825c.257-.256 2.311-3.08 2.311-3.08l4.364-1.028 5.136.772 2.823 1.797.513 4.62s-.513 2.824-.77 2.824-2.31 1.028-2.31 1.028-2.568.256-2.825 0 .771 3.081.771 3.081v3.08l-.256 3.851s0 1.798-.258 2.054c-.257.257-.77 1.028-.77 1.028l-.256 3.85 4.107 1.027-.256 2.312-2.825.256.514 15.661 4.108.77v4.366l-1.797 1.026-.513 15.66H309.94z" fill-rule="evenodd" stroke="#a9a9a9" stroke-width="1.1110219000000001" fill="#fff"/>
+  <path fill-rule="evenodd" d="M282.923 269.495v-11.938h6.686v12.416l-6.686-.478zM314.438 270.444l.238-12.178h5.97v11.938l-6.208.24zM345.486 270.211l-.478-11.46 6.448-.24v11.94l-5.97-.24zM284.588 234.149h3.82v6.208h-3.82zM314.92 234.399h5.254v5.97h-5.253zM345.953 234.865h4.537v5.73h-4.537z"/>
+  <path d="M286.57 206.965c4.108 4.62 4.365 4.62 4.365 4.62M317.12 206.965c.769 1.539 2.053 4.877 3.594 5.133M349.984 207.73s1.284 3.595 3.081 4.108" stroke="#a8a8a8" stroke-width="1.1110219000000001" fill="none"/>
+  <path d="M282.206 194.022c12.012-3.883-2.806-11.648-5.267 0-3.886.628-4.389 3.511-12.789 2.259-20.313 33.102-5.267 86.518 54.169 141.816-106.457-90.594-63.194-157.604-33.714-155.077 16.034 1.096 7.945 21.096-2.399 11.002z" fill-rule="evenodd" fill="#b97700"/>
+  <path d="M285.554 177.049s9.781 2.633 9.781 6.77M295.332 176.299s6.771 3.008 8.275 5.642M348.751 177.432s-8.653 1.129-10.534 3.76M335.575 178.181s-4.888 4.138-4.514 5.265M334.46 196.237c-.753-.376-4.138-4.89-3.387-10.533M301.345 193.24s2.257-2.634 2.257-7.525M317.153 183.828l.376 10.909M326.93 193.24c0-.754 3.01-7.9-.376-11.286M306.242 180.447s-2.633 7.147-.75 13.165M325.431 186.843s-4.137 1.128-6.02 3.01M307.742 187.959c0-.375 4.514-1.128 6.018 1.506" stroke="#7d6c00" stroke-width="2.3686254" fill="none"/>
+  <path d="M300.63 301.86c.19.096 3.745-.674 3.745-2.403 1.826-1.152.48-4.419.48-4.419l-3.361-.673-4.613-5.187c-.223-1.6.322-3.104-.671-4.802-3.17.833-4.995 3.49-6.053 6.531.77.962.866 2.018 2.307 2.882 1.504.257 2.528-.64 3.938-.383.736 1.28.51 2.37.767 3.555 1.923 1.344 2.307 3.266 3.46 4.898zM296.498 279.672v-6.148l-4.419-.193c-.545.93-1.57 1.378-2.21 2.21l-3.074 1.538c1.281 1.537 2.85 2.402 3.843 3.17 2.242.673 4.1.673 5.86-.577zM282.656 288.8l-2.402-4.036c1.473-.48 3.33-.288 4.707.289 0 0 1.058 2.498.289 3.458-.385.864-2.69.48-2.594.29zM319.168 292.931c1.281-.64 2.466-1.76 2.69-3.361l-4.419-5.092-4.034-.095c-.928-.961-2.434-1.153-3.65-1.153 0 0 1.25 1.92 2.882 2.306 1.153 2.591 6.148 7.395 6.531 7.395zM323.5 293.498c0-.095 3.937-1.441 6.05-1.248-.19-1.634 2.979-5.38 2.979-5.38l5.572 7.3c-1.025.865-2.819.577-4.228.865 0 0-2.69 2.594-2.978 2.69s-5.187 1.248-7.59-.191c-1.055-2.018.29-4.325.194-4.036zM326.664 280.722c.673-2.337.864-4.676 0-7.59 0 0-6.341-.096-6.341 0s-4.226 1.921-4.226 2.018 1.346 4.13 2.978 3.746c.736 2.146 2.913 1.6 3.938 2.402 1.217-.192 2.433-.385 3.651-.576zM351.55 274.292c-.865 2.659-1.345 5.509-.097 8.07 1.153.192 2.498.96 3.555.768l5.092-9.223c-3.523-1.12-6.373-.992-8.55.385z" fill-rule="evenodd" fill="#c76e2e"/>
+  <path d="M353.115 193.19c-12.011-3.884 2.807-11.65 5.267 0 3.886.627 4.39 3.51 12.79 2.258 20.313 33.102 5.266 86.518-54.17 141.816 106.457-90.594 63.194-157.604 33.715-155.077-16.034 1.096-7.946 21.096 2.398 11.002z" fill-rule="evenodd" fill="#b97700"/>
+  <path d="M354.331 284.67c-.191 0-3.073 2.112-3.073 2.112-1.378.544-2.753 1.089-4.13 1.634l-4.42.095-.961-3.074 3.363-2.978c-2.85-.416-5.7.705-7.974 2.787 0 0 0 3.361 1.922 4.995 1.153 1.44 4.514 4.035 4.514 4.035 2.114.416 4.131.063 5.476-1.058 1.76-2.85 3.523-5.699 5.283-8.549zM331.078 314.835c1.443.385 11.337-12.776 11.337-12.776-.865-2.465-2.787-4.259-4.9-5.38 0 0-4.805 5.667-4.9 7.589-.767 1.729-2.976 8.357-2.017 9.223-.096.192-.48 2.88.48 1.344z" fill-rule="evenodd" fill="#c76e2e"/>
+  <path stroke-linejoin="round" d="M266.366 317.4c-14.817-12.887-34.809-19.991-62.716-10.35 7.51 3.248 15.628 4.364 22.529 7.915l40.187 2.435z" fill-rule="evenodd" stroke="#004100" stroke-width="2.3686254" fill="#006800"/>
+  <path d="M223.44 308.256c29.227.608 37.752 7.913 36.23 6.696" stroke="#00a400" stroke-linecap="round" stroke-width="2.2203781" fill="none"/>
+  <path stroke-linejoin="round" d="M266.965 318.916c-8.728 1.724-20.804 10.154-24.356 9.741-9.54-1.11-18.454-4.975-27.704-7.915-3.842-1.221-7.713 0-11.57 0 32.78-15.526 43.943-13.396 63.63-1.826z" fill-rule="evenodd" stroke="#004100" stroke-width="2.2203781" fill="#006800"/>
+  <path stroke-linejoin="round" d="M245.361 296.08s-10.959 1.52-15.83 1.825c-4.873-.303-11.955-4.842-19.79-13.09-4.088-4.48-13.395-3.958-13.395-3.958 20.602-4.365 36.634-.204 49.015 15.222zM230.436 274.775c-14.92-.914-33.49-14.308-37.751-30.139-.002.202 5.479 3.45 4.566 4.263 24.457 6.19 26.081 11.161 33.185 25.876zM255.405 300.344c2.13-13.498 2.74-22.427-3.653-30.444-5.277-6.09-6.596-9.743-10.35-18.268-1.116 17.76-4.974 32.474 14.003 48.712zM231.952 262.899c11.06-16.136 12.99-28.314 11.264-47.494-.305 1.522-3.958 10.96-4.261 10.96-16.44 10.35-9.133 26.488-7.003 36.534z" fill-rule="evenodd" stroke="#004100" stroke-width="2.3686254" fill="#006800"/>
+  <path stroke-linejoin="round" d="M222.225 184.96c11.06 16.136 9.336 31.36 7.61 50.54-.305-1.523-3.958-10.96-4.26-10.96-16.441-10.351-5.48-29.534-3.35-39.58z" fill-rule="evenodd" stroke="#004100" stroke-width="2.3686254" fill="#006800"/>
+  <path stroke-linejoin="round" d="M231.353 209.93c26.79-13.498 16.438-30.648 21.31-43.84-18.57 13.802-21.006 28.515-21.31 43.84z" fill-rule="evenodd" stroke="#004100" stroke-width="2.3686254" fill="#006800"/>
+  <path d="M235 206.581c3.35-9.437 10.048-25.573 10.656-25.573M227.088 226.37c-.608-6.7-3.956-24.662-4.26-26.488" stroke="#00a400" stroke-linecap="round" stroke-width="2.2203781" fill="none"/>
+  <path stroke-linejoin="round" d="M228.304 256.502c-14.92-.914-31.055-21.31-35.316-37.141-.001.201 5.479 3.45 4.566 4.262 21.412 9.538 23.646 18.165 30.75 32.88zM223.874 242.494c-11.06-16.136-12.99-28.314-11.264-47.494.305 1.522 3.958 10.96 4.261 10.96 16.44 10.35 9.133 26.488 7.003 36.534zM233.785 214.194c27.703-12.28 19.178-25.167 27.399-38.665-18.571 13.802-27.095 23.34-27.4 38.665z" fill-rule="evenodd" stroke="#004100" stroke-width="2.3686254" fill="#006800"/>
+  <path d="M235 211.445c11.266-11.265 15.223-20.703 15.223-20.703" stroke="#00a400" stroke-linecap="round" stroke-width="2.2203781" fill="none"/>
+  <g fill-rule="evenodd">
+    <path d="M333.56 366.355l13.49.275c-44.787-41.942-130.599-60.205-118.667-137.39-12.298 83.701 70.117 91.41 105.177 137.115z" stroke="#e9bf00" stroke-width="2.3686254" fill="#ffe100"/>
+    <path d="M235.417 212.661a4.298 4.298 0 1 1-8.596 0 4.298 4.298 0 0 1 8.596 0zM232.785 236.297a4.06 4.06 0 1 1-8.118 0 4.06 4.06 0 0 1 8.118 0zM236.6 269.978a3.582 3.582 0 1 1-7.164 0 3.582 3.582 0 0 1 7.164 0zM267.876 307.223a3.582 3.582 0 1 1-7.163 0 3.582 3.582 0 0 1 7.163 0zM272.412 317.907a3.582 3.582 0 1 1-7.163 0 3.582 3.582 0 0 1 7.163 0z" stroke="#68300e" stroke-width="1.1110219000000001" fill="#9d4916"/>
+  </g>
+  <g fill-rule="evenodd" fill="#fff">
+    <g stroke="#000" stroke-width=".667">
+      <path d="M288.203 349.032c-2.355-2.134-3.853-3.503-4.777-5.828l-14.044-1.528c-.063 2.675-.126 5.349-.191 8.024l19.012-.668z" stroke-width="1.1110219000000001"/>
+      <path stroke-linejoin="round" d="M185.313 339.57c8.157 1.507 20.456-.752 24.472 4.518 4.822 5.465-15.093 13.872-12.241 18.6 6.16 6.517 12.5 3.83 19.394.226 1.624-3.523 2.878-9.804 3.766-11.672-2.51-5.773-9.253-8.601-7.53-17.32 11.37-4.249 33.23-3.897 35.583-2.258 1.848 3.623.187 5.273.564 8.16-1.883 3.64-6.728 9.81-6.738 13.074 11.93 4.203 15.074-.648 25.806-.363 12.575.155 20.225 3.531 22.955-1.467-1.87-4.315-13.403-.805-17.78-3.577-2.19-.74-3.604-2.5-5.496-4.44s-7.21-2.04-8.007-6.817c2.225-10.214 16.965-8.653 19.375-10.217l38.405 2.635c6.957-.196 10.892 12.323 1.497 16.09-9.394 3.767-37.18-5.588-49.233.842-.623-2.622-9.283-6.588-9.907-6.713-3.69 1.105-10.88.7-10.88.7-1.758 3.263-3.764 5.652-5.521 8.915-7.975-3.497-15.514 2.715-24.224.874 0 0-13.178 1.506-13.554 1.506s-8.658-.753-8.658-.753c-4.393 1.254-8.785 2.51-13.178 3.765l9.412-8.284-8.282-6.023z" stroke-width="1.1110219000000001"/>
+      <path d="M184.732 337.954a3.63 3.63 0 1 1-7.26 0 3.63 3.63 0 0 1 7.26 0zM183.78 355.911a3.63 3.63 0 1 1-7.26 0 3.63 3.63 0 0 1 7.26 0z" stroke-width="1.1110219000000001"/>
+    </g>
+    <g stroke="#000" stroke-width=".667">
+      <path d="M346.253 349.097c2.355-2.134 3.852-3.503 4.777-5.828l14.043-1.528.192 8.024-19.012-.668z" stroke-width="1.1110219000000001"/>
+      <path stroke-linejoin="round" d="M449.143 339.636c-8.157 1.506-20.457-.753-24.473 4.517-4.822 5.465 15.093 13.872 12.242 18.6-6.16 6.517-12.5 3.83-19.394.226-1.624-3.523-2.878-9.804-3.766-11.671 2.51-5.774 9.253-8.602 7.53-17.32-11.371-4.25-33.23-3.898-35.584-2.26-1.847 3.624-.187 5.274-.563 8.161 1.882 3.64 6.728 9.81 6.738 13.074-11.93 4.203-15.075-.648-25.807-.363-12.574.155-20.225 3.531-22.955-1.467 1.87-4.315 13.404-.805 17.781-3.577 2.19-.74 3.603-2.5 5.496-4.44s7.21-2.04 8.007-6.816c-2.226-10.215-16.966-8.654-19.376-10.218l-38.404 2.635c-6.958-.196-10.892 12.323-1.498 16.091 9.395 3.766 37.18-5.588 49.233.841.623-2.622 9.283-6.588 9.908-6.713 3.69 1.105 10.88.7 10.88.7 1.758 3.263 3.763 5.652 5.52 8.915 7.976-3.497 15.515 2.715 24.225.874 0 0 13.177 1.506 13.554 1.506s8.658-.753 8.658-.753l13.177 3.765c-3.136-2.762-6.274-5.522-9.411-8.284l8.282-6.023z" stroke-width="1.1110219000000001"/>
+      <path d="M449.723 338.02a3.63 3.63 0 1 0 7.261 0 3.63 3.63 0 0 0-7.26 0zM450.675 355.976a3.63 3.63 0 1 0 7.26 0 3.63 3.63 0 0 0-7.26 0z" stroke-width="1.1110219000000001"/>
+    </g>
+    <path d="M316.986 329.343c-3.231-.606-4.38-.433-6.57-.65-1.715 5.271-3.427 10.541-5.141 15.812 7.938.716 15.29.716 15.29.651-4.816-.976-3.644-15.748-3.579-15.813z"/>
+  </g>
+  <g font-size="9" font-family="Trebuchet MS" font-weight="bold">
+    <text y="344.274" x="448.605" transform="translate(-464.91 -233.28) scale(1.6657)">
+      <tspan y="344.274" x="448.605">L</tspan>
+    </text>
+    <text y="344.622" x="453.64" transform="translate(-464.91 -233.28) scale(1.6657)">
+      <tspan y="344.622" x="453.64">I</tspan>
+    </text>
+    <text y="345.056" x="456.678" transform="translate(-464.91 -233.28) scale(1.6657)">
+      <tspan y="345.056" x="456.678">B</tspan>
+    </text>
+    <text y="345.49" x="462.58" transform="translate(-464.91 -233.28) scale(1.6657)">
+      <tspan y="345.49" x="462.58">E</tspan>
+    </text>
+    <text y="345.576" x="468.309" transform="translate(-464.91 -233.28) scale(1.6657)">
+      <tspan y="345.576" x="468.309">R</tspan>
+    </text>
+    <text y="345.403" x="473.952" transform="translate(-464.91 -233.28) scale(1.6657)">
+      <tspan y="345.403" x="473.952">T</tspan>
+    </text>
+    <text y="344.535" x="479.247" transform="translate(-464.91 -233.28) scale(1.6657)">
+      <tspan y="344.535" x="479.247">A</tspan>
+    </text>
+    <text y="344.274" x="485.497" transform="translate(-464.91 -233.28) scale(1.6657)">
+      <tspan y="344.274" x="485.497">S</tspan>
+    </text>
+  </g>
+  <path d="M231.353 318.616c10.047 1.218 24.052.304 30.14-.001M216.128 284.203c8.525 6.698 27.096 10.654 26.791 10.654M253.573 296.696c-2.74-14.004-5.783-17.353-8.219-26.183M201.82 254.67c14.31 6.393 16.44 10.654 25.573 17.047M232.569 257.718c1.219-17.355 3.654-21.922 7.917-25.88M201.82 229.718c5.177 5.785 22.225 23.746 22.225 23.746M217.044 213.877c6.395 4.566 6.395 21.005 6.395 21.005" stroke="#00a400" stroke-linecap="round" stroke-width="2.2203781" fill="none"/>
+</svg>
diff --git a/test/image.svg.test.js b/test/image.svg.test.js
index 2e2ad27a8f..c09fec51a2 100644
--- a/test/image.svg.test.js
+++ b/test/image.svg.test.js
@@ -25,10 +25,10 @@ describe('mapnik.Image SVG', function() {
         }, /first argument is invalid, must be a Buffer/);
         assert.throws(function() {
           new mapnik.Image.fromSVGBytesSync(new Buffer('asdfasdf'));
-        }, /SVG parse error:\s+Unable to parse 'asdfasdf'/);
+        }, /SVG error: unable to parse "asdfasdf"/);
         assert.throws(function() {
           mapnik.Image.fromSVGSync('./test/data/SVG_DOES_NOT_EXIST.svg');
-        }, /SVG parse error:\s+Unable to open '.\/test\/data\/SVG_DOES_NOT_EXIST.svg'/);
+        }, /SVG error: unable to open "\.\/test\/data\/SVG_DOES_NOT_EXIST\.svg"/);
         assert.throws(function() {
           mapnik.Image.fromSVGSync('./test/data/vector_tile/tile0.expected-svg.svg', 256);
         }, /optional second arg must be an options object/);
@@ -73,7 +73,7 @@ describe('mapnik.Image SVG', function() {
         }, /image created from svg must have a width and height greater then zero/);
         mapnik.Image.fromSVGBytes(new Buffer('a'), { scale: 1 }, function(err, res) {
             assert.ok(err);
-            assert.ok(err.message.match(/Unable to parse 'a'/));
+            assert.ok(err.message.match(/SVG error: unable to parse "a"/));
             var svgdata = "<svg width='1000000000000' height='1000000000000'><g id='a'><ellipse fill='#FFFFFF' stroke='#000000' stroke-width='4' cx='50' cy='50' rx='25' ry='25'/></g></svg>";
             var buffer = new Buffer(svgdata);
             mapnik.Image.fromSVGBytes(buffer, { scale: 1 }, function(err, img) {
@@ -149,7 +149,7 @@ describe('mapnik.Image SVG', function() {
         done();
       });
     });
-    
+
     it('should err with async file w/o width or height as Bytes', function(done) {
         var svgdata = "<svg width='0' height='0'><g id='a'><ellipse fill='#FFFFFF' stroke='#000000' stroke-width='4' cx='50' cy='50' rx='25' ry='25'/></g></svg>";
         var buffer = new Buffer(svgdata);
@@ -164,7 +164,7 @@ describe('mapnik.Image SVG', function() {
     it('should err with async invalid buffer', function(done) {
       mapnik.Image.fromSVGBytes(new Buffer('asdfasdf'), function(err, svg) {
         assert.ok(err);
-        assert.ok(err.message.match(/SVG parse error:\s+Unable to parse 'asdfasdf'/));
+        assert.ok(err.message.match(/SVG error: unable to parse "asdfasdf"/));
         assert.equal(svg, undefined);
         done();
       });
@@ -173,7 +173,7 @@ describe('mapnik.Image SVG', function() {
     it('should err with async non-existent file', function(done) {
       mapnik.Image.fromSVG('./test/data/SVG_DOES_NOT_EXIST.svg', function(err, svg) {
         assert.ok(err);
-        assert.ok(err.message.match(/SVG parse error:\s+Unable to open '.\/test\/data\/SVG_DOES_NOT_EXIST.svg'/));
+        assert.ok(err.message.match(/SVG error: unable to open "\.\/test\/data\/SVG_DOES_NOT_EXIST\.svg"/));
         assert.equal(svg, undefined);
         done();
       });
@@ -196,7 +196,7 @@ describe('mapnik.Image SVG', function() {
         assert.equal(img.height(), 256);
         assert.equal(img.encodeSync('png32').length, 17571);
     });
-    
+
     it('#fromSVGSync load from SVG file - 2', function() {
         var img = mapnik.Image.fromSVG('./test/data/vector_tile/tile0.expected-svg.svg');
         assert.ok(img);
diff --git a/test/map.test.js b/test/map.test.js
index b1ecb17a9b..8fd61b5dfb 100644
--- a/test/map.test.js
+++ b/test/map.test.js
@@ -195,7 +195,8 @@ describe('mapnik.Map', function() {
         assert.throws(function() { map.loadSync('./test/stylesheet.xml', {strict: 12 }); });
         assert.throws(function() { map.loadSync('./test/stylesheet.xml', {base: 12 }); });
         assert.throws(function() { map.loadSync('./test/stylesheet.xml', {base: '/DOESNOTEXIST' }); });
-
+        // replace map with the new one
+        map = new mapnik.Map(600,400);
         // Test loading a sample world map
         map.loadSync('./test/stylesheet.xml');
 
diff --git a/test/vector-tile.query.test.js b/test/vector-tile.query.test.js
index bbe23350ac..f39e66eec0 100644
--- a/test/vector-tile.query.test.js
+++ b/test/vector-tile.query.test.js
@@ -63,9 +63,9 @@ describe('mapnik.VectorTile query polygon', function() {
             assert.equal(JSON.parse(features[0].toJSON()).properties.NAME,'Japan');
             assert.equal(features[0].id(),89);
             assert.equal(features[0].geometry().type(),mapnik.Geometry.Polygon);
-            assert.equal(features[0].distance,0);
-            assert.equal(features[0].x_hit,0);
-            assert.equal(features[0].y_hit,0);
+            assert.equal(features[0].distance, 0);
+            assert.equal(features[0].x_hit, 139.6142578125);
+            assert.equal(features[0].y_hit, 37.17782559332976);
             assert.equal(features[0].layer,'world');
             assert.equal(JSON.parse(features[1].toJSON()).properties.NAME,'Japan');
             assert.equal(features[1].id(),89);
@@ -75,8 +75,7 @@ describe('mapnik.VectorTile query polygon', function() {
         }
     });
 
-    it('query polygon + tolerance (noop)', function(done) {
-        // tolerance only applies to points and lines currently in mapnik::hit_test
+    it('query polygon + tolerance', function(done) {
         check(vtile.query(142.3388671875,39.52099229357195,{tolerance:100000000000000}));
         vtile.query(142.3388671875,39.52099229357195,{tolerance:100000000000000}, function(err, features) {
             assert.ifError(err);
@@ -84,7 +83,7 @@ describe('mapnik.VectorTile query polygon', function() {
             done();
         });
         function check(features) {
-            assert.equal(features.length,0);
+            assert.equal(features.length, 2);
         }
     });
     // restrict to single layer
@@ -663,4 +662,3 @@ describe('mapnik.VectorTile query xy single features', function() {
         done();
     });
 });
-
