[Pkg-javascript-commits] [node-mapnik] 01/17: Imported Upstream version 3.5.12+dfsg

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Tue May 10 18:16:02 UTC 2016


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

sebastic pushed a commit to branch master
in repository node-mapnik.

commit 731962904619c12c3431a76d536432aab8d97f41
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Sun May 8 23:17:17 2016 +0200

    Imported Upstream version 3.5.12+dfsg
---
 .travis.yml                                        |  35 ++-
 CHANGELOG.md                                       |  19 ++
 deps/clipper/clipper.cpp                           |  22 +-
 package.json                                       |   4 +-
 scripts/build-appveyor.bat                         |   1 -
 scripts/is_pr_merge.sh                             |  27 +++
 scripts/publish.sh                                 |  26 ++
 src/mapnik_vector_tile.cpp                         | 269 ++++++++++++++++-----
 test/data/vector_tile/compositing/25084.vector.pbf | Bin 0 -> 10847 bytes
 .../vector_tile/compositing/25084_2.vector.pbf     | Bin 0 -> 4623 bytes
 .../vector_tile/compositing/expected/2-1-1b.png    | Bin 154578 -> 154481 bytes
 .../expected/world-reencode-max-extent.png         | Bin 7991 -> 7991 bytes
 .../compositing/expected/world-reencode.png        | Bin 7984 -> 7983 bytes
 test/vector-tile.composite.test.js                 |  16 ++
 test/vector-tile.test.js                           |  34 ++-
 15 files changed, 366 insertions(+), 87 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 9c39f88..8c14ed3 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -31,37 +31,37 @@ matrix:
      - os: osx
        osx_image: xcode7
        compiler: clang
-       env: NODE_VERSION="4" COVERAGE=true NPM_FLAGS="--debug" # node abi 46
+       env: NODE_VERSION="4" COVERAGE=true NPM_FLAGS="--debug" PUBLISHABLE=false # node abi 46
      # Linux
      - os: linux
        compiler: clang
-       env: NODE_VERSION="5" # node abi 47
+       env: NODE_VERSION="5" PUBLISHABLE=true # node abi 47
      - os: linux
        compiler: clang
-       env: NODE_VERSION="4" # node abi 46
+       env: NODE_VERSION="4" PUBLISHABLE=true # node abi 46
      - os: linux
        compiler: clang
-       env: NODE_VERSION="0.10" NPM_FLAGS="--debug" # node abi 11
+       env: NODE_VERSION="0.10" NPM_FLAGS="--debug" PUBLISHABLE=true # node abi 11
      - os: linux
        compiler: clang
-       env: NODE_VERSION="0.10" # node abi 11
+       env: NODE_VERSION="0.10" PUBLISHABLE=true # node abi 11
      # OS X
      - os: osx
        osx_image: xcode7
        compiler: clang
-       env: NODE_VERSION="5" # node abi 47
+       env: NODE_VERSION="5" PUBLISHABLE=true # node abi 47
      - os: osx
        osx_image: xcode7
        compiler: clang
-       env: NODE_VERSION="4" # node abi 46
+       env: NODE_VERSION="4" PUBLISHABLE=true # node abi 46
      - os: osx
        osx_image: xcode7
        compiler: clang
-       env: NODE_VERSION="0.10" NPM_FLAGS="--debug" # node abi 11
+       env: NODE_VERSION="0.10" NPM_FLAGS="--debug" PUBLISHABLE=true # node abi 11
      - os: osx
        osx_image: xcode7
        compiler: clang
-       env: NODE_VERSION="0.10" # node abi 11
+       env: NODE_VERSION="0.10" PUBLISHABLE=true # node abi 11
 
 before_install:
  - scripts/validate_tag.sh
@@ -93,19 +93,16 @@ install:
  - npm test
 
 before_script:
- - if [[ ${COVERAGE} == false ]]; then
-      echo "publishing";
-      if [[ ${COMMIT_MESSAGE} =~ "[publish binary]" ]]; then
-        echo "publishing for the first time";
-        node-pre-gyp publish ${NPM_FLAGS};
-      elif [[ ${COMMIT_MESSAGE} =~ "[republish binary]" ]]; then
-        echo "republishing";
-        node-pre-gyp unpublish publish ${NPM_FLAGS};
-      fi
-   fi
+- if [[ ${PUBLISHABLE} == true ]]; then
+    ./scripts/publish.sh;
+  fi;
 
 script:
  - if [[ ${COVERAGE} == true ]]; then ./mason_packages/.link/bin/cpp-coveralls --exclude __nvm --exclude node_modules --exclude tests --build-root build --gcov-options '\-lp' --exclude tools --exclude docs --exclude sdk --exclude build/Debug/obj/gen --exclude build/Release/obj/gen --exclude src/mapnik_featureset.hpp --exclude src/mapnik_logger.hpp --exclude src/mapnik_image_view.hpp --exclude src/mapnik_geometry.hpp --exclude deps > /dev/null; fi;
  #- node --expose-gc bench/error/test_vt_abort2.js
  # ugh: always killed by travis
  #- nice -n 19 node --expose-gc bench/error/test_vt_abort.js
+
+notifications:
+  slack:
+    secure: wLpScQaDoEsVe0Bu28b62FGZBfmX3s/NK8DWcuSxEFx80k8RKPNgnMg8htamG0zRSf5htF+X6jy2P0IeUvbeupIaJwqtXvHaJYtlMTmemG/xuXLTpLp6k6giT2mWm/lp+ykuaF/PvUcZWUhSf1zhS6vwIekrMYIcDYvNXjO8DNw=
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 49d1642..c695f26 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,24 @@
 # Changelog
 
+## 3.5.12
+
+- Fix performance regression when passing raster through vector tile (via upgrade to mapnik-vector-tile at 1.1.2)
+
+## 3.5.11
+
+- Fix for numerical precision issue in mapnik vector tile where valid v2 vector tiles would be thrown as invalid
+- Added new exception handling for toGeoJSON
+
+## 3.5.10
+
+- Fix for a segfault in the vector tile clipping library
+
+## 3.5.9
+
+- Updated to mapnik-vector-tile `1.1.0`
+- Automatic updating of vector tiles from v1 to v2 no longer takes place automatically when using `setData` and `addData`.
+- Validation of vector tiles is now optional when using `setData` and `addData`
+
 ## 3.5.8
 
 - Updated to mapnik-vector-tile `1.0.6` which includes a speedup on simplification for mapnik-vector-tile
diff --git a/deps/clipper/clipper.cpp b/deps/clipper/clipper.cpp
index 3c1f3f0..2cd7102 100644
--- a/deps/clipper/clipper.cpp
+++ b/deps/clipper/clipper.cpp
@@ -3986,11 +3986,27 @@ void Clipper::FixupFirstLefts2(OutRec* InnerOutRec, OutRec* OuterOutRec)
     {
         if (outRec->IsHole == OuterOutRec->IsHole)
         {
-            outRec->FirstLeft = ParseFirstLeft(OuterOutRec->FirstLeft);
+            if (Poly2ContainsPoly1(outRec->Pts, OuterOutRec->Pts))
+            {
+                outRec->FirstLeft = OuterOutRec;
+            }
+            else
+            {
+                outRec->FirstLeft = ParseFirstLeft(OuterOutRec->FirstLeft);
+            }
         }
         else
         {
-            outRec->FirstLeft = OuterOutRec;
+            if (Area(outRec->Pts) == 0.0 && !Poly2ContainsPoly1(outRec->Pts, OuterOutRec->Pts))
+            {
+                outRec->IsHole = !outRec->IsHole;
+                outRec->FirstLeft = ParseFirstLeft(OuterOutRec->FirstLeft);
+                ReversePolyPtLinks(outRec->Pts);
+            }
+            else
+            {
+                outRec->FirstLeft = OuterOutRec;
+            }
         }
     }
   }
@@ -5215,6 +5231,8 @@ void Clipper::DoSimplePolygons()
                                     dupeRec.emplace(outrec2->Idx, intPt2);
                                 }
                             }
+                            outRec_j = GetOutRec(m_OutPts[j]->Idx);
+                            idx_j = outRec_j->Idx;
                         }
                         continue;
                     }
diff --git a/package.json b/package.json
index ed58fd4..e98b9e5 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,7 @@
   "url": "http://github.com/mapnik/node-mapnik",
   "homepage": "http://mapnik.org",
   "author": "Dane Springmeyer <dane at mapbox.com> (mapnik.org)",
-  "version": "3.5.8",
+  "version": "3.5.12",
   "mapnik_version":"3.0.11",
   "main": "./lib/mapnik.js",
   "binary": {
@@ -41,7 +41,7 @@
     }
   ],
   "dependencies": {
-    "mapnik-vector-tile": "1.0.6",
+    "mapnik-vector-tile": "1.1.2",
     "nan": "~2.2.0",
     "node-pre-gyp": "~0.6.25",
     "protozero": "~1.3.0"
diff --git a/scripts/build-appveyor.bat b/scripts/build-appveyor.bat
index f4695db..6f7916e 100644
--- a/scripts/build-appveyor.bat
+++ b/scripts/build-appveyor.bat
@@ -146,7 +146,6 @@ IF %ERRORLEVEL% NEQ 0 GOTO ERROR
 
 CALL npm test
 :: uncomment to allow build to work even if tests do not pass
-::SET ERRORLEVEL=0
 IF %ERRORLEVEL% NEQ 0 GOTO ERROR
 
 ECHO APPVEYOR_REPO_COMMIT_MESSAGE^: %APPVEYOR_REPO_COMMIT_MESSAGE%
diff --git a/scripts/is_pr_merge.sh b/scripts/is_pr_merge.sh
new file mode 100755
index 0000000..6e94c1a
--- /dev/null
+++ b/scripts/is_pr_merge.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+set -eu pipefail
+
+: '
+
+This script is designed to detect if a gitsha represents a normal
+push commit (to any branch) or whether it represents travis attempting
+to merge between the origin and the upstream branch.
+
+For more details see: https://docs.travis-ci.com/user/pull-requests
+
+'
+
+# Get the commit message via git log
+# This should always be the exact text the developer provided
+COMMIT_LOG=$(git log --format=%B --no-merges -n 1 | tr -d '\n')
+
+# Get the commit message via git show
+# If the gitsha represents a merge then this will
+# look something like "Merge e3b1981 into 615d2a3"
+# Otherwise it will be the same as the "git log" output
+COMMIT_SHOW=$(git show -s --format=%B | tr -d '\n')
+
+if [[ "${COMMIT_LOG}" != "${COMMIT_SHOW}" ]]; then
+   echo true
+fi
diff --git a/scripts/publish.sh b/scripts/publish.sh
new file mode 100755
index 0000000..a8f4d43
--- /dev/null
+++ b/scripts/publish.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+echo "dumping binary meta..."
+./node_modules/.bin/node-pre-gyp reveal ${NPM_FLAGS}
+
+echo "determining publishing status..."
+
+if [[ $(./scripts/is_pr_merge.sh) ]]; then
+    echo "Skipping publishing because this is a PR merge commit"
+else
+    echo "This is a push commit, continuing to package..."
+    ./node_modules/.bin/node-pre-gyp package ${NPM_FLAGS}
+
+    COMMIT_MESSAGE=$(git log --format=%B --no-merges | head -n 1 | tr -d '\n')
+    echo "Commit message: ${COMMIT_MESSAGE}"
+
+    if [[ ${COMMIT_MESSAGE} =~ "[publish binary]" ]]; then
+        echo "Publishing"
+        ./node_modules/.bin/node-pre-gyp publish ${NPM_FLAGS}
+    elif [[ ${COMMIT_MESSAGE} =~ "[republish binary]" ]]; then
+        echo "Re-Publishing"
+        ./node_modules/.bin/node-pre-gyp unpublish publish ${NPM_FLAGS}
+    else
+        echo "Skipping publishing"
+    fi;
+fi
diff --git a/src/mapnik_vector_tile.cpp b/src/mapnik_vector_tile.cpp
index 1e6efea..66cf466 100644
--- a/src/mapnik_vector_tile.cpp
+++ b/src/mapnik_vector_tile.cpp
@@ -466,6 +466,10 @@ void _composite(VectorTile* target_vt,
     {
         map.set_maximum_extent(*max_extent);
     }
+    else
+    {
+        map.set_maximum_extent(target_vt->get_tile()->get_buffered_extent());
+    }
 
     std::vector<mapnik::vector_tile_impl::merc_tile_ptr> merc_vtiles;
     for (VectorTile* vt : vtiles)
@@ -2922,47 +2926,57 @@ v8::Local<v8::Value> VectorTile::_toGeoJSONSync(Nan::NAN_METHOD_ARGS_TYPE info)
 
     VectorTile* v = Nan::ObjectWrap::Unwrap<VectorTile>(info.Holder());
     std::string result;
-    if (layer_id->IsString())
+    try
     {
-        std::string layer_name = TOSTR(layer_id);
-        if (layer_name == "__array__")
-        {
-            write_geojson_array(result, v);
-        }
-        else if (layer_name == "__all__")
+        if (layer_id->IsString())
         {
-            write_geojson_all(result, v);
+            std::string layer_name = TOSTR(layer_id);
+            if (layer_name == "__array__")
+            {
+                write_geojson_array(result, v);
+            }
+            else if (layer_name == "__all__")
+            {
+                write_geojson_all(result, v);
+            }
+            else
+            {
+                if (!write_geojson_layer_name(result, layer_name, v))
+                {
+                    std::string error_msg("Layer name '" + layer_name + "' not found");
+                    Nan::ThrowTypeError(error_msg.c_str());
+                    return scope.Escape(Nan::Undefined());
+                }
+            }
         }
-        else
+        else if (layer_id->IsNumber())
         {
-            if (!write_geojson_layer_name(result, layer_name, v))
+            int layer_idx = layer_id->IntegerValue();
+            if (layer_idx < 0)
             {
-                std::string error_msg("Layer name '" + layer_name + "' not found");
-                Nan::ThrowTypeError(error_msg.c_str());
+                Nan::ThrowTypeError("A layer index can not be negative");
+                return scope.Escape(Nan::Undefined());
+            }
+            else if (layer_idx >= static_cast<int>(v->get_tile()->get_layers().size()))
+            {
+                Nan::ThrowTypeError("Layer index exceeds the number of layers in the vector tile.");
+                return scope.Escape(Nan::Undefined());
+            }
+            if (!write_geojson_layer_index(result, layer_idx, v))
+            {
+                // LCOV_EXCL_START
+                Nan::ThrowTypeError("Layer could not be retrieved (should have not reached here)");
                 return scope.Escape(Nan::Undefined());
+                // LCOV_EXCL_STOP
             }
         }
     }
-    else if (layer_id->IsNumber())
+    catch (std::exception const& ex)
     {
-        int layer_idx = layer_id->IntegerValue();
-        if (layer_idx < 0)
-        {
-            Nan::ThrowTypeError("A layer index can not be negative");
-            return scope.Escape(Nan::Undefined());
-        }
-        else if (layer_idx >= static_cast<int>(v->get_tile()->get_layers().size()))
-        {
-            Nan::ThrowTypeError("Layer index exceeds the number of layers in the vector tile.");
-            return scope.Escape(Nan::Undefined());
-        }
-        if (!write_geojson_layer_index(result, layer_idx, v))
-        {
-            // LCOV_EXCL_START
-            Nan::ThrowTypeError("Layer could not be retrieved (should have not reached here)");
-            return scope.Escape(Nan::Undefined());
-            // LCOV_EXCL_STOP
-        }
+        // LCOV_EXCL_START
+        Nan::ThrowTypeError(ex.what());
+        return scope.Escape(Nan::Undefined());
+        // LCOV_EXCL_STOP
     }
     return scope.Escape(Nan::New<v8::String>(result).ToLocalChecked());
 }
@@ -3816,6 +3830,10 @@ void VectorTile::EIO_AfterAddImageBuffer(uv_work_t* req)
  * @instance
  * @name addDataSync
  * @param {Buffer} buffer - raw data
+ * @param {object} [options]
+ * @param {boolean} [options.validate=false] - If true does validity checks mvt schema (not geometries)
+ * Will throw if anything invalid or unexpected is encountered in the data
+ * @param {boolean} [options.upgrade=false] - If true will upgrade v1 tiles to adhere to the v2 specification
  * @example
  * var data_buffer = fs.readFileSync('./path/to/data.mvt'); // returns a buffer
  * // assumes you have created a vector tile object already
@@ -3848,9 +3866,41 @@ v8::Local<v8::Value> VectorTile::_addDataSync(Nan::NAN_METHOD_ARGS_TYPE info)
         Nan::ThrowError("cannot accept empty buffer as protobuf");
         return scope.Escape(Nan::Undefined());
     }
+    bool upgrade = false;
+    bool validate = false;
+    v8::Local<v8::Object> options = Nan::New<v8::Object>();
+    if (info.Length() > 1)
+    {
+        if (!info[1]->IsObject())
+        {
+            Nan::ThrowTypeError("second arg must be a options object");
+            return scope.Escape(Nan::Undefined());
+        }
+        options = info[1]->ToObject();
+        if (options->Has(Nan::New<v8::String>("validate").ToLocalChecked()))
+        {
+            v8::Local<v8::Value> param_val = options->Get(Nan::New("validate").ToLocalChecked());
+            if (!param_val->IsBoolean())
+            {
+                Nan::ThrowTypeError("option 'validate' must be a boolean");
+                return scope.Escape(Nan::Undefined());
+            }
+            validate = param_val->BooleanValue();
+        }
+        if (options->Has(Nan::New<v8::String>("upgrade").ToLocalChecked()))
+        {
+            v8::Local<v8::Value> param_val = options->Get(Nan::New("upgrade").ToLocalChecked());
+            if (!param_val->IsBoolean())
+            {
+                Nan::ThrowTypeError("option 'upgrade' must be a boolean");
+                return scope.Escape(Nan::Undefined());
+            }
+            upgrade = param_val->BooleanValue();
+        }
+    }
     try
     {
-        merge_from_compressed_buffer(*d->get_tile(), node::Buffer::Data(obj), buffer_size); 
+        merge_from_compressed_buffer(*d->get_tile(), node::Buffer::Data(obj), buffer_size, validate, upgrade);
     }
     catch (std::exception const& ex)
     {
@@ -3865,6 +3915,8 @@ typedef struct
     uv_work_t request;
     VectorTile* d;
     const char *data;
+    bool validate;
+    bool upgrade;
     size_t dataLength;
     bool error;
     std::string error_name;
@@ -3880,6 +3932,10 @@ typedef struct
  * @instance
  * @name addData
  * @param {Buffer} buffer - raw vector data
+ * @param {object} [options]
+ * @param {boolean} [options.validate=false] - If true does validity checks mvt schema (not geometries)
+ * Will throw if anything invalid or unexpected is encountered in the data
+ * @param {boolean} [options.upgrade=false] - If true will upgrade v1 tiles to adhere to the v2 specification
  * @param {Object} callback
  * @example
  * var data_buffer = fs.readFileSync('./path/to/data.mvt'); // returns a buffer
@@ -3891,17 +3947,11 @@ typedef struct
  */
 NAN_METHOD(VectorTile::addData)
 {
-    if (info.Length() == 1)
-    {
-        info.GetReturnValue().Set(_addDataSync(info));
-        return;
-    }
-
     // ensure callback is a function
     v8::Local<v8::Value> callback = info[info.Length() - 1];
     if (!info[info.Length() - 1]->IsFunction())
     {
-        Nan::ThrowTypeError("last argument must be a callback function");
+        info.GetReturnValue().Set(_addDataSync(info));
         return;
     }
 
@@ -3917,11 +3967,46 @@ NAN_METHOD(VectorTile::addData)
         return;
     }
 
+    bool upgrade = false;
+    bool validate = false;
+    v8::Local<v8::Object> options = Nan::New<v8::Object>();
+    if (info.Length() > 1)
+    {
+        if (!info[1]->IsObject())
+        {
+            Nan::ThrowTypeError("second arg must be a options object");
+            return;
+        }
+        options = info[1]->ToObject();
+        if (options->Has(Nan::New<v8::String>("validate").ToLocalChecked()))
+        {
+            v8::Local<v8::Value> param_val = options->Get(Nan::New("validate").ToLocalChecked());
+            if (!param_val->IsBoolean())
+            {
+                Nan::ThrowTypeError("option 'validate' must be a boolean");
+                return;
+            }
+            validate = param_val->BooleanValue();
+        }
+        if (options->Has(Nan::New<v8::String>("upgrade").ToLocalChecked()))
+        {
+            v8::Local<v8::Value> param_val = options->Get(Nan::New("upgrade").ToLocalChecked());
+            if (!param_val->IsBoolean())
+            {
+                Nan::ThrowTypeError("option 'upgrade' must be a boolean");
+                return;
+            }
+            upgrade = param_val->BooleanValue();
+        }
+    }
+
     VectorTile* d = Nan::ObjectWrap::Unwrap<VectorTile>(info.Holder());
 
     vector_tile_adddata_baton_t *closure = new vector_tile_adddata_baton_t();
     closure->request.data = closure;
     closure->d = d;
+    closure->validate = validate;
+    closure->upgrade = upgrade;
     closure->error = false;
     closure->cb.Reset(callback.As<v8::Function>());
     closure->buffer.Reset(obj.As<v8::Object>());
@@ -3944,7 +4029,7 @@ void VectorTile::EIO_AddData(uv_work_t* req)
     }
     try
     {
-        merge_from_compressed_buffer(*closure->d->get_tile(), closure->data, closure->dataLength); 
+        merge_from_compressed_buffer(*closure->d->get_tile(), closure->data, closure->dataLength, closure->validate, closure->upgrade);
     }
     catch (std::exception const& ex)
     {
@@ -3982,6 +4067,10 @@ void VectorTile::EIO_AfterAddData(uv_work_t* req)
  * @instance
  * @name setDataSync
  * @param {Buffer} buffer - raw data
+ * @param {object} [options]
+ * @param {boolean} [options.validate=false] - If true does validity checks mvt schema (not geometries)
+ * Will throw if anything invalid or unexpected is encountered in the data
+ * @param {boolean} [options.upgrade=false] - If true will upgrade v1 tiles to adhere to the v2 specification
  * @example
  * var data = fs.readFileSync('./path/to/data.mvt');
  * vectorTile.setDataSync(data);
@@ -4013,10 +4102,42 @@ v8::Local<v8::Value> VectorTile::_setDataSync(Nan::NAN_METHOD_ARGS_TYPE info)
         Nan::ThrowError("cannot accept empty buffer as protobuf");
         return scope.Escape(Nan::Undefined());
     }
+    bool upgrade = false;
+    bool validate = false;
+    v8::Local<v8::Object> options = Nan::New<v8::Object>();
+    if (info.Length() > 1)
+    {
+        if (!info[1]->IsObject())
+        {
+            Nan::ThrowTypeError("second arg must be a options object");
+            return scope.Escape(Nan::Undefined());
+        }
+        options = info[1]->ToObject();
+        if (options->Has(Nan::New<v8::String>("validate").ToLocalChecked()))
+        {
+            v8::Local<v8::Value> param_val = options->Get(Nan::New("validate").ToLocalChecked());
+            if (!param_val->IsBoolean())
+            {
+                Nan::ThrowTypeError("option 'validate' must be a boolean");
+                return scope.Escape(Nan::Undefined());
+            }
+            validate = param_val->BooleanValue();
+        }
+        if (options->Has(Nan::New<v8::String>("upgrade").ToLocalChecked()))
+        {
+            v8::Local<v8::Value> param_val = options->Get(Nan::New("upgrade").ToLocalChecked());
+            if (!param_val->IsBoolean())
+            {
+                Nan::ThrowTypeError("option 'upgrade' must be a boolean");
+                return scope.Escape(Nan::Undefined());
+            }
+            upgrade = param_val->BooleanValue();
+        }
+    }
     try
     {
         d->clear();
-        merge_from_compressed_buffer(*d->get_tile(), node::Buffer::Data(obj), buffer_size); 
+        merge_from_compressed_buffer(*d->get_tile(), node::Buffer::Data(obj), buffer_size, validate, upgrade);
     }
     catch (std::exception const& ex)
     {
@@ -4031,6 +4152,8 @@ typedef struct
     uv_work_t request;
     VectorTile* d;
     const char *data;
+    bool validate;
+    bool upgrade;
     size_t dataLength;
     bool error;
     std::string error_name;
@@ -4046,6 +4169,10 @@ typedef struct
  * @instance
  * @name setData
  * @param {Buffer} buffer - raw data
+ * @param {object} [options]
+ * @param {boolean} [options.validate=false] - If true does validity checks mvt schema (not geometries)
+ * Will throw if anything invalid or unexpected is encountered in the data
+ * @param {boolean} [options.upgrade=false] - If true will upgrade v1 tiles to adhere to the v2 specification
  * @param {Function} callback
  * @example
  * var data = fs.readFileSync('./path/to/data.mvt');
@@ -4056,17 +4183,11 @@ typedef struct
  */
 NAN_METHOD(VectorTile::setData)
 {
-    if (info.Length() == 1)
-    {
-        info.GetReturnValue().Set(_setDataSync(info));
-        return;
-    }
-
     // ensure callback is a function
     v8::Local<v8::Value> callback = info[info.Length() - 1];
     if (!info[info.Length() - 1]->IsFunction())
     {
-        Nan::ThrowTypeError("last argument must be a callback function");
+        info.GetReturnValue().Set(_setDataSync(info));
         return;
     }
 
@@ -4082,10 +4203,45 @@ NAN_METHOD(VectorTile::setData)
         return;
     }
 
+    bool upgrade = false;
+    bool validate = false;
+    v8::Local<v8::Object> options = Nan::New<v8::Object>();
+    if (info.Length() > 1)
+    {
+        if (!info[1]->IsObject())
+        {
+            Nan::ThrowTypeError("second arg must be a options object");
+            return;
+        }
+        options = info[1]->ToObject();
+        if (options->Has(Nan::New<v8::String>("validate").ToLocalChecked()))
+        {
+            v8::Local<v8::Value> param_val = options->Get(Nan::New("validate").ToLocalChecked());
+            if (!param_val->IsBoolean())
+            {
+                Nan::ThrowTypeError("option 'validate' must be a boolean");
+                return;
+            }
+            validate = param_val->BooleanValue();
+        }
+        if (options->Has(Nan::New<v8::String>("upgrade").ToLocalChecked()))
+        {
+            v8::Local<v8::Value> param_val = options->Get(Nan::New("upgrade").ToLocalChecked());
+            if (!param_val->IsBoolean())
+            {
+                Nan::ThrowTypeError("option 'upgrade' must be a boolean");
+                return;
+            }
+            upgrade = param_val->BooleanValue();
+        }
+    }
+
     VectorTile* d = Nan::ObjectWrap::Unwrap<VectorTile>(info.Holder());
 
     vector_tile_setdata_baton_t *closure = new vector_tile_setdata_baton_t();
     closure->request.data = closure;
+    closure->validate = validate;
+    closure->upgrade = upgrade;
     closure->d = d;
     closure->error = false;
     closure->cb.Reset(callback.As<v8::Function>());
@@ -4111,7 +4267,7 @@ void VectorTile::EIO_SetData(uv_work_t* req)
     try
     {
         closure->d->clear();
-        merge_from_compressed_buffer(*closure->d->get_tile(), closure->data, closure->dataLength); 
+        merge_from_compressed_buffer(*closure->d->get_tile(), closure->data, closure->dataLength, closure->validate, closure->upgrade);
     }
     catch (std::exception const& ex)
     {
@@ -6380,19 +6536,24 @@ NAN_METHOD(VectorTile::info)
                 case mapnik::vector_tile_impl::Tile_Encoding::LAYERS:
                     {
                         v8::Local<v8::Object> layer_obj = Nan::New<v8::Object>();
-                        protozero::pbf_reader layer_msg = tile_msg.get_message();
                         std::uint64_t point_feature_count = 0;
                         std::uint64_t line_feature_count = 0;
                         std::uint64_t polygon_feature_count = 0;
                         std::uint64_t unknown_feature_count = 0;
                         std::uint64_t raster_feature_count = 0;
-                        std::string layer_name;
-                        std::uint32_t layer_version = 1;
+                        auto layer_data = tile_msg.get_data();
+                        protozero::pbf_reader layer_props_msg(layer_data);
+                        auto layer_info = mapnik::vector_tile_impl::get_layer_name_and_version(layer_props_msg);
+                        std::string const& layer_name = layer_info.first;
+                        std::uint32_t layer_version = layer_info.second;
                         std::set<mapnik::vector_tile_impl::validity_error> layer_errors;
+                        if (version > 2 || version < 1)
+                        {
+                            layer_errors.insert(mapnik::vector_tile_impl::LAYER_HAS_UNSUPPORTED_VERSION);
+                        }
+                        protozero::pbf_reader layer_msg(layer_data);
                         mapnik::vector_tile_impl::layer_is_valid(layer_msg, 
                                                                  layer_errors, 
-                                                                 layer_name, 
-                                                                 layer_version,
                                                                  point_feature_count,
                                                                  line_feature_count,
                                                                  polygon_feature_count,
diff --git a/test/data/vector_tile/compositing/25084.vector.pbf b/test/data/vector_tile/compositing/25084.vector.pbf
new file mode 100644
index 0000000..7403c2b
Binary files /dev/null and b/test/data/vector_tile/compositing/25084.vector.pbf differ
diff --git a/test/data/vector_tile/compositing/25084_2.vector.pbf b/test/data/vector_tile/compositing/25084_2.vector.pbf
new file mode 100644
index 0000000..d2bd8e8
Binary files /dev/null and b/test/data/vector_tile/compositing/25084_2.vector.pbf differ
diff --git a/test/data/vector_tile/compositing/expected/2-1-1b.png b/test/data/vector_tile/compositing/expected/2-1-1b.png
index 04b020e..f06feac 100644
Binary files a/test/data/vector_tile/compositing/expected/2-1-1b.png and b/test/data/vector_tile/compositing/expected/2-1-1b.png differ
diff --git a/test/data/vector_tile/compositing/expected/world-reencode-max-extent.png b/test/data/vector_tile/compositing/expected/world-reencode-max-extent.png
index fa9dc7d..d78b900 100644
Binary files a/test/data/vector_tile/compositing/expected/world-reencode-max-extent.png and b/test/data/vector_tile/compositing/expected/world-reencode-max-extent.png differ
diff --git a/test/data/vector_tile/compositing/expected/world-reencode.png b/test/data/vector_tile/compositing/expected/world-reencode.png
index 63d727c..b1e913f 100644
Binary files a/test/data/vector_tile/compositing/expected/world-reencode.png and b/test/data/vector_tile/compositing/expected/world-reencode.png differ
diff --git a/test/vector-tile.composite.test.js b/test/vector-tile.composite.test.js
index 8debd8c..c0b0512 100644
--- a/test/vector-tile.composite.test.js
+++ b/test/vector-tile.composite.test.js
@@ -784,4 +784,20 @@ describe('mapnik.VectorTile.composite', function() {
         done();
     });
 
+    it('should correctly composite -- numerical precision issue in mapnik vector tile area calculation', function() {
+        // Original data.
+        var vt = new mapnik.VectorTile(16,10691,25084);
+        var vt_data = fs.readFileSync('./test/data/vector_tile/compositing/25084.vector.pbf');
+        var vt2 = new mapnik.VectorTile(16,10691,25084);
+        var vt_data2 = fs.readFileSync('./test/data/vector_tile/compositing/25084_2.vector.pbf');
+        vt.setData(vt_data);
+        // Tile data
+        var vtile = new mapnik.VectorTile(18,42764,100336, {buffer_size: 255*16});
+        vtile.composite([vt, vt2]);
+        assert(!vtile.empty());
+        assert.doesNotThrow(function() {
+            vtile.toGeoJSON('wildoak');
+        });
+    });
+
 });
diff --git a/test/vector-tile.test.js b/test/vector-tile.test.js
index d620772..f28ec3b 100644
--- a/test/vector-tile.test.js
+++ b/test/vector-tile.test.js
@@ -1330,17 +1330,26 @@ describe('mapnik.VectorTile ', function() {
         assert.throws(function() { vtile.setData({},function(){}); }); // first arg must be a buffer object
         assert.throws(function() { vtile.setData(new Buffer('foo'), null); });
         assert.throws(function() { vtile.setData(new Buffer(0)); }); // empty buffer is not valid
-        
-        // invalid .mvt
-        var badTile = fs.readFileSync(path.resolve(__dirname + '/data/vector_tile/invalid_v2_tile.mvt'));
-        assert.throws(function() { vtile.setData(badTile); });
-
         vtile.setData(new Buffer('foo'),function(err) {
             assert.throws(function() { if (err) throw err; });
             done();
         });
     });
 
+    it('should error out if we validate tile with empty layers and features to setData - 1', function(done) {
+        var vtile = new mapnik.VectorTile(0,0,0);
+        var tile_with_emptyness = fs.readFileSync(path.resolve(__dirname + '/data/vector_tile/invalid_v2_tile.mvt'));
+        assert.throws(function() { vtile.setData(tile_with_emptyness,{validate:true}); });
+        // tile will be partially parsed (when not upgrading) before validation error is throw
+        // so we check that not all the layers are added
+        assert.equal(vtile.names().length,3);
+        // only fails with validation
+        var vtile3 = new mapnik.VectorTile(0,0,0);
+        vtile3.setData(tile_with_emptyness,{validate:false});
+        assert.equal(vtile3.names().length,23);
+        done();
+    });
+
     it('should error out if we pass invalid data to setData - 2', function(done) {
         var vtile = new mapnik.VectorTile(0,0,0);
         assert.equal(vtile.empty(), true);
@@ -1400,12 +1409,19 @@ describe('mapnik.VectorTile ', function() {
         });
     });
 
-    it('should return empty and have layer name', function() {
+    it('should not return empty and will have layer name', function() {
         var vtile = new mapnik.VectorTile(0,0,0);
-        // a layer with only a name "layer-name" and no features
-        // during v1 to v2 conversion this will be dropped, it is assumed
-        // to be v1 because it has no version!
         vtile.setData(new Buffer('1A0C0A0A6C617965722D6E616D65', 'hex'));
+        assert.deepEqual(vtile.names(), ['layer-name']);
+        assert.equal(vtile.empty(), false);
+    });
+
+    it('should return empty and have no layer name when upgraded', function() {
+        var vtile = new mapnik.VectorTile(0,0,0);
+        vtile.setData(new Buffer('1A0C0A0A6C617965722D6E616D65', 'hex'),{upgrade:true});
+        // a layer with only a name "layer-name" and no features
+        // during v1 to v2 conversion this will be dropped
+        // note: this tile also lacks a version, but mapnik-vt defaults to assuming v1
         assert.deepEqual(vtile.names(), []);
         assert.equal(vtile.empty(), true);
     });

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/collab-maint/node-mapnik.git



More information about the Pkg-javascript-commits mailing list