shapefile
Version:
An implementation of the shapefile (.shp) spatial data format.
66 lines (58 loc) • 2.17 kB
JavaScript
export default function(record) {
var i = 44, j, n = record.getInt32(36, true), m = record.getInt32(40, true), parts = new Array(n), points = new Array(m), polygons = [], holes = [];
for (j = 0; j < n; ++j, i += 4) parts[j] = record.getInt32(i, true);
for (j = 0; j < m; ++j, i += 16) points[j] = [record.getFloat64(i, true), record.getFloat64(i + 8, true)];
parts.forEach(function(i, j) {
var ring = points.slice(i, parts[j + 1]);
if (ringClockwise(ring)) polygons.push([ring]);
else holes.push(ring);
});
holes.forEach(function(hole) {
polygons.some(function(polygon) {
if (ringContainsSome(polygon[0], hole)) {
polygon.push(hole);
return true;
}
}) || polygons.push([hole]);
});
return polygons.length === 1
? {type: "Polygon", coordinates: polygons[0]}
: {type: "MultiPolygon", coordinates: polygons};
};
function ringClockwise(ring) {
if ((n = ring.length) < 4) return false;
var i = 0, n, area = ring[n - 1][1] * ring[0][0] - ring[n - 1][0] * ring[0][1];
while (++i < n) area += ring[i - 1][1] * ring[i][0] - ring[i - 1][0] * ring[i][1];
return area >= 0;
}
function ringContainsSome(ring, hole) {
var i = -1, n = hole.length, c;
while (++i < n) {
if (c = ringContains(ring, hole[i])) {
return c > 0;
}
}
return false;
}
function ringContains(ring, point) {
var x = point[0], y = point[1], contains = -1;
for (var i = 0, n = ring.length, j = n - 1; i < n; j = i++) {
var pi = ring[i], xi = pi[0], yi = pi[1],
pj = ring[j], xj = pj[0], yj = pj[1];
if (segmentContains(pi, pj, point)) {
return 0;
}
if (((yi > y) !== (yj > y)) && ((x < (xj - xi) * (y - yi) / (yj - yi) + xi))) {
contains = -contains;
}
}
return contains;
}
function segmentContains(p0, p1, p2) {
var x20 = p2[0] - p0[0], y20 = p2[1] - p0[1];
if (x20 === 0 && y20 === 0) return true;
var x10 = p1[0] - p0[0], y10 = p1[1] - p0[1];
if (x10 === 0 && y10 === 0) return false;
var t = (x20 * x10 + y20 * y10) / (x10 * x10 + y10 * y10);
return t < 0 || t > 1 ? false : t === 0 || t === 1 ? true : t * x10 === x20 && t * y10 === y20;
}