Skip to content

Commit

Permalink
Bump to v3.5.1, added new info method to mapnik.VectorTile [publish b…
Browse files Browse the repository at this point in the history
…inary]
  • Loading branch information
flippmoke committed Mar 1, 2016
1 parent 5444ce6 commit 511612a
Show file tree
Hide file tree
Showing 5 changed files with 236 additions and 4 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,10 @@
# Changelog

## 3.5.1

- Added the `mapnik.VectorTile.info` command that returns an object that inspects buffers and provides information about vector tiles.
- Updated `mapnik-vector-tile` to `1.0.2`

## 3.5.0

This is a major update and reflects a large number of changes added into node-mapnik due to update of the [Mapbox Vector Tile Specification](https://github.com/mapbox/vector-tile-spec). As part of this the [mapnik-vector-tile library](https://github.com/mapbox/mapnik-vector-tile) was updated to `1.0.0`. Therefore, a large number of interfaces changes have taken place around the `mapnik.VectorTile` object.
Expand Down
4 changes: 2 additions & 2 deletions package.json
Expand Up @@ -4,7 +4,7 @@
"url": "http://github.com/mapnik/node-mapnik",
"homepage": "http://mapnik.org",
"author": "Dane Springmeyer <dane@mapbox.com> (mapnik.org)",
"version": "3.5.0",
"version": "3.5.1",
"main": "./lib/mapnik.js",
"binary": {
"module_name": "mapnik",
Expand Down Expand Up @@ -40,7 +40,7 @@
}
],
"dependencies": {
"mapnik-vector-tile": "1.0.1",
"mapnik-vector-tile": "1.0.2",
"nan": "~2.2.0",
"node-pre-gyp": "~0.6.22",
"protozero": "~1.3.0"
Expand Down
162 changes: 162 additions & 0 deletions src/mapnik_vector_tile.cpp
Expand Up @@ -313,6 +313,8 @@ void VectorTile::Initialize(v8::Local<v8::Object> target)
ATTR(lcons, "tileSize", get_tile_size, set_tile_size);
ATTR(lcons, "bufferSize", get_buffer_size, set_buffer_size);

Nan::SetMethod(lcons->GetFunction(), "info", info);

target->Set(Nan::New("VectorTile").ToLocalChecked(),lcons->GetFunction());
constructor.Reset(lcons);
}
Expand Down Expand Up @@ -5747,3 +5749,163 @@ NAN_SETTER(VectorTile::set_buffer_size)
d->tile_->buffer_size(val);
}
}

typedef struct {
uv_work_t request;
const char *data;
size_t dataLength;
v8::Local<v8::Object> obj;
bool error;
std::string error_str;
Nan::Persistent<v8::Object> buffer;
Nan::Persistent<v8::Function> cb;
} vector_tile_info_baton_t;

/**
* Return an object containing information about a vector tile buffer. (synchronous)
*
* @name info
* @param {Buffer} buffer - vector tile buffer
* @returns {Object} json object with information about the vector tile buffer
* @instance
* @memberof mapnik.VectorTile
* @example
* var buffer = fs.readFileSync('./path/to/vtile.mvt');
* var info = mapnik.VectorTile.info(buffer);
*/
NAN_METHOD(VectorTile::info)
{
if (info.Length() < 1 || !info[0]->IsObject())
{
Nan::ThrowTypeError("must provide a buffer argument");
return;
}

v8::Local<v8::Object> obj = info[0]->ToObject();
if (obj->IsNull() || obj->IsUndefined() || !node::Buffer::HasInstance(obj))
{
Nan::ThrowTypeError("first argument is invalid, must be a Buffer");
return;
}

v8::Local<v8::Object> out = Nan::New<v8::Object>();
v8::Local<v8::Array> layers = Nan::New<v8::Array>();
std::set<mapnik::vector_tile_impl::validity_error> errors;
bool has_errors = false;
std::size_t layers_size = 0;
bool first_layer = true;
std::set<std::string> layer_names_set;
std::uint32_t version = 1;
protozero::pbf_reader tile_msg;
std::string decompressed;
try
{
if (mapnik::vector_tile_impl::is_gzip_compressed(node::Buffer::Data(obj),node::Buffer::Length(obj)) ||
mapnik::vector_tile_impl::is_zlib_compressed(node::Buffer::Data(obj),node::Buffer::Length(obj)))
{
mapnik::vector_tile_impl::zlib_decompress(node::Buffer::Data(obj), node::Buffer::Length(obj), decompressed);
tile_msg = protozero::pbf_reader(decompressed);
}
else
{
tile_msg = protozero::pbf_reader(node::Buffer::Data(obj),node::Buffer::Length(obj));
}
while (tile_msg.next())
{
switch (tile_msg.tag())
{
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;
std::set<mapnik::vector_tile_impl::validity_error> layer_errors;
mapnik::vector_tile_impl::layer_is_valid(layer_msg,
layer_errors,
layer_name,
layer_version,
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 +
raster_feature_count;
if (!layer_name.empty())
{
auto p = layer_names_set.insert(layer_name);
if (!p.second)
{
errors.insert(mapnik::vector_tile_impl::TILE_REPEATED_LAYER_NAMES);
}
layer_obj->Set(Nan::New("name").ToLocalChecked(), Nan::New<v8::String>(layer_name).ToLocalChecked());
}
layer_obj->Set(Nan::New("features").ToLocalChecked(), Nan::New<v8::Number>(feature_count));
layer_obj->Set(Nan::New("point_features").ToLocalChecked(), Nan::New<v8::Number>(point_feature_count));
layer_obj->Set(Nan::New("linestring_features").ToLocalChecked(), Nan::New<v8::Number>(line_feature_count));
layer_obj->Set(Nan::New("polygon_features").ToLocalChecked(), Nan::New<v8::Number>(polygon_feature_count));
layer_obj->Set(Nan::New("unknown_features").ToLocalChecked(), Nan::New<v8::Number>(unknown_feature_count));
layer_obj->Set(Nan::New("raster_features").ToLocalChecked(), Nan::New<v8::Number>(raster_feature_count));
layer_obj->Set(Nan::New("version").ToLocalChecked(), Nan::New<v8::Number>(layer_version));
if (!layer_errors.empty())
{
has_errors = true;
v8::Local<v8::Array> err_arr = Nan::New<v8::Array>();
std::size_t i = 0;
for (auto const& e : layer_errors)
{
err_arr->Set(i++, Nan::New<v8::String>(mapnik::vector_tile_impl::validity_error_to_string(e)).ToLocalChecked());
}
layer_obj->Set(Nan::New("errors").ToLocalChecked(), err_arr);
}
if (first_layer)
{
version = layer_version;
}
else
{
if (version != layer_version)
{
errors.insert(mapnik::vector_tile_impl::TILE_HAS_DIFFERENT_VERSIONS);
}
}
first_layer = false;
layers->Set(layers_size++, layer_obj);
}
break;
default:
errors.insert(mapnik::vector_tile_impl::TILE_HAS_UNKNOWN_TAG);
tile_msg.skip();
break;
}
}
}
catch (...)
{
errors.insert(mapnik::vector_tile_impl::INVALID_PBF_BUFFER);
}
out->Set(Nan::New("layers").ToLocalChecked(), layers);
has_errors = has_errors || !errors.empty();
out->Set(Nan::New("errors").ToLocalChecked(), Nan::New<v8::Boolean>(has_errors));
if (!errors.empty())
{
v8::Local<v8::Array> err_arr = Nan::New<v8::Array>();
std::size_t i = 0;
for (auto const& e : errors)
{
err_arr->Set(i++, Nan::New<v8::String>(mapnik::vector_tile_impl::validity_error_to_string(e)).ToLocalChecked());
}
out->Set(Nan::New("tile_errors").ToLocalChecked(), err_arr);
}
info.GetReturnValue().Set(out);
return;
}
1 change: 1 addition & 0 deletions src/mapnik_vector_tile.hpp
Expand Up @@ -123,6 +123,7 @@ class VectorTile: public Nan::ObjectWrap
static void EIO_Clear(uv_work_t* req);
static void EIO_AfterClear(uv_work_t* req);
static NAN_METHOD(empty);
static NAN_METHOD(info);
#if BOOST_VERSION >= 105800
static NAN_METHOD(reportGeometrySimplicity);
static void EIO_ReportGeometrySimplicity(uv_work_t* req);
Expand Down
68 changes: 66 additions & 2 deletions test/vector-tile.test.js
Expand Up @@ -1217,7 +1217,7 @@ describe('mapnik.VectorTile ', function() {
});
});

it('should error on bogus gzip data', function(done) {
it('setData should error on bogus gzip data', function(done) {
var vtile = new mapnik.VectorTile(0,0,0);
var fake_gzip = new Buffer(30);
fake_gzip.fill(0);
Expand All @@ -1230,7 +1230,7 @@ describe('mapnik.VectorTile ', function() {
});
});

it('should error on bogus zlib data', function(done) {
it('setData should error on bogus zlib data', function(done) {
var vtile = new mapnik.VectorTile(0,0,0);
var fake_zlib = new Buffer(30);
fake_zlib.fill(0);
Expand All @@ -1242,6 +1242,70 @@ describe('mapnik.VectorTile ', function() {
done();
});
});

it('info should throw with invalid use', function() {
assert.throws(function() { mapnik.VetorTile.info(); });
assert.throws(function() { mapnik.VetorTile.info(null); });
assert.throws(function() { mapnik.VetorTile.info({}); });
});

it('info should show error on bogus gzip data', function() {
var fake_gzip = new Buffer(30);
fake_gzip.fill(0);
fake_gzip[0] = 0x1F;
fake_gzip[1] = 0x8B;
var out = mapnik.VectorTile.info(fake_gzip);
assert(out.errors);
assert.equal(out.layers.length, 0);
assert.equal(out.tile_errors.length, 1);
assert.equal(out.tile_errors[0], 'Buffer is not encoded as a valid PBF');
});

it('info should show error on bogus zlib data', function() {
var fake_zlib = new Buffer(30);
fake_zlib.fill(0);
fake_zlib[0] = 0x78;
fake_zlib[1] = 0x9C;
var out = mapnik.VectorTile.info(fake_zlib);
assert(out.errors);
assert.equal(out.layers.length, 0);
assert.equal(out.tile_errors.length, 1);
assert.equal(out.tile_errors[0], 'Buffer is not encoded as a valid PBF');
});

it('info should show problems with invalid v2 tile', function() {
var badTile = fs.readFileSync(path.resolve(__dirname + '/data/vector_tile/invalid_v2_tile.mvt'));
var out = mapnik.VectorTile.info(badTile);
assert(out.errors);
assert.equal(out.layers.length, 23);
assert.equal(out.tile_errors, undefined);
assert.equal(out.layers[0].name, 'landuse');
assert.equal(out.layers[0].features, 140);
assert.equal(out.layers[0].point_features, 0);
assert.equal(out.layers[0].linestring_features, 2);
assert.equal(out.layers[0].polygon_features, 138);
assert.equal(out.layers[0].unknown_features, 0);
assert.equal(out.layers[0].raster_features, 0);
assert.equal(out.layers[0].version, 2);
assert.equal(out.layers[0].errors, undefined);
assert.equal(out.layers[4].name, 'barrier_line');
assert.equal(out.layers[4].features, 0);
assert.equal(out.layers[4].point_features, 0);
assert.equal(out.layers[4].linestring_features, 0);
assert.equal(out.layers[4].polygon_features, 0);
assert.equal(out.layers[4].unknown_features, 0);
assert.equal(out.layers[4].raster_features, 0);
assert.equal(out.layers[4].version, 2);
assert.equal(out.layers[4].errors.length, 1);
assert.equal(out.layers[4].errors[0], 'Vector Tile Layer message has no features');
});

it('should not have errors if we pass a valid vector tile to info', function() {
var data = fs.readFileSync("./test/data/vector_tile/tile1.vector.pbf.gz");
var out = mapnik.VectorTile.info(data);
assert.equal(out.errors, false);
assert.equal(out.layers.length, 2);
});

it('should error out if we pass invalid data to setData - 1', function(done) {
var vtile = new mapnik.VectorTile(0,0,0);
Expand Down

0 comments on commit 511612a

Please sign in to comment.