UNPKG

geojson-vt

Version:

Slice GeoJSON data into vector tiles efficiently

140 lines (118 loc) 3.87 kB
'use strict'; module.exports = convert; var simplify = require('./simplify'); // converts GeoJSON feature into an intermediate JSON vector format with projection & simplification function convert(data, tolerance) { var features = []; if (data.type === 'FeatureCollection') { for (var i = 0; i < data.features.length; i++) { convertFeature(features, data.features[i], tolerance); } } else if (data.type === 'Feature') { convertFeature(features, data, tolerance); } else { convertFeature(features, {geometry: data}, tolerance); } return features; } function convertFeature(features, feature, tolerance) { var geom = feature.geometry, type = geom.type, coords = geom.coordinates, tags = feature.properties, i, j, rings; if (type === 'Point') { features.push(create(tags, 1, [projectPoint(coords)])); } else if (type === 'MultiPoint') { features.push(create(tags, 1, project(coords))); } else if (type === 'LineString') { features.push(create(tags, 2, [project(coords, tolerance)])); } else if (type === 'MultiLineString' || type === 'Polygon') { rings = []; for (i = 0; i < coords.length; i++) { rings.push(project(coords[i], tolerance)); } features.push(create(tags, type === 'Polygon' ? 3 : 2, rings)); } else if (type === 'MultiPolygon') { rings = []; for (i = 0; i < coords.length; i++) { for (j = 0; j < coords[i].length; j++) { rings.push(project(coords[i][j], tolerance)); } } features.push(create(tags, 3, rings)); } else if (type === 'GeometryCollection') { for (i = 0; i < geom.geometries.length; i++) { convertFeature(features, { geometry: geom.geometries[i], properties: tags }, tolerance); } } else { console.warn('Unsupported GeoJSON type: ' + geom.type); } } function create(tags, type, geometry) { var feature = { geometry: geometry, type: type, tags: tags || null, min: [1, 1], max: [0, 0] }; calcBBox(feature); return feature; } function project(lonlats, tolerance) { var projected = []; for (var i = 0; i < lonlats.length; i++) { projected.push(projectPoint(lonlats[i])); } if (tolerance) { simplify(projected, tolerance); calcSize(projected); } return projected; } function projectPoint(p) { var sin = Math.sin(p[1] * Math.PI / 180), x = (p[0] / 360 + 0.5), y = (0.5 - 0.25 * Math.log((1 + sin) / (1 - sin)) / Math.PI); return [x, y, 0]; } // calculate area and length of the poly function calcSize(points) { var sum = 0, dist = 0; for (var i = 0, a, b; i < points.length - 1; i++) { a = b || points[i]; b = points[i + 1]; sum += a[0] * b[1] - b[0] * a[1]; dist += Math.abs(b[0] - a[0]) + Math.abs(b[1] - a[1]); // Manhattan distance } points.area = Math.abs(sum / 2); points.dist = dist; } // calculate the feature bounding box for faster clipping later function calcBBox(feature) { var geometry = feature.geometry, min = feature.min, max = feature.max; if (feature.type === 1) { calcRingBBOX(min, max, geometry); } else { for (var i = 0; i < geometry.length; i++) { calcRingBBOX(min, max, geometry[i]); } } return feature; } function calcRingBBOX(min, max, points) { for (var i = 0, p; i < points.length; i++) { p = points[i]; min[0] = Math.min(p[0], min[0]); max[0] = Math.max(p[0], max[0]); min[1] = Math.min(p[1], min[1]); max[1] = Math.max(p[1], max[1]); } }