geojson-vt
Version:
Slice GeoJSON data into vector tiles efficiently
143 lines (105 loc) • 3.68 kB
JavaScript
module.exports = clip;
/* clip features between two axis-parallel lines:
* | |
* ___|___ | /
* / | \____|____/
* | |
*/
function clip(features, scale, k1, k2, axis, intersect) {
k1 /= scale;
k2 /= scale;
var clipped = [];
for (var i = 0; i < features.length; i++) {
var feature = features[i],
geometry = feature.geometry,
type = feature.type,
min, max;
if (feature.min) {
min = feature.min[axis];
max = feature.max[axis];
if (min >= k1 && max <= k2) { // trivial accept
clipped.push(feature);
continue;
} else if (min > k2 || max < k1) continue; // trivial reject
}
var slices = type === 1 ?
clipPoints(geometry, k1, k2, axis) :
clipGeometry(geometry, k1, k2, axis, intersect, type === 3);
if (slices.length) {
clipped.push({
geometry: slices,
type: type,
tags: features[i].tags || null
});
}
}
return clipped.length ? clipped : null;
}
function clipPoints(geometry, k1, k2, axis) {
var slice = [];
for (var i = 0; i < geometry.length; i++) {
var a = geometry[i],
ak = a[axis];
if (ak >= k1 && ak <= k2) slice.push(a);
}
return slice;
}
function clipGeometry(geometry, k1, k2, axis, intersect, closed) {
var slices = [];
for (var i = 0; i < geometry.length; i++) {
var ak = 0,
bk = 0,
b = null,
points = geometry[i],
area = points.area,
dist = points.dist,
len = points.length,
a, j;
var slice = [];
for (j = 0; j < len - 1; j++) {
a = b || points[j];
b = points[j + 1];
ak = bk || a[axis];
bk = b[axis];
if (ak < k1) {
if ((bk > k2)) { // ---|-----|-->
slice.push(intersect(a, b, k1), intersect(a, b, k2));
if (!closed) slice = newSlice(slices, slice, area, dist);
} else if (bk >= k1) slice.push(intersect(a, b, k1)); // ---|--> |
} else if (ak > k2) {
if ((bk < k1)) { // <--|-----|---
slice.push(intersect(a, b, k2), intersect(a, b, k1));
if (!closed) slice = newSlice(slices, slice, area, dist);
} else if (bk <= k2) slice.push(intersect(a, b, k2)); // | <--|---
} else {
slice.push(a);
if (bk < k1) { // <--|--- |
slice.push(intersect(a, b, k1));
if (!closed) slice = newSlice(slices, slice, area, dist);
} else if (bk > k2) { // | ---|-->
slice.push(intersect(a, b, k2));
if (!closed) slice = newSlice(slices, slice, area, dist);
}
// | --> |
}
}
a = points[len - 1];
ak = a[axis];
if (ak >= k1 && ak <= k2) slice.push(a);
var sliceLen = slice.length;
// close the polygon if its endpoints are not the same after clipping
if (closed && slice[0] !== slice[sliceLen - 1]) slice.push(slice[0]);
// add the final slice
newSlice(slices, slice, area, dist);
}
return slices;
}
function newSlice(slices, slice, area, dist) {
if (slice.length) {
slice.area = area;
slice.dist = dist;
slices.push(slice);
}
return [];
}
;