vector-tile
Advanced tools
Comparing version 1.2.0 to 1.2.1
## vector-tile-js changelog | ||
### 1.2.1 (2016-05-18) | ||
- Fixed geometry structure of MultiPoints, Polygons, and MultiPolygons in toGeoJSON() | ||
### 1.2.0 (2015-12-10) | ||
@@ -4,0 +8,0 @@ |
@@ -5,3 +5,3 @@ var mapnik = require('mapnik'); | ||
mapnik.register_datasource(path.join(mapnik.settings.paths.input_plugins,'geojson.input')); | ||
mapnik.register_datasource(path.join(mapnik.settings.paths.input_plugins, 'geojson.input')); | ||
@@ -35,2 +35,15 @@ var fixtures = { | ||
}, | ||
"zero-polygon": { | ||
"type": "FeatureCollection", | ||
"features": [ | ||
{ | ||
"type": "Feature", | ||
"geometry": { | ||
"type": "MultiPolygon", | ||
"coordinates": [] | ||
}, | ||
"properties": {} | ||
} | ||
] | ||
}, | ||
"singleton-multi-point": { | ||
@@ -62,2 +75,15 @@ "type": "FeatureCollection", | ||
}, | ||
"singleton-multi-polygon": { | ||
"type": "FeatureCollection", | ||
"features": [ | ||
{ | ||
"type": "Feature", | ||
"geometry": { | ||
"type": "MultiPolygon", | ||
"coordinates": [[[[0, 0], [1, 0], [1, 1], [0, 0]]]] | ||
}, | ||
"properties": {} | ||
} | ||
] | ||
}, | ||
"multi-point": { | ||
@@ -88,2 +114,41 @@ "type": "FeatureCollection", | ||
] | ||
}, | ||
"multi-polygon": { | ||
"type": "FeatureCollection", | ||
"features": [ | ||
{ | ||
"type": "Feature", | ||
"geometry": { | ||
"type": "MultiPolygon", | ||
"coordinates": [[[[0, 0], [1, 0], [1, 1], [0, 0]]], [[[0, 0], [-1, 0], [-1, -1], [0, 0]]]] | ||
}, | ||
"properties": {} | ||
} | ||
] | ||
}, | ||
"polygon-with-inner": { | ||
"type": "FeatureCollection", | ||
"features": [ | ||
{ | ||
"type": "Feature", | ||
"geometry": { | ||
"type": "Polygon", | ||
"coordinates": [[[-2, 2], [2, 2], [2, -2], [-2, -2], [-2, 2]], [[-1, 1], [1, 1], [1, -1], [-1, -1], [-1, 1]]] | ||
}, | ||
"properties": {} | ||
} | ||
] | ||
}, | ||
"stacked-multipolygon": { | ||
"type": "FeatureCollection", | ||
"features": [ | ||
{ | ||
"type": "Feature", | ||
"geometry": { | ||
"type": "MultiPolygon", | ||
"coordinates": [[[[-2, 2], [2, 2], [2, -2], [-2, -2], [-2, 2]]], [[[-1, 1], [1, 1], [1, -1], [-1, -1], [-1, 1]]]] | ||
}, | ||
"properties": {} | ||
} | ||
] | ||
} | ||
@@ -93,5 +158,5 @@ } | ||
for (var fixture in fixtures) { | ||
var vtile = new mapnik.VectorTile(0,0,0); | ||
var vtile = new mapnik.VectorTile(0, 0, 0); | ||
vtile.addGeoJSON(JSON.stringify(fixtures[fixture]), "geojson"); | ||
fs.writeFileSync('./test/fixtures/' + fixture + '.pbf', vtile.getData()); | ||
} |
@@ -134,6 +134,6 @@ 'use strict'; | ||
coords = this.loadGeometry(), | ||
type = VectorTileFeature.types[this.type]; | ||
type = VectorTileFeature.types[this.type], | ||
i, j; | ||
for (var i = 0; i < coords.length; i++) { | ||
var line = coords[i]; | ||
function project(line) { | ||
for (var j = 0; j < line.length; j++) { | ||
@@ -148,11 +148,32 @@ var p = line[j], y2 = 180 - (p.y + y0) * 360 / size; | ||
if (type === 'Point' && coords.length === 1) { | ||
coords = coords[0][0]; | ||
} else if (type === 'Point') { | ||
switch (this.type) { | ||
case 1: | ||
var points = []; | ||
for (i = 0; i < coords.length; i++) { | ||
points[i] = coords[i][0]; | ||
} | ||
coords = points; | ||
project(coords); | ||
break; | ||
case 2: | ||
for (i = 0; i < coords.length; i++) { | ||
project(coords[i]); | ||
} | ||
break; | ||
case 3: | ||
coords = classifyRings(coords); | ||
for (i = 0; i < coords.length; i++) { | ||
for (j = 0; j < coords[i].length; j++) { | ||
project(coords[i][j]); | ||
} | ||
} | ||
break; | ||
} | ||
if (coords.length === 1) { | ||
coords = coords[0]; | ||
type = 'MultiPoint'; | ||
} else if (type === 'LineString' && coords.length === 1) { | ||
coords = coords[0]; | ||
} else if (type === 'LineString') { | ||
type = 'MultiLineString'; | ||
} else { | ||
type = 'Multi' + type; | ||
} | ||
@@ -175,1 +196,41 @@ | ||
}; | ||
// classifies an array of rings into polygons with outer rings and holes | ||
function classifyRings(rings) { | ||
var len = rings.length; | ||
if (len <= 1) return [rings]; | ||
var polygons = [], | ||
polygon, | ||
ccw; | ||
for (var i = 0; i < len; i++) { | ||
var area = signedArea(rings[i]); | ||
if (area === 0) continue; | ||
if (ccw === undefined) ccw = area < 0; | ||
if (ccw === area < 0) { | ||
if (polygon) polygons.push(polygon); | ||
polygon = [rings[i]]; | ||
} else { | ||
polygon.push(rings[i]); | ||
} | ||
} | ||
if (polygon) polygons.push(polygon); | ||
return polygons; | ||
} | ||
function signedArea(ring) { | ||
var sum = 0; | ||
for (var i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) { | ||
p1 = ring[i]; | ||
p2 = ring[j]; | ||
sum += (p2.x - p1.x) * (p1.y + p2.y); | ||
} | ||
return sum; | ||
} |
@@ -5,3 +5,3 @@ { | ||
"repository": "https://github.com/mapbox/vector-tile-js.git", | ||
"version": "1.2.0", | ||
"version": "1.2.1", | ||
"license": "BSD", | ||
@@ -16,6 +16,8 @@ "main": "index.js", | ||
"istanbul": "~0.3.6", | ||
"mapnik": "^3.1.6", | ||
"mapnik": "^3.5.13", | ||
"jshint": "^2.6.3", | ||
"pbf": "^1.3.2", | ||
"tape": "~3.5.0" | ||
"tape": "~3.5.0", | ||
"eslint": "~1.00.0", | ||
"eslint-config-unstyled": "^1.1.0" | ||
}, | ||
@@ -30,5 +32,5 @@ "jshintConfig": { | ||
"scripts": { | ||
"test": "jshint lib && tape test/parse.test.js", | ||
"test": "eslint lib index.js && jshint lib && tape test/parse.test.js", | ||
"cov": "istanbul cover ./node_modules/.bin/tape test/parse.test.js && coveralls < ./coverage/lcov.info" | ||
} | ||
} | ||
} |
@@ -8,2 +8,28 @@ var test = require('tape'), | ||
function approximateDeepEqual(a, b, epsilon) { | ||
epsilon = epsilon || 1e-6; | ||
if (typeof a !== typeof b) | ||
return false; | ||
if (typeof a === 'number') | ||
return Math.abs(a - b) < epsilon; | ||
if (a === null || typeof a !== 'object') | ||
return a === b; | ||
var ka = Object.keys(a); | ||
var kb = Object.keys(b); | ||
if (ka.length != kb.length) | ||
return false; | ||
ka.sort(); | ||
kb.sort(); | ||
for (var i = 0; i < ka.length; i++) | ||
if (ka[i] != kb[i] || !approximateDeepEqual(a[ka[i]], b[ka[i]], epsilon)) | ||
return false; | ||
return true; | ||
} | ||
test('parsing vector tiles', function(t) { | ||
@@ -63,55 +89,53 @@ var data = fs.readFileSync(__dirname + '/fixtures/14-8801-5371.vector.pbf'); | ||
function close(actual, expected) { | ||
t.equal(actual.length, expected.length); | ||
for (var i = 0; i < actual.length; i++) { | ||
if (actual[i].length) { | ||
close(actual[i], expected[i]); | ||
} else { | ||
t.ok(Math.abs(actual[i] - expected[i]) < 1e-6); | ||
} | ||
t.ok(approximateDeepEqual(tile.layers.poi_label.feature(11).toGeoJSON(8801, 5371, 14), { | ||
type: 'Feature', | ||
id: 3000003150561, | ||
properties: { | ||
localrank: 1, | ||
maki: 'park', | ||
name: 'Mauerpark', | ||
name_de: 'Mauerpark', | ||
name_en: 'Mauerpark', | ||
name_es: 'Mauerpark', | ||
name_fr: 'Mauerpark', | ||
osm_id: 3000003150561, | ||
ref: '', | ||
scalerank: 2, | ||
type: 'Park' | ||
}, | ||
geometry: { | ||
type: 'Point', | ||
coordinates: [13.402258157730103, 52.54398925380624] | ||
} | ||
} | ||
})); | ||
var point = tile.layers.poi_label.feature(11).toGeoJSON(8801, 5371, 14); | ||
t.deepEqual(point.type, 'Feature'); | ||
t.deepEqual(point.id, 3000003150561); | ||
t.deepEqual(point.properties, { | ||
localrank: 1, | ||
maki: 'park', | ||
name: 'Mauerpark', | ||
name_de: 'Mauerpark', | ||
name_en: 'Mauerpark', | ||
name_es: 'Mauerpark', | ||
name_fr: 'Mauerpark', | ||
osm_id: 3000003150561, | ||
ref: '', | ||
scalerank: 2, | ||
type: 'Park' | ||
}); | ||
t.deepEqual(point.geometry.type, 'Point'); | ||
close(point.geometry.coordinates, [13.402258157730103, 52.54398925380624]); | ||
t.ok(approximateDeepEqual(tile.layers.bridge.feature(0).toGeoJSON(8801, 5371, 14), { | ||
type: 'Feature', | ||
id: 238162948, | ||
properties: { | ||
class: 'service', | ||
oneway: 0, | ||
osm_id: 238162948, | ||
type: 'service' | ||
}, | ||
geometry: { | ||
type: 'LineString', | ||
coordinates: [[13.399457931518555, 52.546334844036416], [13.399441838264465, 52.546504478525016]] | ||
} | ||
})); | ||
var line = tile.layers.bridge.feature(0).toGeoJSON(8801, 5371, 14); | ||
t.deepEqual(line.type, 'Feature'); | ||
t.deepEqual(line.properties, { | ||
class: 'service', | ||
oneway: 0, | ||
osm_id: 238162948, | ||
type: 'service' | ||
}); | ||
t.deepEqual(line.geometry.type, 'LineString'); | ||
close(line.geometry.coordinates, | ||
[[13.399457931518555, 52.546334844036416], [13.399441838264465, 52.546504478525016]]); | ||
t.ok(approximateDeepEqual(tile.layers.building.feature(0).toGeoJSON(8801, 5371, 14), { | ||
type: 'Feature', | ||
id: 1000267229912, | ||
properties: { | ||
osm_id: 1000267229912 | ||
}, | ||
geometry: { | ||
type: 'Polygon', | ||
coordinates: [[[13.392285704612732, 52.54974045706258], [13.392264246940613, 52.549737195107554], | ||
[13.392248153686523, 52.549737195107554], [13.392248153686523, 52.54974045706258], | ||
[13.392285704612732, 52.54974045706258]]] | ||
} | ||
})); | ||
var poly = tile.layers.building.feature(0).toGeoJSON(8801, 5371, 14); | ||
t.deepEqual(poly.type, 'Feature'); | ||
t.deepEqual(poly.properties, { | ||
osm_id: 1000267229912 | ||
}); | ||
t.deepEqual(poly.geometry.type, 'Polygon'); | ||
close(poly.geometry.coordinates, | ||
[[[13.392285704612732, 52.54974045706258], [13.392264246940613, 52.549737195107554], | ||
[13.392248153686523, 52.549737195107554], [13.392248153686523, 52.54974045706258], | ||
[13.392285704612732, 52.54974045706258]]]); | ||
function geoJSONFromFixture(name) { | ||
@@ -123,8 +147,38 @@ var tile = new VectorTile(new Protobuf(fs.readFileSync(__dirname + '/fixtures/' + name + '.pbf'))); | ||
// https://github.com/mapbox/vector-tile-spec/issues/30 | ||
t.equal(geoJSONFromFixture("singleton-multi-point").geometry.type, 'Point'); | ||
t.equal(geoJSONFromFixture("singleton-multi-line").geometry.type, 'LineString'); | ||
t.ok(approximateDeepEqual(geoJSONFromFixture("singleton-multi-point").geometry, { | ||
type: 'Point', | ||
coordinates: [1, 2] | ||
}, 1e-1)); | ||
t.ok(approximateDeepEqual(geoJSONFromFixture("singleton-multi-line").geometry, { | ||
type: 'LineString', | ||
coordinates: [[1, 2], [3, 4]] | ||
}, 1e-1)); | ||
t.ok(approximateDeepEqual(geoJSONFromFixture("singleton-multi-polygon").geometry, { | ||
type: 'Polygon', | ||
coordinates: [[[1, 0], [0, 0], [1, 1], [1, 0]]] | ||
}, 1e-1)); | ||
t.equal(geoJSONFromFixture("multi-point").geometry.type, 'MultiPoint'); | ||
t.equal(geoJSONFromFixture("multi-line").geometry.type, 'MultiLineString'); | ||
t.ok(approximateDeepEqual(geoJSONFromFixture("multi-point").geometry, { | ||
type: 'MultiPoint', | ||
coordinates: [[1, 2], [3, 4]] | ||
}, 1e-1)); | ||
t.ok(approximateDeepEqual(geoJSONFromFixture("multi-line").geometry, { | ||
type: 'MultiLineString', | ||
coordinates: [[[1, 2], [3, 4]], [[5, 6], [7, 8]]] | ||
}, 1e-1)); | ||
t.ok(approximateDeepEqual(geoJSONFromFixture("multi-polygon").geometry, { | ||
type: 'MultiPolygon', | ||
coordinates: [[[[1, 0], [0, 0], [1, 1], [1, 0]]], [[[-1, -1], [-1, 0], [0, 0], [-1, -1]]]] | ||
}, 1e-1)); | ||
// https://github.com/mapbox/vector-tile-js/issues/32 | ||
t.ok(approximateDeepEqual(geoJSONFromFixture("polygon-with-inner").geometry, { | ||
type: 'Polygon', | ||
coordinates: [[[2, -2], [-2, -2], [-2, 2], [2, 2], [2, -2]], [[-1, 1], [-1, -1], [1, -1], [1, 1], [-1, 1]]] | ||
}, 1e-1)); | ||
t.ok(approximateDeepEqual(geoJSONFromFixture("stacked-multipolygon").geometry, { | ||
type: 'MultiPolygon', | ||
coordinates: [[[[2, -2], [-2, -2], [-2, 2], [2, 2], [2, -2]]], [[[1, -1], [-1, -1], [-1, 1], [1, 1], [1, -1]]]] | ||
}, 1e-1)); | ||
t.end(); | ||
@@ -131,0 +185,0 @@ }) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
261071
30
609
9