diff --git a/packages/turf-kinks/index.ts b/packages/turf-kinks/index.ts index f8dcfb6c30..331068832a 100644 --- a/packages/turf-kinks/index.ts +++ b/packages/turf-kinks/index.ts @@ -8,7 +8,6 @@ import { Polygon, } from "geojson"; import { point } from "@turf/helpers"; -import { sweeplineIntersections as findIntersections } from "./lib/sweepline-intersections-export.js"; /** * Takes a {@link LineString|linestring}, {@link MultiLineString|multi-linestring}, @@ -33,29 +32,138 @@ import { sweeplineIntersections as findIntersections } from "./lib/sweepline-int * var addToMap = [poly, kinks] */ function kinks( - featureIn: Feature + featureIn: Feature | T ): FeatureCollection { + let coordinates: any; + let feature: any; const results: FeatureCollection = { type: "FeatureCollection", features: [], }; - if ( - featureIn.type === "Feature" && - ((featureIn as Feature).geometry.type === "Point" || - (featureIn as Feature).geometry.type === "MultiPoint") - ) { + if (featureIn.type === "Feature") { + feature = featureIn.geometry; + } else { + feature = featureIn; + } + if (feature.type === "LineString") { + coordinates = [feature.coordinates]; + } else if (feature.type === "MultiLineString") { + coordinates = feature.coordinates; + } else if (feature.type === "MultiPolygon") { + coordinates = [].concat(...feature.coordinates); + } else if (feature.type === "Polygon") { + coordinates = feature.coordinates; + } else { throw new Error( "Input must be a LineString, MultiLineString, " + "Polygon, or MultiPolygon Feature or Geometry" ); } - const intersections = findIntersections(featureIn, false); - for (let i = 0; i < intersections.length; ++i) { - const intersection = intersections[i]; - results.features.push(point([intersection[0], intersection[1]])); - } + coordinates.forEach((line1: any) => { + coordinates.forEach((line2: any) => { + for (let i = 0; i < line1.length - 1; i++) { + // start iteration at i, intersections for k < i have already + // been checked in previous outer loop iterations + for (let k = i; k < line2.length - 1; k++) { + if (line1 === line2) { + // segments are adjacent and always share a vertex, not a kink + if (Math.abs(i - k) === 1) { + continue; + } + // first and last segment in a closed lineString or ring always share a vertex, not a kink + if ( + // segments are first and last segment of lineString + i === 0 && + k === line1.length - 2 && + // lineString is closed + line1[i][0] === line1[line1.length - 1][0] && + line1[i][1] === line1[line1.length - 1][1] + ) { + continue; + } + } + + const intersection: any = lineIntersects( + line1[i][0], + line1[i][1], + line1[i + 1][0], + line1[i + 1][1], + line2[k][0], + line2[k][1], + line2[k + 1][0], + line2[k + 1][1] + ); + if (intersection) { + results.features.push(point([intersection[0], intersection[1]])); + } + } + } + }); + }); return results; } +// modified from http://jsfiddle.net/justin_c_rounds/Gd2S2/light/ +function lineIntersects( + line1StartX: any, + line1StartY: any, + line1EndX: any, + line1EndY: any, + line2StartX: any, + line2StartY: any, + line2EndX: any, + line2EndY: any +) { + // if the lines intersect, the result contains the x and y of the + // intersection (treating the lines as infinite) and booleans for whether + // line segment 1 or line segment 2 contain the point + let denominator; + let a; + let b; + let numerator1; + let numerator2; + const result = { + x: null, + y: null, + onLine1: false, + onLine2: false, + }; + denominator = + (line2EndY - line2StartY) * (line1EndX - line1StartX) - + (line2EndX - line2StartX) * (line1EndY - line1StartY); + if (denominator === 0) { + if (result.x !== null && result.y !== null) { + return result; + } else { + return false; + } + } + a = line1StartY - line2StartY; + b = line1StartX - line2StartX; + numerator1 = (line2EndX - line2StartX) * a - (line2EndY - line2StartY) * b; + numerator2 = (line1EndX - line1StartX) * a - (line1EndY - line1StartY) * b; + a = numerator1 / denominator; + b = numerator2 / denominator; + + // if we cast these lines infinitely in both directions, they intersect here: + result.x = line1StartX + a * (line1EndX - line1StartX); + result.y = line1StartY + a * (line1EndY - line1StartY); + + // if line1 is a segment and line2 is infinite, they intersect if: + if (a >= 0 && a <= 1) { + result.onLine1 = true; + } + // if line2 is a segment and line1 is infinite, they intersect if: + if (b >= 0 && b <= 1) { + result.onLine2 = true; + } + // if line1 and line2 are segments, they intersect if both of the above are true + if (result.onLine1 && result.onLine2) { + return [result.x, result.y]; + } else { + return false; + } +} + export { kinks }; export default kinks; diff --git a/packages/turf-kinks/package.json b/packages/turf-kinks/package.json index 1f4e004587..33c573846e 100644 --- a/packages/turf-kinks/package.json +++ b/packages/turf-kinks/package.json @@ -66,7 +66,6 @@ "dependencies": { "@turf/helpers": "workspace:^", "@types/geojson": "^7946.0.10", - "sweepline-intersections": "^1.5.0", "tslib": "^2.6.2" } } diff --git a/packages/turf-kinks/test/in/issue-2627.geojson b/packages/turf-kinks/test/in/issue-2627.geojson new file mode 100644 index 0000000000..c27ee8dbd6 --- /dev/null +++ b/packages/turf-kinks/test/in/issue-2627.geojson @@ -0,0 +1,195 @@ +{ + "type": "Polygon", + "coordinates": [ + [ + [11.032103, 53.905391], + [11.032478, 53.90552], + [11.032784, 53.905631], + [11.033154, 53.905675], + [11.03376, 53.905665], + [11.034415, 53.90571], + [11.034833, 53.905631], + [11.035396, 53.905492], + [11.036094, 53.905583], + [11.03662, 53.90565], + [11.036958, 53.905574], + [11.037118, 53.905526], + [11.037194, 53.905991], + [11.037741, 53.90898], + [11.038202, 53.911439], + [11.038519, 53.913243], + [11.038932, 53.915534], + [11.039125, 53.91658], + [11.039436, 53.918137], + [11.038175, 53.91785], + [11.038368, 53.917654], + [11.037183, 53.917379], + [11.036979, 53.91743], + [11.036662, 53.917695], + [11.036341, 53.918071], + [11.035691, 53.917913], + [11.035332, 53.917869], + [11.032505, 53.917787], + [11.032022, 53.917749], + [11.032135, 53.918662], + [11.031582, 53.918731], + [11.031067, 53.918848], + [11.030268, 53.91912], + [11.028396, 53.919793], + [11.02639, 53.920548], + [11.02573, 53.920772], + [11.025456, 53.920823], + [11.023611, 53.909521], + [11.024276, 53.909518], + [11.025022, 53.909521], + [11.025783, 53.909511], + [11.028165, 53.909508], + [11.028664, 53.909527], + [11.028868, 53.909464], + [11.02904, 53.908601], + [11.029201, 53.907208], + [11.02934, 53.90625], + [11.029839, 53.906275], + [11.030123, 53.90625], + [11.030461, 53.906149], + [11.031008, 53.905963], + [11.031298, 53.905852], + [11.03162, 53.905523], + [11.031824, 53.9054], + [11.032103, 53.905391] + ], + [ + [11.03228, 53.90643], + [11.032054, 53.906446], + [11.031904, 53.906478], + [11.031711, 53.906655], + [11.031588, 53.906762], + [11.031765, 53.906775], + [11.031985, 53.906699], + [11.032124, 53.906645], + [11.032301, 53.906629], + [11.032435, 53.906509], + [11.03228, 53.90643] + ], + [ + [11.031631, 53.908491], + [11.031411, 53.908497], + [11.03126, 53.908671], + [11.031368, 53.908845], + [11.0317, 53.908901], + [11.031931, 53.908816], + [11.032012, 53.908699], + [11.031926, 53.908544], + [11.031631, 53.908491] + ], + [ + [11.033261, 53.909436], + [11.033288, 53.909543], + [11.033422, 53.909502], + [11.033369, 53.909439], + [11.033261, 53.909436] + ], + [ + [11.031277, 53.911227], + [11.031159, 53.911265], + [11.031089, 53.911325], + [11.031153, 53.911455], + [11.031368, 53.911439], + [11.031421, 53.91129], + [11.031277, 53.911227] + ], + [ + [11.029549, 53.911297], + [11.029567, 53.911309], + [11.02956, 53.911306], + [11.029458, 53.911433], + [11.029608, 53.911493], + [11.02971, 53.911404], + [11.029567, 53.911309], + [11.029576, 53.911313], + [11.029549, 53.911297] + ], + [ + [11.02764, 53.911442], + [11.027521, 53.911534], + [11.027709, 53.911597], + [11.027849, 53.911496], + [11.02764, 53.911442] + ], + [ + [11.034109, 53.912001], + [11.033986, 53.912039], + [11.034066, 53.912166], + [11.034168, 53.912197], + [11.034281, 53.912159], + [11.034302, 53.912077], + [11.034109, 53.912001] + ], + [ + [11.029367, 53.913382], + [11.029276, 53.913404], + [11.029147, 53.91355], + [11.029142, 53.91367], + [11.02927, 53.913746], + [11.029453, 53.913746], + [11.029501, 53.91348], + [11.029378, 53.913388], + [11.029383, 53.913407], + [11.029367, 53.913382] + ], + [ + [11.035895, 53.913486], + [11.035783, 53.913496], + [11.03581, 53.913584], + [11.036029, 53.913641], + [11.036137, 53.913572], + [11.035895, 53.913486] + ], + [ + [11.032178, 53.913496], + [11.03199, 53.913534], + [11.031813, 53.913692], + [11.031491, 53.913869], + [11.031083, 53.913957], + [11.03066, 53.914071], + [11.030349, 53.914169], + [11.029941, 53.914358], + [11.029807, 53.914498], + [11.029801, 53.914769], + [11.029925, 53.914959], + [11.030257, 53.915038], + [11.030654, 53.915013], + [11.031024, 53.91494], + [11.031464, 53.914791], + [11.031738, 53.914592], + [11.032199, 53.914093], + [11.032344, 53.913657], + [11.032178, 53.913496] + ], + [ + [11.034232, 53.91621], + [11.034109, 53.916333], + [11.034189, 53.916463], + [11.034324, 53.916418], + [11.034318, 53.916292], + [11.034232, 53.91621] + ], + [ + [11.028745, 53.916801], + [11.028584, 53.916918], + [11.028707, 53.917022], + [11.028863, 53.917117], + [11.0289, 53.917009], + [11.028954, 53.916873], + [11.028745, 53.916801] + ], + [ + [11.035874, 53.917521], + [11.035761, 53.917578], + [11.036094, 53.917704], + [11.036185, 53.917625], + [11.035879, 53.917527], + [11.035874, 53.917521] + ] + ] +} diff --git a/packages/turf-kinks/test/out/issue-2627.geojson b/packages/turf-kinks/test/out/issue-2627.geojson new file mode 100644 index 0000000000..d89e9a3755 --- /dev/null +++ b/packages/turf-kinks/test/out/issue-2627.geojson @@ -0,0 +1,29 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [11.029567, 53.911309] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [11.029567, 53.911309] + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "Point", + "coordinates": [11.029567, 53.911309] + } + } + ] +} diff --git a/packages/turf-kinks/test/out/switzerlandKinked.geojson b/packages/turf-kinks/test/out/switzerlandKinked.geojson index 0bbf6429ca..732c7bb105 100644 --- a/packages/turf-kinks/test/out/switzerlandKinked.geojson +++ b/packages/turf-kinks/test/out/switzerlandKinked.geojson @@ -6,7 +6,7 @@ "properties": {}, "geometry": { "type": "Point", - "coordinates": [9.182061729855718, 47.67348418083509] + "coordinates": [9.219017027587402, 47.657889465138915] } }, { @@ -14,7 +14,7 @@ "properties": {}, "geometry": { "type": "Point", - "coordinates": [9.219017027587402, 47.657889465138915] + "coordinates": [9.182061729855718, 47.67348418083509] } }, { diff --git a/packages/turf-kinks/test/out/triple.geojson b/packages/turf-kinks/test/out/triple.geojson index 6c912ab4ec..cf0bf19ad8 100644 --- a/packages/turf-kinks/test/out/triple.geojson +++ b/packages/turf-kinks/test/out/triple.geojson @@ -6,7 +6,7 @@ "properties": {}, "geometry": { "type": "Point", - "coordinates": [-45, -7.5] + "coordinates": [-45, 2.5] } }, { @@ -22,7 +22,7 @@ "properties": {}, "geometry": { "type": "Point", - "coordinates": [-45, 2.5] + "coordinates": [-45, -7.5] } }, { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 06baabcf4a..79e22f59c0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3619,9 +3619,6 @@ importers: '@types/geojson': specifier: ^7946.0.10 version: 7946.0.14 - sweepline-intersections: - specifier: ^1.5.0 - version: 1.5.0 tslib: specifier: ^2.6.2 version: 2.6.2