UNPKG

@mapgis/geojson-vt

Version:

Slice GeoJSON data into vector tiles efficiently

122 lines (103 loc) 3.8 kB
export default function createTile(features, z, tx, ty, options) { const tolerance = z === options.maxZoom ? 0 : options.tolerance / ((1 << z) * options.extent); const tile = { features: [], numPoints: 0, numSimplified: 0, numFeatures: features.length, source: null, x: tx, y: ty, z, transformed: false, minX: Infinity, minY: Infinity, maxX: -Infinity, maxY: -Infinity }; for (const feature of features) { addFeature(tile, feature, tolerance, options); } return tile; } function addFeature(tile, feature, tolerance, options) { const geom = feature.geometry; const type = feature.type; const simplified = []; tile.minX = Math.min(tile.minX, feature.minX); tile.minY = Math.min(tile.minY, feature.minY); tile.maxX = Math.max(tile.maxX, feature.maxX); tile.maxY = Math.max(tile.maxY, feature.maxY); if (type === 'Point' || type === 'MultiPoint') { for (let i = 0; i < geom.length; i += 3) { simplified.push(geom[i], geom[i + 1]); tile.numPoints++; tile.numSimplified++; } } else if (type === 'LineString') { addLine(simplified, geom, tile, tolerance, false, false); } else if (type === 'MultiLineString' || type === 'Polygon') { for (let i = 0; i < geom.length; i++) { addLine(simplified, geom[i], tile, tolerance, type === 'Polygon', i === 0); } } else if (type === 'MultiPolygon') { for (let k = 0; k < geom.length; k++) { const polygon = geom[k]; for (let i = 0; i < polygon.length; i++) { addLine(simplified, polygon[i], tile, tolerance, true, i === 0); } } } if (simplified.length) { let tags = feature.tags || null; if (type === 'LineString' && options.lineMetrics) { tags = {}; for (const key in feature.tags) tags[key] = feature.tags[key]; tags['mapbox_clip_start'] = geom.start / geom.size; tags['mapbox_clip_end'] = geom.end / geom.size; } const tileFeature = { geometry: simplified, type: type === 'Polygon' || type === 'MultiPolygon' ? 3 : (type === 'LineString' || type === 'MultiLineString' ? 2 : 1), tags }; if (feature.id !== null) { tileFeature.id = feature.id; } tile.features.push(tileFeature); } } function addLine(result, geom, tile, tolerance, isPolygon, isOuter) { const sqTolerance = tolerance * tolerance; if (tolerance > 0 && (geom.size < (isPolygon ? sqTolerance : tolerance))) { tile.numPoints += geom.length / 3; return; } const ring = []; for (let i = 0; i < geom.length; i += 3) { if (tolerance === 0 || geom[i + 2] > sqTolerance) { tile.numSimplified++; ring.push(geom[i], geom[i + 1]); } tile.numPoints++; } if (isPolygon) rewind(ring, isOuter); result.push(ring); } function rewind(ring, clockwise) { let area = 0; for (let i = 0, len = ring.length, j = len - 2; i < len; j = i, i += 2) { area += (ring[i] - ring[j]) * (ring[i + 1] + ring[j + 1]); } if (area > 0 === clockwise) { for (let i = 0, len = ring.length; i < len / 2; i += 2) { const x = ring[i]; const y = ring[i + 1]; ring[i] = ring[len - 2 - i]; ring[i + 1] = ring[len - 1 - i]; ring[len - 2 - i] = x; ring[len - 1 - i] = y; } } }