| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579 |
- // index.ts
- import { flattenEach, featureEach } from "@turf/meta";
- import { polygon as polygon2, featureCollection as featureCollection2 } from "@turf/helpers";
- // lib/geojson-polygon-self-intersections.js
- import rbush from "rbush";
- function geojsonPolygonSelfIntersections(feature, filterFn, useSpatialIndex) {
- if (feature.geometry.type !== "Polygon")
- throw new Error("The input feature must be a Polygon");
- if (useSpatialIndex === void 0) useSpatialIndex = 1;
- var coord = feature.geometry.coordinates;
- var output = [];
- var seen = {};
- if (useSpatialIndex) {
- var allEdgesAsRbushTreeItems = [];
- for (var ring0 = 0; ring0 < coord.length; ring0++) {
- for (var edge0 = 0; edge0 < coord[ring0].length - 1; edge0++) {
- allEdgesAsRbushTreeItems.push(rbushTreeItem(ring0, edge0));
- }
- }
- var tree = new rbush();
- tree.load(allEdgesAsRbushTreeItems);
- }
- for (var ringA = 0; ringA < coord.length; ringA++) {
- for (var edgeA = 0; edgeA < coord[ringA].length - 1; edgeA++) {
- if (useSpatialIndex) {
- var bboxOverlaps = tree.search(rbushTreeItem(ringA, edgeA));
- bboxOverlaps.forEach(function(bboxIsect) {
- var ring12 = bboxIsect.ring;
- var edge12 = bboxIsect.edge;
- ifIsectAddToOutput(ringA, edgeA, ring12, edge12);
- });
- } else {
- for (var ring1 = 0; ring1 < coord.length; ring1++) {
- for (var edge1 = 0; edge1 < coord[ring1].length - 1; edge1++) {
- ifIsectAddToOutput(ringA, edgeA, ring1, edge1);
- }
- }
- }
- }
- }
- if (!filterFn)
- output = {
- type: "Feature",
- geometry: { type: "MultiPoint", coordinates: output }
- };
- return output;
- function ifIsectAddToOutput(ring02, edge02, ring12, edge12) {
- var start0 = coord[ring02][edge02];
- var end0 = coord[ring02][edge02 + 1];
- var start1 = coord[ring12][edge12];
- var end1 = coord[ring12][edge12 + 1];
- var isect = intersect(start0, end0, start1, end1);
- if (isect === null) return;
- var frac0;
- var frac1;
- if (end0[0] !== start0[0]) {
- frac0 = (isect[0] - start0[0]) / (end0[0] - start0[0]);
- } else {
- frac0 = (isect[1] - start0[1]) / (end0[1] - start0[1]);
- }
- if (end1[0] !== start1[0]) {
- frac1 = (isect[0] - start1[0]) / (end1[0] - start1[0]);
- } else {
- frac1 = (isect[1] - start1[1]) / (end1[1] - start1[1]);
- }
- if (frac0 >= 1 || frac0 <= 0 || frac1 >= 1 || frac1 <= 0) return;
- var key = isect;
- var unique = !seen[key];
- if (unique) {
- seen[key] = true;
- }
- if (filterFn) {
- output.push(
- filterFn(
- isect,
- ring02,
- edge02,
- start0,
- end0,
- frac0,
- ring12,
- edge12,
- start1,
- end1,
- frac1,
- unique
- )
- );
- } else {
- output.push(isect);
- }
- }
- function rbushTreeItem(ring, edge) {
- var start = coord[ring][edge];
- var end = coord[ring][edge + 1];
- var minX;
- var maxX;
- var minY;
- var maxY;
- if (start[0] < end[0]) {
- minX = start[0];
- maxX = end[0];
- } else {
- minX = end[0];
- maxX = start[0];
- }
- if (start[1] < end[1]) {
- minY = start[1];
- maxY = end[1];
- } else {
- minY = end[1];
- maxY = start[1];
- }
- return {
- minX,
- minY,
- maxX,
- maxY,
- ring,
- edge
- };
- }
- }
- function intersect(start0, end0, start1, end1) {
- if (equalArrays(start0, start1) || equalArrays(start0, end1) || equalArrays(end0, start1) || equalArrays(end1, start1))
- return null;
- var x0 = start0[0], y0 = start0[1], x1 = end0[0], y1 = end0[1], x2 = start1[0], y2 = start1[1], x3 = end1[0], y3 = end1[1];
- var denom = (x0 - x1) * (y2 - y3) - (y0 - y1) * (x2 - x3);
- if (denom === 0) return null;
- var x4 = ((x0 * y1 - y0 * x1) * (x2 - x3) - (x0 - x1) * (x2 * y3 - y2 * x3)) / denom;
- var y4 = ((x0 * y1 - y0 * x1) * (y2 - y3) - (y0 - y1) * (x2 * y3 - y2 * x3)) / denom;
- return [x4, y4];
- }
- function equalArrays(array1, array2) {
- if (!array1 || !array2) return false;
- if (array1.length !== array2.length) return false;
- for (var i = 0, l = array1.length; i < l; i++) {
- if (array1[i] instanceof Array && array2[i] instanceof Array) {
- if (!equalArrays(array1[i], array2[i])) return false;
- } else if (array1[i] !== array2[i]) {
- return false;
- }
- }
- return true;
- }
- // lib/simplepolygon.js
- import { area } from "@turf/area";
- import { featureCollection, polygon } from "@turf/helpers";
- import { booleanPointInPolygon } from "@turf/boolean-point-in-polygon";
- import rbush2 from "rbush";
- function simplepolygon(feature) {
- if (feature.type != "Feature")
- throw new Error("The input must a geojson object of type Feature");
- if (feature.geometry === void 0 || feature.geometry == null)
- throw new Error(
- "The input must a geojson object with a non-empty geometry"
- );
- if (feature.geometry.type != "Polygon")
- throw new Error("The input must be a geojson Polygon");
- var numRings = feature.geometry.coordinates.length;
- var vertices = [];
- for (var i = 0; i < numRings; i++) {
- var ring = feature.geometry.coordinates[i];
- if (!equalArrays2(ring[0], ring[ring.length - 1])) {
- ring.push(ring[0]);
- }
- for (var j = 0; j < ring.length - 1; j++) {
- vertices.push(ring[j]);
- }
- }
- if (!isUnique(vertices))
- throw new Error(
- "The input polygon may not have duplicate vertices (except for the first and last vertex of each ring)"
- );
- var numvertices = vertices.length;
- var selfIsectsData = geojsonPolygonSelfIntersections(
- feature,
- function filterFn(isect, ring0, edge0, start0, end0, frac0, ring1, edge1, start1, end1, frac1, unique) {
- return [
- isect,
- ring0,
- edge0,
- start0,
- end0,
- frac0,
- ring1,
- edge1,
- start1,
- end1,
- frac1,
- unique
- ];
- }
- );
- var numSelfIsect = selfIsectsData.length;
- if (numSelfIsect == 0) {
- var outputFeatureArray = [];
- for (var i = 0; i < numRings; i++) {
- outputFeatureArray.push(
- polygon([feature.geometry.coordinates[i]], {
- parent: -1,
- winding: windingOfRing(feature.geometry.coordinates[i])
- })
- );
- }
- var output = featureCollection(outputFeatureArray);
- determineParents();
- setNetWinding();
- return output;
- }
- var pseudoVtxListByRingAndEdge = [];
- var isectList = [];
- for (var i = 0; i < numRings; i++) {
- pseudoVtxListByRingAndEdge.push([]);
- for (var j = 0; j < feature.geometry.coordinates[i].length - 1; j++) {
- pseudoVtxListByRingAndEdge[i].push([
- new PseudoVtx(
- feature.geometry.coordinates[i][modulo(j + 1, feature.geometry.coordinates[i].length - 1)],
- 1,
- [i, j],
- [i, modulo(j + 1, feature.geometry.coordinates[i].length - 1)],
- void 0
- )
- ]);
- isectList.push(
- new Isect(
- feature.geometry.coordinates[i][j],
- [i, modulo(j - 1, feature.geometry.coordinates[i].length - 1)],
- [i, j],
- void 0,
- void 0,
- false,
- true
- )
- );
- }
- }
- for (var i = 0; i < numSelfIsect; i++) {
- pseudoVtxListByRingAndEdge[selfIsectsData[i][1]][selfIsectsData[i][2]].push(
- new PseudoVtx(
- selfIsectsData[i][0],
- selfIsectsData[i][5],
- [selfIsectsData[i][1], selfIsectsData[i][2]],
- [selfIsectsData[i][6], selfIsectsData[i][7]],
- void 0
- )
- );
- if (selfIsectsData[i][11])
- isectList.push(
- new Isect(
- selfIsectsData[i][0],
- [selfIsectsData[i][1], selfIsectsData[i][2]],
- [selfIsectsData[i][6], selfIsectsData[i][7]],
- void 0,
- void 0,
- true,
- true
- )
- );
- }
- var numIsect = isectList.length;
- for (var i = 0; i < pseudoVtxListByRingAndEdge.length; i++) {
- for (var j = 0; j < pseudoVtxListByRingAndEdge[i].length; j++) {
- pseudoVtxListByRingAndEdge[i][j].sort(function(a, b) {
- return a.param < b.param ? -1 : 1;
- });
- }
- }
- var allIsectsAsIsectRbushTreeItem = [];
- for (var i = 0; i < numIsect; i++) {
- allIsectsAsIsectRbushTreeItem.push({
- minX: isectList[i].coord[0],
- minY: isectList[i].coord[1],
- maxX: isectList[i].coord[0],
- maxY: isectList[i].coord[1],
- index: i
- });
- }
- var isectRbushTree = new rbush2();
- isectRbushTree.load(allIsectsAsIsectRbushTreeItem);
- for (var i = 0; i < pseudoVtxListByRingAndEdge.length; i++) {
- for (var j = 0; j < pseudoVtxListByRingAndEdge[i].length; j++) {
- for (var k = 0; k < pseudoVtxListByRingAndEdge[i][j].length; k++) {
- var coordToFind;
- if (k == pseudoVtxListByRingAndEdge[i][j].length - 1) {
- coordToFind = pseudoVtxListByRingAndEdge[i][modulo(j + 1, feature.geometry.coordinates[i].length - 1)][0].coord;
- } else {
- coordToFind = pseudoVtxListByRingAndEdge[i][j][k + 1].coord;
- }
- var IsectRbushTreeItemFound = isectRbushTree.search({
- minX: coordToFind[0],
- minY: coordToFind[1],
- maxX: coordToFind[0],
- maxY: coordToFind[1]
- })[0];
- pseudoVtxListByRingAndEdge[i][j][k].nxtIsectAlongEdgeIn = IsectRbushTreeItemFound.index;
- }
- }
- }
- for (var i = 0; i < pseudoVtxListByRingAndEdge.length; i++) {
- for (var j = 0; j < pseudoVtxListByRingAndEdge[i].length; j++) {
- for (var k = 0; k < pseudoVtxListByRingAndEdge[i][j].length; k++) {
- var coordToFind = pseudoVtxListByRingAndEdge[i][j][k].coord;
- var IsectRbushTreeItemFound = isectRbushTree.search({
- minX: coordToFind[0],
- minY: coordToFind[1],
- maxX: coordToFind[0],
- maxY: coordToFind[1]
- })[0];
- var l = IsectRbushTreeItemFound.index;
- if (l < numvertices) {
- isectList[l].nxtIsectAlongRingAndEdge2 = pseudoVtxListByRingAndEdge[i][j][k].nxtIsectAlongEdgeIn;
- } else {
- if (equalArrays2(
- isectList[l].ringAndEdge1,
- pseudoVtxListByRingAndEdge[i][j][k].ringAndEdgeIn
- )) {
- isectList[l].nxtIsectAlongRingAndEdge1 = pseudoVtxListByRingAndEdge[i][j][k].nxtIsectAlongEdgeIn;
- } else {
- isectList[l].nxtIsectAlongRingAndEdge2 = pseudoVtxListByRingAndEdge[i][j][k].nxtIsectAlongEdgeIn;
- }
- }
- }
- }
- }
- var queue = [];
- var i = 0;
- for (var j = 0; j < numRings; j++) {
- var leftIsect = i;
- for (var k = 0; k < feature.geometry.coordinates[j].length - 1; k++) {
- if (isectList[i].coord[0] < isectList[leftIsect].coord[0]) {
- leftIsect = i;
- }
- i++;
- }
- var isectAfterLeftIsect = isectList[leftIsect].nxtIsectAlongRingAndEdge2;
- for (var k = 0; k < isectList.length; k++) {
- if (isectList[k].nxtIsectAlongRingAndEdge1 == leftIsect || isectList[k].nxtIsectAlongRingAndEdge2 == leftIsect) {
- var isectBeforeLeftIsect = k;
- break;
- }
- }
- var windingAtIsect = isConvex(
- [
- isectList[isectBeforeLeftIsect].coord,
- isectList[leftIsect].coord,
- isectList[isectAfterLeftIsect].coord
- ],
- true
- ) ? 1 : -1;
- queue.push({ isect: leftIsect, parent: -1, winding: windingAtIsect });
- }
- queue.sort(function(a, b) {
- return isectList[a.isect].coord > isectList[b.isect].coord ? -1 : 1;
- });
- var outputFeatureArray = [];
- while (queue.length > 0) {
- var popped = queue.pop();
- var startIsect = popped.isect;
- var currentOutputRingParent = popped.parent;
- var currentOutputRingWinding = popped.winding;
- var currentOutputRing = outputFeatureArray.length;
- var currentOutputRingCoords = [isectList[startIsect].coord];
- var currentIsect = startIsect;
- if (isectList[startIsect].ringAndEdge1Walkable) {
- var walkingRingAndEdge = isectList[startIsect].ringAndEdge1;
- var nxtIsect = isectList[startIsect].nxtIsectAlongRingAndEdge1;
- } else {
- var walkingRingAndEdge = isectList[startIsect].ringAndEdge2;
- var nxtIsect = isectList[startIsect].nxtIsectAlongRingAndEdge2;
- }
- while (!equalArrays2(isectList[startIsect].coord, isectList[nxtIsect].coord)) {
- currentOutputRingCoords.push(isectList[nxtIsect].coord);
- var nxtIsectInQueue = void 0;
- for (var i = 0; i < queue.length; i++) {
- if (queue[i].isect == nxtIsect) {
- nxtIsectInQueue = i;
- break;
- }
- }
- if (nxtIsectInQueue != void 0) {
- queue.splice(nxtIsectInQueue, 1);
- }
- if (equalArrays2(walkingRingAndEdge, isectList[nxtIsect].ringAndEdge1)) {
- walkingRingAndEdge = isectList[nxtIsect].ringAndEdge2;
- isectList[nxtIsect].ringAndEdge2Walkable = false;
- if (isectList[nxtIsect].ringAndEdge1Walkable) {
- var pushing = { isect: nxtIsect };
- if (isConvex(
- [
- isectList[currentIsect].coord,
- isectList[nxtIsect].coord,
- isectList[isectList[nxtIsect].nxtIsectAlongRingAndEdge2].coord
- ],
- currentOutputRingWinding == 1
- )) {
- pushing.parent = currentOutputRingParent;
- pushing.winding = -currentOutputRingWinding;
- } else {
- pushing.parent = currentOutputRing;
- pushing.winding = currentOutputRingWinding;
- }
- queue.push(pushing);
- }
- currentIsect = nxtIsect;
- nxtIsect = isectList[nxtIsect].nxtIsectAlongRingAndEdge2;
- } else {
- walkingRingAndEdge = isectList[nxtIsect].ringAndEdge1;
- isectList[nxtIsect].ringAndEdge1Walkable = false;
- if (isectList[nxtIsect].ringAndEdge2Walkable) {
- var pushing = { isect: nxtIsect };
- if (isConvex(
- [
- isectList[currentIsect].coord,
- isectList[nxtIsect].coord,
- isectList[isectList[nxtIsect].nxtIsectAlongRingAndEdge1].coord
- ],
- currentOutputRingWinding == 1
- )) {
- pushing.parent = currentOutputRingParent;
- pushing.winding = -currentOutputRingWinding;
- } else {
- pushing.parent = currentOutputRing;
- pushing.winding = currentOutputRingWinding;
- }
- queue.push(pushing);
- }
- currentIsect = nxtIsect;
- nxtIsect = isectList[nxtIsect].nxtIsectAlongRingAndEdge1;
- }
- }
- currentOutputRingCoords.push(isectList[nxtIsect].coord);
- outputFeatureArray.push(
- polygon([currentOutputRingCoords], {
- index: currentOutputRing,
- parent: currentOutputRingParent,
- winding: currentOutputRingWinding,
- netWinding: void 0
- })
- );
- }
- var output = featureCollection(outputFeatureArray);
- determineParents();
- setNetWinding();
- function determineParents() {
- var featuresWithoutParent = [];
- for (var i2 = 0; i2 < output.features.length; i2++) {
- if (output.features[i2].properties.parent == -1)
- featuresWithoutParent.push(i2);
- }
- if (featuresWithoutParent.length > 1) {
- for (var i2 = 0; i2 < featuresWithoutParent.length; i2++) {
- var parent = -1;
- var parentArea = Infinity;
- for (var j2 = 0; j2 < output.features.length; j2++) {
- if (featuresWithoutParent[i2] == j2) continue;
- if (booleanPointInPolygon(
- output.features[featuresWithoutParent[i2]].geometry.coordinates[0][0],
- output.features[j2],
- { ignoreBoundary: true }
- )) {
- if (area(output.features[j2]) < parentArea) {
- parent = j2;
- }
- }
- }
- output.features[featuresWithoutParent[i2]].properties.parent = parent;
- }
- }
- }
- function setNetWinding() {
- for (var i2 = 0; i2 < output.features.length; i2++) {
- if (output.features[i2].properties.parent == -1) {
- var netWinding = output.features[i2].properties.winding;
- output.features[i2].properties.netWinding = netWinding;
- setNetWindingOfChildren(i2, netWinding);
- }
- }
- }
- function setNetWindingOfChildren(parent, ParentNetWinding) {
- for (var i2 = 0; i2 < output.features.length; i2++) {
- if (output.features[i2].properties.parent == parent) {
- var netWinding = ParentNetWinding + output.features[i2].properties.winding;
- output.features[i2].properties.netWinding = netWinding;
- setNetWindingOfChildren(i2, netWinding);
- }
- }
- }
- return output;
- }
- var PseudoVtx = function(coord, param, ringAndEdgeIn, ringAndEdgeOut, nxtIsectAlongEdgeIn) {
- this.coord = coord;
- this.param = param;
- this.ringAndEdgeIn = ringAndEdgeIn;
- this.ringAndEdgeOut = ringAndEdgeOut;
- this.nxtIsectAlongEdgeIn = nxtIsectAlongEdgeIn;
- };
- var Isect = function(coord, ringAndEdge1, ringAndEdge2, nxtIsectAlongRingAndEdge1, nxtIsectAlongRingAndEdge2, ringAndEdge1Walkable, ringAndEdge2Walkable) {
- this.coord = coord;
- this.ringAndEdge1 = ringAndEdge1;
- this.ringAndEdge2 = ringAndEdge2;
- this.nxtIsectAlongRingAndEdge1 = nxtIsectAlongRingAndEdge1;
- this.nxtIsectAlongRingAndEdge2 = nxtIsectAlongRingAndEdge2;
- this.ringAndEdge1Walkable = ringAndEdge1Walkable;
- this.ringAndEdge2Walkable = ringAndEdge2Walkable;
- };
- function isConvex(pts, righthanded) {
- if (typeof righthanded === "undefined") righthanded = true;
- if (pts.length != 3)
- throw new Error("This function requires an array of three points [x,y]");
- var d = (pts[1][0] - pts[0][0]) * (pts[2][1] - pts[0][1]) - (pts[1][1] - pts[0][1]) * (pts[2][0] - pts[0][0]);
- return d >= 0 == righthanded;
- }
- function windingOfRing(ring) {
- var leftVtx = 0;
- for (var i = 0; i < ring.length - 1; i++) {
- if (ring[i][0] < ring[leftVtx][0]) leftVtx = i;
- }
- if (isConvex(
- [
- ring[modulo(leftVtx - 1, ring.length - 1)],
- ring[leftVtx],
- ring[modulo(leftVtx + 1, ring.length - 1)]
- ],
- true
- )) {
- var winding = 1;
- } else {
- var winding = -1;
- }
- return winding;
- }
- function equalArrays2(array1, array2) {
- if (!array1 || !array2) return false;
- if (array1.length != array2.length) return false;
- for (var i = 0, l = array1.length; i < l; i++) {
- if (array1[i] instanceof Array && array2[i] instanceof Array) {
- if (!equalArrays2(array1[i], array2[i])) return false;
- } else if (array1[i] != array2[i]) {
- return false;
- }
- }
- return true;
- }
- function modulo(n, m) {
- return (n % m + m) % m;
- }
- function isUnique(array) {
- var u = {};
- var isUnique2 = 1;
- for (var i = 0, l = array.length; i < l; ++i) {
- if (Object.prototype.hasOwnProperty.call(u, array[i])) {
- isUnique2 = 0;
- break;
- }
- u[array[i]] = 1;
- }
- return isUnique2;
- }
- // index.ts
- function unkinkPolygon(geojson) {
- var features = [];
- flattenEach(geojson, function(feature) {
- if (feature.geometry.type !== "Polygon") return;
- featureEach(simplepolygon(feature), function(poly) {
- features.push(polygon2(poly.geometry.coordinates, feature.properties));
- });
- });
- return featureCollection2(features);
- }
- var turf_unkink_polygon_default = unkinkPolygon;
- export {
- turf_unkink_polygon_default as default,
- unkinkPolygon
- };
- //# sourceMappingURL=index.js.map
|