@loaders.gl/mvt
Version:
Loader for Mapbox Vector Tiles
1,687 lines (1,666 loc) • 65.2 kB
JavaScript
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
// dist/index.js
var dist_exports = {};
__export(dist_exports, {
MVTLoader: () => MVTLoader,
MVTSource: () => MVTSource,
MVTWorkerLoader: () => MVTWorkerLoader,
TableTileSource: () => TableTileSource,
TileJSONLoader: () => TileJSONLoader
});
module.exports = __toCommonJS(dist_exports);
// dist/lib/get-schemas-from-tilejson.js
function getSchemaFromTileJSONLayer(layer) {
const fields = [];
if (layer.fields) {
for (const field of layer.fields) {
fields.push({
name: field.name,
type: getDataTypeFromTileJSONField(field),
metadata: getMetadataFromTileJSONField(field)
});
}
}
return {
metadata: getMetadataFromTileJSONLayer(layer),
fields
};
}
function getMetadataFromTileJSONLayer(layer) {
const metadata = {};
for (const [key, value] of Object.entries(layer)) {
if (key !== "fields" && value) {
metadata[key] = JSON.stringify(value);
}
}
return metadata;
}
function getDataTypeFromTileJSONField(field) {
switch (field.type.toLowerCase()) {
case "float32":
return "float32";
case "number":
case "float64":
return "float64";
case "string":
case "utf8":
return "utf8";
case "boolean":
return "bool";
default:
return "null";
}
}
function getMetadataFromTileJSONField(field) {
const metadata = {};
for (const [key, value] of Object.entries(field)) {
if (key !== "name" && value) {
metadata[key] = JSON.stringify(value);
}
}
return metadata;
}
// dist/lib/parse-tilejson.js
var isObject = (x) => x !== null && typeof x === "object";
function parseTileJSON(jsonMetadata, options) {
var _a;
if (!jsonMetadata || !isObject(jsonMetadata)) {
return null;
}
let tileJSON = {
name: jsonMetadata.name || "",
description: jsonMetadata.description || ""
};
if (typeof jsonMetadata.generator === "string") {
tileJSON.generator = jsonMetadata.generator;
}
if (typeof jsonMetadata.generator_options === "string") {
tileJSON.generatorOptions = jsonMetadata.generator_options;
}
tileJSON.boundingBox = parseBounds(jsonMetadata.bounds) || parseBounds(jsonMetadata.antimeridian_adjusted_bounds);
tileJSON.center = parseCenter(jsonMetadata.center);
tileJSON.maxZoom = safeParseFloat(jsonMetadata.maxzoom);
tileJSON.minZoom = safeParseFloat(jsonMetadata.minzoom);
if (typeof (jsonMetadata == null ? void 0 : jsonMetadata.json) === "string") {
try {
tileJSON.metaJson = JSON.parse(jsonMetadata.json);
} catch (error) {
console.warn("Failed to parse tilejson.json field", error);
}
}
const tilestats = jsonMetadata.tilestats || ((_a = tileJSON.metaJson) == null ? void 0 : _a.tilestats);
const tileStatsLayers = parseTilestatsLayers(tilestats, options);
const tileJSONlayers = parseTileJSONLayers(jsonMetadata.vector_layers);
const layers = mergeLayers(tileJSONlayers, tileStatsLayers);
tileJSON = {
...tileJSON,
layers
};
if (tileJSON.maxZoom === null && layers.length > 0) {
tileJSON.maxZoom = layers[0].maxZoom || null;
}
if (tileJSON.minZoom === null && layers.length > 0) {
tileJSON.minZoom = layers[0].minZoom || null;
}
return tileJSON;
}
function parseTileJSONLayers(layers) {
if (!Array.isArray(layers)) {
return [];
}
return layers.map((layer) => parseTileJSONLayer(layer));
}
function parseTileJSONLayer(layer) {
const fields = Object.entries(layer.fields || []).map(([key, datatype]) => ({
name: key,
...attributeTypeToFieldType(String(datatype))
}));
const layer2 = { ...layer };
delete layer2.fields;
return {
name: layer.id || "",
...layer2,
fields
};
}
function parseTilestatsLayers(tilestats, options) {
if (isObject(tilestats) && Array.isArray(tilestats.layers)) {
return tilestats.layers.map((layer) => parseTilestatsForLayer(layer, options));
}
return [];
}
function parseTilestatsForLayer(layer, options) {
const fields = [];
const indexedAttributes = {};
const attributes = layer.attributes || [];
for (const attribute of attributes) {
const name = attribute.attribute;
if (typeof name === "string") {
if (name.split("|").length > 1) {
const fname = name.split("|")[0];
indexedAttributes[fname] = indexedAttributes[fname] || [];
indexedAttributes[fname].push(attribute);
console.warn("ignoring tilestats indexed field", fname);
} else if (!fields[name]) {
fields.push(attributeToField(attribute, options));
} else {
}
}
}
return {
name: layer.layer || "",
dominantGeometry: layer.geometry,
fields
};
}
function mergeLayers(layers, tilestatsLayers) {
return layers.map((layer) => {
const tilestatsLayer = tilestatsLayers.find((tsLayer) => tsLayer.name === layer.name);
const fields = (tilestatsLayer == null ? void 0 : tilestatsLayer.fields) || layer.fields || [];
const mergedLayer = {
...layer,
...tilestatsLayer,
fields
};
mergedLayer.schema = getSchemaFromTileJSONLayer(mergedLayer);
return mergedLayer;
});
}
function parseBounds(bounds) {
const result = fromArrayOrString(bounds);
if (Array.isArray(result) && result.length === 4 && [result[0], result[2]].every(isLng) && [result[1], result[3]].every(isLat)) {
return [
[result[0], result[1]],
[result[2], result[3]]
];
}
return void 0;
}
function parseCenter(center) {
const result = fromArrayOrString(center);
if (Array.isArray(result) && result.length === 3 && isLng(result[0]) && isLat(result[1]) && isZoom(result[2])) {
return result;
}
return null;
}
function safeParseFloat(input) {
const result = typeof input === "string" ? parseFloat(input) : typeof input === "number" ? input : null;
return result === null || isNaN(result) ? null : result;
}
function isLat(num) {
return Number.isFinite(num) && num <= 90 && num >= -90;
}
function isLng(num) {
return Number.isFinite(num) && num <= 180 && num >= -180;
}
function isZoom(num) {
return Number.isFinite(num) && num >= 0 && num <= 22;
}
function fromArrayOrString(data) {
if (typeof data === "string") {
return data.split(",").map(parseFloat);
} else if (Array.isArray(data)) {
return data;
}
return null;
}
var attrTypeMap = {
number: {
type: "float32"
},
numeric: {
type: "float32"
},
string: {
type: "utf8"
},
vachar: {
type: "utf8"
},
float: {
type: "float32"
},
int: {
type: "int32"
},
int4: {
type: "int32"
},
boolean: {
type: "boolean"
},
bool: {
type: "boolean"
}
};
function attributeToField(attribute = {}, options) {
var _a;
const fieldTypes = attributeTypeToFieldType(attribute.type);
const field = {
name: attribute.attribute,
// what happens if attribute type is string...
// filterProps: getFilterProps(fieldTypes.type, attribute),
...fieldTypes
};
if (typeof attribute.min === "number") {
field.min = attribute.min;
}
if (typeof attribute.max === "number") {
field.max = attribute.max;
}
if (typeof attribute.count === "number") {
field.uniqueValueCount = attribute.count;
}
if (attribute.values) {
field.values = attribute.values;
}
if (field.values && typeof options.maxValues === "number") {
field.values = (_a = field.values) == null ? void 0 : _a.slice(0, options.maxValues);
}
return field;
}
function attributeTypeToFieldType(aType) {
const type = aType.toLowerCase();
if (!type || !attrTypeMap[type]) {
}
return attrTypeMap[type] || { type: "string" };
}
// dist/tilejson-loader.js
var VERSION = true ? "4.3.2" : "latest";
var TileJSONLoader = {
dataType: null,
batchType: null,
name: "TileJSON",
id: "tilejson",
module: "pmtiles",
version: VERSION,
worker: true,
extensions: ["json"],
mimeTypes: ["application/json"],
text: true,
options: {
tilejson: {
maxValues: void 0
}
},
parse: async (arrayBuffer, options) => {
const jsonString = new TextDecoder().decode(arrayBuffer);
const json = JSON.parse(jsonString);
const tilejsonOptions = { ...TileJSONLoader.options.tilejson, ...options == null ? void 0 : options.tilejson };
return parseTileJSON(json, tilejsonOptions);
},
parseTextSync: (text, options) => {
const json = JSON.parse(text);
const tilejsonOptions = { ...TileJSONLoader.options.tilejson, ...options == null ? void 0 : options.tilejson };
return parseTileJSON(json, tilejsonOptions);
}
};
// dist/lib/parse-mvt.js
var import_gis = require("@loaders.gl/gis");
var import_loader_utils = require("@loaders.gl/loader-utils");
var import_pbf = __toESM(require("pbf"), 1);
// dist/lib/utils/geometry-utils.js
var import_polygon = require("@math.gl/polygon");
function signedArea(ring) {
let sum = 0;
for (let i = 0, j = ring.length - 1, p1, p2; i < ring.length; j = i++) {
p1 = ring[i];
p2 = ring[j];
sum += (p2[0] - p1[0]) * (p1[1] + p2[1]);
}
return sum;
}
function convertToLocalCoordinates(coordinates, extent) {
if (Array.isArray(coordinates[0])) {
for (const subcoords of coordinates) {
convertToLocalCoordinates(subcoords, extent);
}
return;
}
const p = coordinates;
p[0] /= extent;
p[1] /= extent;
}
function convertToLocalCoordinatesFlat(data, extent) {
for (let i = 0; i < data.length; ++i) {
data[i] /= extent;
}
}
function projectToLngLat(line, tileIndex, extent) {
if (typeof line[0][0] !== "number") {
for (const point of line) {
projectToLngLat(point, tileIndex, extent);
}
return;
}
const size = extent * Math.pow(2, tileIndex.z);
const x0 = extent * tileIndex.x;
const y0 = extent * tileIndex.y;
for (let j = 0; j < line.length; j++) {
const p = line[j];
p[0] = (p[0] + x0) * 360 / size - 180;
const y2 = 180 - (p[1] + y0) * 360 / size;
p[1] = 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90;
}
}
function projectToLngLatFlat(data, tileIndex, extent) {
const { x, y, z } = tileIndex;
const size = extent * Math.pow(2, z);
const x0 = extent * x;
const y0 = extent * y;
for (let j = 0, jl = data.length; j < jl; j += 2) {
data[j] = (data[j] + x0) * 360 / size - 180;
const y2 = 180 - (data[j + 1] + y0) * 360 / size;
data[j + 1] = 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90;
}
}
function classifyRings(rings) {
const len = rings.length;
if (len <= 1)
return [rings];
const polygons = [];
let polygon;
let ccw;
for (let i = 0; i < len; i++) {
const area = signedArea(rings[i]);
if (area === 0)
continue;
if (ccw === void 0)
ccw = area < 0;
if (ccw === area < 0) {
if (polygon)
polygons.push(polygon);
polygon = [rings[i]];
} else if (polygon)
polygon.push(rings[i]);
}
if (polygon)
polygons.push(polygon);
return polygons;
}
function classifyRingsFlat(geom) {
const len = geom.indices.length;
const type = "Polygon";
if (len <= 1) {
return {
type,
data: geom.data,
areas: [[(0, import_polygon.getPolygonSignedArea)(geom.data)]],
indices: [geom.indices]
};
}
const areas = [];
const polygons = [];
let ringAreas = [];
let polygon = [];
let ccw;
let offset = 0;
for (let endIndex, i = 0, startIndex; i < len; i++) {
startIndex = geom.indices[i] - offset;
endIndex = geom.indices[i + 1] - offset || geom.data.length;
const shape = geom.data.slice(startIndex, endIndex);
const area = (0, import_polygon.getPolygonSignedArea)(shape);
if (area === 0) {
const before = geom.data.slice(0, startIndex);
const after = geom.data.slice(endIndex);
geom.data = before.concat(after);
offset += endIndex - startIndex;
continue;
}
if (ccw === void 0)
ccw = area < 0;
if (ccw === area < 0) {
if (polygon.length) {
areas.push(ringAreas);
polygons.push(polygon);
}
polygon = [startIndex];
ringAreas = [area];
} else {
ringAreas.push(area);
polygon.push(startIndex);
}
}
if (ringAreas)
areas.push(ringAreas);
if (polygon.length)
polygons.push(polygon);
return { type, areas, indices: polygons, data: geom.data };
}
// dist/lib/vector-tile/vector-tile-feature.js
var VectorTileFeature = class {
properties;
extent;
type;
id;
_pbf;
_geometry;
_keys;
_values;
_geometryInfo;
// eslint-disable-next-line max-params
constructor(pbf, end, extent, keys, values, geometryInfo) {
this.properties = {};
this.extent = extent;
this.type = 0;
this.id = null;
this._pbf = pbf;
this._geometry = -1;
this._keys = keys;
this._values = values;
this._geometryInfo = geometryInfo;
pbf.readFields(readFeature, this, end);
}
toGeoJSONFeature(coordinates, tileIndex) {
const coords = this.loadGeometry();
switch (coordinates) {
case "wgs84":
return _toGeoJSONFeature(this, coords, (line) => projectToLngLat(line, tileIndex, this.extent));
default:
return _toGeoJSONFeature(this, coords, convertToLocalCoordinates);
}
}
/**
*
* @param options
* @returns
*/
toBinaryFeature(coordinates, tileIndex) {
const geom = this.loadFlatGeometry();
switch (coordinates) {
case "wgs84":
return this._toBinaryCoordinates(geom, (coords) => projectToLngLatFlat(coords, tileIndex, this.extent));
default:
return this._toBinaryCoordinates(geom, convertToLocalCoordinatesFlat);
}
}
/** Read a bounding box from the feature */
// eslint-disable-next-line max-statements
bbox() {
const pbf = this._pbf;
pbf.pos = this._geometry;
const end = pbf.readVarint() + pbf.pos;
let cmd = 1;
let length = 0;
let x = 0;
let y = 0;
let x1 = Infinity;
let x2 = -Infinity;
let y1 = Infinity;
let y2 = -Infinity;
while (pbf.pos < end) {
if (length <= 0) {
const cmdLen = pbf.readVarint();
cmd = cmdLen & 7;
length = cmdLen >> 3;
}
length--;
if (cmd === 1 || cmd === 2) {
x += pbf.readSVarint();
y += pbf.readSVarint();
if (x < x1)
x1 = x;
if (x > x2)
x2 = x;
if (y < y1)
y1 = y;
if (y > y2)
y2 = y;
} else if (cmd !== 7) {
throw new Error(`unknown command ${cmd}`);
}
}
return [x1, y1, x2, y2];
}
// BINARY HELPERS
/**
*
* @param transform
* @returns result
*/
_toBinaryCoordinates(geom, transform) {
let geometry;
transform(geom.data, this.extent);
const coordLength = 2;
switch (this.type) {
case 1:
this._geometryInfo.pointFeaturesCount++;
this._geometryInfo.pointPositionsCount += geom.indices.length;
geometry = { type: "Point", ...geom };
break;
case 2:
this._geometryInfo.lineFeaturesCount++;
this._geometryInfo.linePathsCount += geom.indices.length;
this._geometryInfo.linePositionsCount += geom.data.length / coordLength;
geometry = { type: "LineString", ...geom };
break;
case 3:
geometry = classifyRingsFlat(geom);
this._geometryInfo.polygonFeaturesCount++;
this._geometryInfo.polygonObjectsCount += geometry.indices.length;
for (const indices of geometry.indices) {
this._geometryInfo.polygonRingsCount += indices.length;
}
this._geometryInfo.polygonPositionsCount += geometry.data.length / coordLength;
break;
default:
throw new Error(`Invalid geometry type: ${this.type}`);
}
const result = { type: "Feature", geometry, properties: this.properties };
if (this.id !== null) {
result.id = this.id;
}
return result;
}
// GEOJSON HELPER
// eslint-disable-next-line complexity, max-statements
loadGeometry() {
const pbf = this._pbf;
pbf.pos = this._geometry;
const end = pbf.readVarint() + pbf.pos;
let cmd = 1;
let length = 0;
let x = 0;
let y = 0;
const lines = [];
let line;
while (pbf.pos < end) {
if (length <= 0) {
const cmdLen = pbf.readVarint();
cmd = cmdLen & 7;
length = cmdLen >> 3;
}
length--;
switch (cmd) {
case 1:
case 2:
x += pbf.readSVarint();
y += pbf.readSVarint();
if (cmd === 1) {
if (line)
lines.push(line);
line = [];
}
if (line)
line.push([x, y]);
break;
case 7:
if (line) {
line.push(line[0].slice());
}
break;
default:
throw new Error(`unknown command ${cmd}`);
}
}
if (line)
lines.push(line);
return lines;
}
/**
* Expands the protobuf data to an intermediate Flat GeoJSON
* data format, which maps closely to the binary data buffers.
* It is similar to GeoJSON, but rather than storing the coordinates
* in multidimensional arrays, we have a 1D `data` with all the
* coordinates, and then index into this using the `indices`
* parameter, e.g.
*
* geometry: {
* type: 'Point', data: [1,2], indices: [0]
* }
* geometry: {
* type: 'LineString', data: [1,2,3,4,...], indices: [0]
* }
* geometry: {
* type: 'Polygon', data: [1,2,3,4,...], indices: [[0, 2]]
* }
* Thus the indices member lets us look up the relevant range
* from the data array.
* The Multi* versions of the above types share the same data
* structure, just with multiple elements in the indices array
*/
// eslint-disable-next-line complexity, max-statements
loadFlatGeometry() {
const pbf = this._pbf;
pbf.pos = this._geometry;
const endPos = pbf.readVarint() + pbf.pos;
let cmd = 1;
let cmdLen;
let length = 0;
let x = 0;
let y = 0;
let i = 0;
const indices = [];
const data = [];
while (pbf.pos < endPos) {
if (length <= 0) {
cmdLen = pbf.readVarint();
cmd = cmdLen & 7;
length = cmdLen >> 3;
}
length--;
if (cmd === 1 || cmd === 2) {
x += pbf.readSVarint();
y += pbf.readSVarint();
if (cmd === 1) {
indices.push(i);
}
data.push(x, y);
i += 2;
} else if (cmd === 7) {
if (i > 0) {
const start = indices[indices.length - 1];
data.push(data[start], data[start + 1]);
i += 2;
}
} else {
throw new Error(`unknown command ${cmd}`);
}
}
return { data, indices };
}
};
__publicField(VectorTileFeature, "types", ["Unknown", "Point", "LineString", "Polygon"]);
function _toGeoJSONFeature(vtFeature, coords, transform) {
let type = VectorTileFeature.types[vtFeature.type];
let i;
let j;
let coordinates;
switch (vtFeature.type) {
case 1:
const points = [];
for (i = 0; i < coords.length; i++) {
points[i] = coords[i][0];
}
coordinates = points;
transform(coordinates, vtFeature.extent);
break;
case 2:
coordinates = coords;
for (i = 0; i < coordinates.length; i++) {
transform(coordinates[i], vtFeature.extent);
}
break;
case 3:
coordinates = classifyRings(coords);
for (i = 0; i < coordinates.length; i++) {
for (j = 0; j < coordinates[i].length; j++) {
transform(coordinates[i][j], vtFeature.extent);
}
}
break;
default:
throw new Error("illegal vector tile type");
}
if (coordinates.length === 1) {
coordinates = coordinates[0];
} else {
type = `Multi${type}`;
}
const result = {
type: "Feature",
geometry: {
type,
coordinates
},
properties: vtFeature.properties
};
if (vtFeature.id !== null) {
result.properties ||= {};
result.properties.id = vtFeature.id;
}
return result;
}
function readFeature(tag, feature, pbf) {
if (feature && pbf) {
if (tag === 1)
feature.id = pbf.readVarint();
else if (tag === 2)
readTag(pbf, feature);
else if (tag === 3)
feature.type = pbf.readVarint();
else if (tag === 4)
feature._geometry = pbf.pos;
}
}
function readTag(pbf, feature) {
const end = pbf.readVarint() + pbf.pos;
while (pbf.pos < end) {
const key = feature._keys[pbf.readVarint()];
const value = feature._values[pbf.readVarint()];
feature.properties[key] = value;
}
}
// dist/lib/vector-tile/vector-tile-layer.js
var VectorTileLayer = class {
version;
name;
extent;
length;
_pbf;
_keys;
_values;
_features;
constructor(pbf, end) {
this.version = 1;
this.name = "";
this.extent = 4096;
this.length = 0;
this._pbf = pbf;
this._keys = [];
this._values = [];
this._features = [];
pbf.readFields(readLayer, this, end);
this.length = this._features.length;
}
/**
* return feature `i` from this layer as a `VectorTileFeature`
* @param index
* @returns feature
*/
getGeoJSONFeature(i) {
if (i < 0 || i >= this._features.length) {
throw new Error("feature index out of bounds");
}
this._pbf.pos = this._features[i];
const end = this._pbf.readVarint() + this._pbf.pos;
return new VectorTileFeature(this._pbf, end, this.extent, this._keys, this._values);
}
/**
* return binary feature `i` from this layer as a `VectorTileFeature`
*
* @param index
* @param geometryInfo
* @returns binary feature
*/
getBinaryFeature(i, geometryInfo) {
if (i < 0 || i >= this._features.length) {
throw new Error("feature index out of bounds");
}
this._pbf.pos = this._features[i];
const end = this._pbf.readVarint() + this._pbf.pos;
return new VectorTileFeature(this._pbf, end, this.extent, this._keys, this._values, geometryInfo);
}
};
function readLayer(tag, layer, pbf) {
if (layer && pbf) {
if (tag === 15)
layer.version = pbf.readVarint();
else if (tag === 1)
layer.name = pbf.readString();
else if (tag === 5)
layer.extent = pbf.readVarint();
else if (tag === 2)
layer._features.push(pbf.pos);
else if (tag === 3)
layer._keys.push(pbf.readString());
else if (tag === 4)
layer._values.push(readValueMessage(pbf));
}
}
function readValueMessage(pbf) {
let value = null;
const end = pbf.readVarint() + pbf.pos;
while (pbf.pos < end) {
const tag = pbf.readVarint() >> 3;
value = tag === 1 ? pbf.readString() : tag === 2 ? pbf.readFloat() : tag === 3 ? pbf.readDouble() : tag === 4 ? pbf.readVarint64() : tag === 5 ? pbf.readVarint() : tag === 6 ? pbf.readSVarint() : tag === 7 ? pbf.readBoolean() : null;
}
return value;
}
// dist/lib/vector-tile/vector-tile.js
var VectorTile = class {
layers;
constructor(pbf, end) {
this.layers = pbf.readFields(readTile, {}, end);
}
};
function readTile(tag, layers, pbf) {
if (tag === 3) {
if (pbf) {
const layer = new VectorTileLayer(pbf, pbf.readVarint() + pbf.pos);
if (layer.length && layers) {
layers[layer.name] = layer;
}
}
}
}
// dist/lib/parse-mvt.js
function parseMVT(arrayBuffer, options) {
var _a, _b;
const mvtOptions = checkOptions(options);
const shape = ((_a = options == null ? void 0 : options.gis) == null ? void 0 : _a.format) || ((_b = options == null ? void 0 : options.mvt) == null ? void 0 : _b.shape) || (options == null ? void 0 : options.shape);
switch (shape) {
case "columnar-table":
return { shape: "columnar-table", data: parseToBinary(arrayBuffer, mvtOptions) };
case "geojson-table": {
const table = {
shape: "geojson-table",
type: "FeatureCollection",
features: parseToGeojsonFeatures(arrayBuffer, mvtOptions)
};
return table;
}
case "geojson":
return parseToGeojsonFeatures(arrayBuffer, mvtOptions);
case "binary-geometry":
return parseToBinary(arrayBuffer, mvtOptions);
case "binary":
return parseToBinary(arrayBuffer, mvtOptions);
default:
throw new Error(shape || "undefined shape");
}
}
function parseToBinary(arrayBuffer, options) {
const [flatGeoJsonFeatures, geometryInfo] = parseToFlatGeoJson(arrayBuffer, options);
const binaryData = (0, import_gis.flatGeojsonToBinary)(flatGeoJsonFeatures, geometryInfo);
binaryData.byteLength = arrayBuffer.byteLength;
return binaryData;
}
function parseToFlatGeoJson(arrayBuffer, options) {
const features2 = [];
const geometryInfo = {
coordLength: 2,
pointPositionsCount: 0,
pointFeaturesCount: 0,
linePositionsCount: 0,
linePathsCount: 0,
lineFeaturesCount: 0,
polygonPositionsCount: 0,
polygonObjectsCount: 0,
polygonRingsCount: 0,
polygonFeaturesCount: 0
};
if (arrayBuffer.byteLength <= 0) {
return [features2, geometryInfo];
}
const tile = new VectorTile(new import_pbf.default(arrayBuffer));
const selectedLayers = options && Array.isArray(options.layers) ? options.layers : Object.keys(tile.layers);
selectedLayers.forEach((layerName) => {
const vectorTileLayer = tile.layers[layerName];
if (!vectorTileLayer) {
return;
}
for (let i = 0; i < vectorTileLayer.length; i++) {
const vectorTileFeature = vectorTileLayer.getBinaryFeature(i, geometryInfo);
const decodedFeature = getDecodedFeatureBinary(vectorTileFeature, options, layerName);
features2.push(decodedFeature);
}
});
return [features2, geometryInfo];
}
function parseToGeojsonFeatures(arrayBuffer, options) {
if (arrayBuffer.byteLength <= 0) {
return [];
}
const features2 = [];
const tile = new VectorTile(new import_pbf.default(arrayBuffer));
const selectedLayers = Array.isArray(options.layers) ? options.layers : Object.keys(tile.layers);
selectedLayers.forEach((layerName) => {
const vectorTileLayer = tile.layers[layerName];
if (!vectorTileLayer) {
return;
}
for (let i = 0; i < vectorTileLayer.length; i++) {
const vectorTileFeature = vectorTileLayer.getGeoJSONFeature(i);
const decodedFeature = getDecodedFeature(vectorTileFeature, options, layerName);
features2.push(decodedFeature);
}
});
return features2;
}
function checkOptions(options) {
var _a;
if (!(options == null ? void 0 : options.mvt)) {
throw new Error("mvt options required");
}
if (((_a = options.mvt) == null ? void 0 : _a.coordinates) === "wgs84" && !options.mvt.tileIndex) {
throw new Error("MVT Loader: WGS84 coordinates need tileIndex property");
}
if (options.gis) {
import_loader_utils.log.warn('MVTLoader: "options.gis" is deprecated, use "options.mvt.shape" instead')();
}
return options.mvt;
}
function getDecodedFeature(feature, options, layerName) {
const decodedFeature = feature.toGeoJSONFeature(options.coordinates || "local", options.tileIndex);
if (options.layerProperty) {
decodedFeature.properties ||= {};
decodedFeature.properties[options.layerProperty] = layerName;
}
return decodedFeature;
}
function getDecodedFeatureBinary(feature, options, layerName) {
const decodedFeature = feature.toBinaryFeature(options.coordinates || "local", options.tileIndex);
if (options.layerProperty && decodedFeature.properties) {
decodedFeature.properties[options.layerProperty] = layerName;
}
return decodedFeature;
}
// dist/mvt-loader.js
var VERSION2 = true ? "4.3.2" : "latest";
var MVTWorkerLoader = {
dataType: null,
batchType: null,
name: "Mapbox Vector Tile",
id: "mvt",
module: "mvt",
version: VERSION2,
// Note: ArcGIS uses '.pbf' extension and 'application/octet-stream'
extensions: ["mvt", "pbf"],
mimeTypes: [
// https://www.iana.org/assignments/media-types/application/vnd.mapbox-vector-tile
"application/vnd.mapbox-vector-tile",
"application/x-protobuf"
// 'application/octet-stream'
],
worker: true,
category: "geometry",
options: {
mvt: {
shape: "geojson",
coordinates: "local",
layerProperty: "layerName",
layers: void 0,
tileIndex: void 0
}
}
};
var MVTLoader = {
...MVTWorkerLoader,
parse: async (arrayBuffer, options) => parseMVT(arrayBuffer, options),
parseSync: parseMVT,
binary: true
};
// dist/mvt-source.js
var import_loader_utils2 = require("@loaders.gl/loader-utils");
var import_images = require("@loaders.gl/images");
var import_mvt = require("@loaders.gl/mvt");
var MVTSource = {
name: "MVT",
id: "mvt",
module: "mvt",
version: "0.0.0",
extensions: ["mvt"],
mimeTypes: ["application/octet-stream"],
options: {
mvt: {
// TODO - add options here
}
},
type: "mvt",
fromUrl: true,
fromBlob: false,
testURL: (url) => true,
createDataSource(url, props) {
return new MVTTileSource(url, props);
}
};
var MVTTileSource = class extends import_loader_utils2.DataSource {
props;
url;
metadataUrl = null;
data;
schema = "tms";
metadata;
extension;
mimeType = null;
constructor(url, props) {
var _a, _b;
super(props);
this.props = props;
this.url = (0, import_loader_utils2.resolvePath)(url);
this.metadataUrl = ((_a = props.mvt) == null ? void 0 : _a.metadataUrl) || `${this.url}/tilejson.json`;
this.extension = ((_b = props.mvt) == null ? void 0 : _b.extension) || ".png";
this.data = this.url;
this.getTileData = this.getTileData.bind(this);
this.metadata = this.getMetadata();
if (isURLTemplate(this.url)) {
this.schema = "template";
}
}
// @ts-ignore - Metadata type misalignment
async getMetadata() {
var _a, _b;
if (!this.metadataUrl) {
return null;
}
let response;
try {
response = await this.fetch(this.metadataUrl);
} catch (error) {
console.error(error.message);
return null;
}
if (!response.ok) {
console.error(response.statusText);
return null;
}
const tileJSON = await response.text();
const metadata = ((_b = (_a = import_mvt.TileJSONLoader).parseTextSync) == null ? void 0 : _b.call(_a, tileJSON)) || null;
return metadata;
}
getTileMIMEType() {
return this.mimeType;
}
async getTile(parameters) {
const { x, y, z } = parameters;
const tileUrl = this.getTileURL(x, y, z);
const response = await this.fetch(tileUrl);
if (!response.ok) {
return null;
}
const arrayBuffer = await response.arrayBuffer();
return arrayBuffer;
}
// Tile Source interface implementation: deck.gl compatible API
// TODO - currently only handles image tiles, not vector tiles
async getTileData(parameters) {
const { x, y, z } = parameters.index;
const arrayBuffer = await this.getTile({ x, y, z, layers: [] });
if (arrayBuffer === null) {
return null;
}
const imageMetadata = (0, import_images.getBinaryImageMetadata)(arrayBuffer);
this.mimeType = this.mimeType || (imageMetadata == null ? void 0 : imageMetadata.mimeType) || "application/vnd.mapbox-vector-tile";
switch (this.mimeType) {
case "application/vnd.mapbox-vector-tile":
return await this._parseVectorTile(arrayBuffer, { x, y, z, layers: [] });
default:
return await this._parseImageTile(arrayBuffer);
}
}
// ImageTileSource interface implementation
async getImageTile(tileParams) {
const arrayBuffer = await this.getTile(tileParams);
return arrayBuffer ? this._parseImageTile(arrayBuffer) : null;
}
async _parseImageTile(arrayBuffer) {
return await import_images.ImageLoader.parse(arrayBuffer, this.loadOptions);
}
// VectorTileSource interface implementation
async getVectorTile(tileParams) {
const arrayBuffer = await this.getTile(tileParams);
return arrayBuffer ? this._parseVectorTile(arrayBuffer, tileParams) : null;
}
async _parseVectorTile(arrayBuffer, tileParams) {
var _a;
const loadOptions = {
shape: "geojson-table",
mvt: {
coordinates: "wgs84",
tileIndex: { x: tileParams.x, y: tileParams.y, z: tileParams.z },
...(_a = this.loadOptions) == null ? void 0 : _a.mvt
},
...this.loadOptions
};
return await import_mvt.MVTLoader.parse(arrayBuffer, loadOptions);
}
getMetadataUrl() {
return this.metadataUrl;
}
getTileURL(x, y, z) {
switch (this.schema) {
case "xyz":
return `${this.url}/${x}/${y}/${z}${this.extension}`;
case "tms":
return `${this.url}/${z}/${x}/${y}${this.extension}`;
case "template":
return getURLFromTemplate(this.url, x, y, z, "0");
default:
throw new Error(this.schema);
}
}
};
function isURLTemplate(s) {
return /(?=.*{z})(?=.*{x})(?=.*({y}|{-y}))|(?=.*{x})(?=.*({y}|{-y})(?=.*{z}))/.test(s);
}
var xRegex = new RegExp("{x}", "g");
var yRegex = new RegExp("{y}", "g");
var zRegex = new RegExp("{z}", "g");
function getURLFromTemplate(template, x, y, z, id = "0") {
if (Array.isArray(template)) {
const i = stringHash(id) % template.length;
template = template[i];
}
let url = template;
url = url.replace(xRegex, String(x));
url = url.replace(yRegex, String(y));
url = url.replace(zRegex, String(z));
if (Number.isInteger(y) && Number.isInteger(z)) {
url = url.replace(/\{-y\}/g, String(Math.pow(2, z) - y - 1));
}
return url;
}
function stringHash(s) {
return Math.abs(s.split("").reduce((a, b) => (a << 5) - a + b.charCodeAt(0) | 0, 0));
}
// dist/table-tile-source.js
var import_loader_utils3 = require("@loaders.gl/loader-utils");
var import_schema = require("@loaders.gl/schema");
var import_stats = require("@probe.gl/stats");
// dist/lib/vector-tiler/proto-tile.js
function createProtoTile(features2, z, tx, ty, options) {
const tolerance = z === options.maxZoom ? 0 : options.tolerance / ((1 << z) * options.extent);
const tile = {
protoFeatures: [],
sourceFeatures: null,
numPoints: 0,
numSimplified: 0,
numFeatures: features2.length,
x: tx,
y: ty,
z,
transformed: false,
minX: 2,
minY: 1,
maxX: -1,
maxY: 0
};
for (const feature of features2) {
addProtoFeature(tile, feature, tolerance, options);
}
return tile;
}
function addProtoFeature(tile, feature, tolerance, options) {
const geometry = feature.geometry;
const type = feature.type;
const simplifiedGeometry = [];
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);
let simplifiedType;
switch (type) {
case "Point":
case "MultiPoint":
simplifiedType = 1;
for (let i = 0; i < geometry.length; i += 3) {
simplifiedGeometry.push(geometry[i], geometry[i + 1]);
tile.numPoints++;
tile.numSimplified++;
}
break;
case "LineString":
simplifiedType = 2;
addProtoLine(simplifiedGeometry, geometry, tile, tolerance, false, false);
break;
case "MultiLineString":
simplifiedType = 2;
for (let i = 0; i < geometry.length; i++) {
addProtoLine(simplifiedGeometry, geometry[i], tile, tolerance, false, i === 0);
}
break;
case "Polygon":
simplifiedType = 3;
for (let i = 0; i < geometry.length; i++) {
addProtoLine(simplifiedGeometry, geometry[i], tile, tolerance, true, i === 0);
}
break;
case "MultiPolygon":
simplifiedType = 3;
for (let k = 0; k < geometry.length; k++) {
const polygon = geometry[k];
for (let i = 0; i < polygon.length; i++) {
addProtoLine(simplifiedGeometry, polygon[i], tile, tolerance, true, i === 0);
}
}
break;
default:
throw new Error(`Unknown geometry type: ${type}`);
}
if (simplifiedGeometry.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 = geometry.start / geometry.size;
tags.mapbox_clip_end = geometry.end / geometry.size;
}
const tileFeature = {
geometry: simplifiedGeometry,
simplifiedType,
// @ts-expect-error
tags
};
if (feature.id !== null) {
tileFeature.id = feature.id;
}
tile.protoFeatures.push(tileFeature);
}
}
function addProtoLine(result, geometry, tile, tolerance, isPolygon, isOuter) {
const sqTolerance = tolerance * tolerance;
if (tolerance > 0 && geometry.size < (isPolygon ? sqTolerance : tolerance)) {
tile.numPoints += geometry.length / 3;
return;
}
const ring = [];
for (let i = 0; i < geometry.length; i += 3) {
if (tolerance === 0 || geometry[i + 2] > sqTolerance) {
tile.numSimplified++;
ring.push(geometry[i], geometry[i + 1]);
}
tile.numPoints++;
}
if (isPolygon)
rewind(ring, isOuter);
result.push(ring);
}
function rewind(ring, clockwise) {
let area = 0;
for (let i = 0, j = ring.length - 2; i < ring.length; 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;
}
}
}
// dist/lib/vector-tiler/transform-tile.js
function transformTile(protoTile, extent) {
if (protoTile.transformed) {
return protoTile;
}
const z2 = 1 << protoTile.z;
const tx = protoTile.x;
const ty = protoTile.y;
for (const protoFeature of protoTile.protoFeatures) {
const geom = protoFeature.geometry;
const simplifiedType = protoFeature.simplifiedType;
protoFeature.geometry = [];
if (simplifiedType === 1) {
for (let j = 0; j < geom.length; j += 2) {
protoFeature.geometry.push(transformPoint(geom[j], geom[j + 1], extent, z2, tx, ty));
}
} else {
for (let j = 0; j < geom.length; j++) {
const ring = [];
for (let k = 0; k < geom[j].length; k += 2) {
ring.push(transformPoint(geom[j][k], geom[j][k + 1], extent, z2, tx, ty));
}
protoFeature.geometry.push(ring);
}
}
}
protoTile.transformed = true;
return protoTile;
}
function transformPoint(x, y, extent, z2, tx, ty) {
return [Math.round(extent * (x * z2 - tx)), Math.round(extent * (y * z2 - ty))];
}
// dist/lib/vector-tiler/tile-to-geojson.js
function convertTileToGeoJSON(protoTile, props) {
const features2 = [];
for (const rawFeature of protoTile.protoFeatures) {
if (!rawFeature || !rawFeature.geometry) {
continue;
}
let type;
let coordinates;
switch (rawFeature.simplifiedType) {
case 1:
if (rawFeature.geometry.length === 1) {
type = "Point";
coordinates = rawFeature.geometry[0];
} else {
type = "MultiPoint";
coordinates = rawFeature.geometry;
}
break;
case 2:
if (rawFeature.geometry.length === 1) {
type = "LineString";
coordinates = rawFeature.geometry[0];
} else {
type = "MultiLineString";
coordinates = rawFeature.geometry;
}
break;
case 3:
if (rawFeature.geometry.length > 1) {
type = "MultiPolygon";
coordinates = [rawFeature.geometry];
} else {
type = "Polygon";
coordinates = rawFeature.geometry;
}
break;
default:
throw new Error(`${rawFeature.simplifiedType}is not a valid simplified type`);
}
switch (props.coordinates) {
case "EPSG:4326":
case "wgs84":
projectToLngLat(coordinates, props.tileIndex, props.extent);
break;
default:
convertToLocalCoordinates(coordinates, props.extent);
break;
}
const feature = {
type: "Feature",
geometry: {
type,
coordinates
},
properties: rawFeature.tags || {},
id: rawFeature.id
};
features2.push(feature);
}
if (features2.length === 0) {
return null;
}
const table = {
shape: "geojson-table",
type: "FeatureCollection",
features: features2
};
return table;
}
// dist/lib/vector-tiler/features/proto-feature.js
function createProtoFeature(id, type, geometry, tags) {
const feature = {
// eslint-disable-next-line
id: id == null ? null : id,
type,
simplifiedType: void 0,
// TODO
geometry,
tags,
minX: Infinity,
minY: Infinity,
maxX: -Infinity,
maxY: -Infinity
};
switch (type) {
case "Point":
case "MultiPoint":
case "LineString":
calcLineBBox(feature, geometry);
break;
case "MultiLineString":
for (const line of geometry) {
calcLineBBox(feature, line);
}
break;
case "Polygon":
calcLineBBox(feature, geometry[0]);
break;
case "MultiPolygon":
for (const polygon of geometry) {
calcLineBBox(feature, polygon[0]);
}
break;
default:
throw new Error(String(type));
}
return feature;
}
function calcLineBBox(feature, geometry) {
for (let i = 0; i < geometry.length; i += 3) {
feature.minX = Math.min(feature.minX, geometry[i]);
feature.minY = Math.min(feature.minY, geometry[i + 1]);
feature.maxX = Math.max(feature.maxX, geometry[i]);
feature.maxY = Math.max(feature.maxY, geometry[i + 1]);
}
}
// dist/lib/vector-tiler/features/simplify-path.js
function simplifyPath(coords, first, last, sqTolerance) {
let maxSqDist = sqTolerance;
const mid = last - first >> 1;
let minPosToMid = last - first;
let index;
const ax = coords[first];
const ay = coords[first + 1];
const bx = coords[last];
const by = coords[last + 1];
for (let i = first + 3; i < last; i += 3) {
const d = getSqSegDist(coords[i], coords[i + 1], ax, ay, bx, by);
if (d > maxSqDist) {
index = i;
maxSqDist = d;
} else if (d === maxSqDist) {
const posToMid = Math.abs(i - mid);
if (posToMid < minPosToMid) {
index = i;
minPosToMid = posToMid;
}
}
}
if (maxSqDist > sqTolerance) {
if (index - first > 3)
simplifyPath(coords, first, index, sqTolerance);
coords[index + 2] = maxSqDist;
if (last - index > 3)
simplifyPath(coords, index, last, sqTolerance);
}
}
function getSqSegDist(px, py, x, y, bx, by) {
let dx = bx - x;
let dy = by - y;
if (dx !== 0 || dy !== 0) {
const t = ((px - x) * dx + (py - y) * dy) / (dx * dx + dy * dy);
if (t > 1) {
x = bx;
y = by;
} else if (t > 0) {
x += dx * t;
y += dy * t;
}
}
dx = px - x;
dy = py - y;
return dx * dx + dy * dy;
}
// dist/lib/vector-tiler/features/convert-feature.js
function convertFeaturesToProtoFeature(data, options) {
const protoFeatures = [];
switch (data.type) {
case "FeatureCollection":
let i = 0;
for (const feature of data.features) {
protoFeatures.push(convertFeature(feature, options, i++));
}
break;
case "Feature":
protoFeatures.push(convertFeature(data, options));
break;
default:
protoFeatures.push(convertFeature({ geometry: data }, options));
}
return protoFeatures;
}
function convertFeature(geojson, options, index) {
if (!geojson.geometry) {
return;
}
const coords = geojson.geometry.coordinates;
const type = geojson.geometry.type;
const tolerance = Math.pow(options.tolerance / ((1 << options.maxZoom) * options.extent), 2);
let geometry = [];
let id = geojson.id;
if (options.promoteId) {
id = geojson.properties[options.promoteId];
} else if (options.generateId) {
id = index || 0;
}
switch (type) {
case "Point":
convertPoint(coords, geometry);
break;
case "MultiPoint":
for (const p of coords) {
convertPoint(p, geometry);
}
break;
case "LineString":
convertLine(coords, geometry, tolerance, false);
break;
case "MultiLineString":
if (options.lineMetrics) {
for (const line of coords) {
geometry = [];
convertLine(line, geometry, tolerance, false);
features.push(createProtoFeature(id, "LineString", geometry, geojson.properties));
}
return;
convertLines(coords, geometry, tolerance, false);
}
break;
case "Polygon":
convertLines(coords, geometry, tolerance, true);
break;
case "MultiPolygon":
for (const polygon of coords) {
const newPolygon = [];
convertLines(polygon, newPolygon, tolerance, true);
geometry.push(newPolygon);
}
break;
case "GeometryCollection":
for (const singleGeometry of geojson.geometry.geometries) {
convertFeature(features, {
id,
geometry: singleGeometry,
properties: geojson.properties
}, options, index);
}
break;
default:
throw new Error("Input data is not a valid GeoJSON object.");
}
return createProtoFeature(id, type, geometry, geojson.properties);
}
function convertPoint(coords, out) {
out.push(projectX(coords[0]), projectY(coords[1]), 0);
}
function convertLine(ring, out, tolerance, isPolygon) {
let x0, y0;
let size = 0;
for (let j = 0; j < ring.length; j++) {
const x = projectX(ring[j][0]);
const y = projectY(ring[j][1]);
out.push(x, y, 0);
if (j > 0) {
if (isPolygon) {
size += (x0 * y - x * y0) / 2;
} else {
size += Math.sqrt(Math.pow(x - x0, 2) + Math.pow(y - y0, 2));
}
}
x0 = x;
y0 = y;
}
const last = out.length - 3;
out[2] = 1;
simplifyPath(out, 0, last, tolerance);
out[last + 2] = 1;
out.size = Math.abs(size);
out.start = 0;
out.end = out.size;
}
function convertLines(rings, out, tolerance, isPolygon) {
for (let i = 0; i < rings.length; i++) {
const geom = [];
convertLine(rings[i], geom, tolerance, isPolygon);
out.push(geom);
}
}
function projectX(x) {
return x / 360 + 0.5;
}
function projectY(y) {
const sin = Math.sin(y * Math.PI / 180);
const y2 = 0.5 - 0.25 * Math.log((1 + sin) / (1 - sin)) / Math.PI;
return y2 < 0 ? 0 : y2 > 1 ? 1 : y2;
}
// dist/lib/vector-tiler/features/clip-features.js
function clipFeatures(features2, scale, k1, k2, axis, minAll, maxAll, options) {
k1 /= scale;
k2 /= scale;
if (minAll >= k1 && maxAll < k2) {
return features2;
} else if (maxAll < k1 || minAll >= k2) {
return null;
}
const clipped = [];
for (const feature of features2) {
const geometry = feature.geometry;
let type = feature.type;
const min = axis === 0 ? feature.minX : feature.minY;
const max = axis === 0 ? feature.maxX : feature.maxY;
if (min >= k1 && max < k2) {
clipped.push(feature);
continue;
} else if (max < k1 || min >= k2) {
continue;
}
let newGeometry = [];
if (type === "Point" || type === "MultiPoint") {
clipPoints(geometry, newGeometry, k1, k2, axis);
} else if (type === "LineString") {
clipLine(geometry, newGeometry, k1, k2, axis, false, options.lineMetrics);
} else if (type === "MultiLineString") {
clipLines(geometry, newGeometry, k1, k2, axis, false);
} else if (type === "Polygon") {
clipLines(geometry, newGeometry, k1, k2, axis, true);
} else if (type === "MultiPolygon") {
for (const polygon of geometry) {
const newPolygon = [];
clipLines(polygon, newPolygon, k1, k2, axis, true);
if (newPolygon.length) {
newGeometry.push(newPolygon);
}
}
}
if (newGeometry.length) {
if (options.lineMetrics && type === "LineString") {
for (const line of newGeometry) {
clipped.push(createProtoFeature(feature.id, type, line, feature.tags));
}
continue;
}
if (type === "LineString" || type === "MultiLineString") {
if (newGeometry.length === 1) {
type = "LineString";