137 lines
4.9 KiB
JavaScript
Executable File
137 lines
4.9 KiB
JavaScript
Executable File
import { point } from "@turf/helpers";
|
|
/**
|
|
* Takes a {@link LineString|linestring}, {@link MultiLineString|multi-linestring},
|
|
* {@link MultiPolygon|multi-polygon} or {@link Polygon|polygon} and
|
|
* returns {@link Point|points} at all self-intersections.
|
|
*
|
|
* @name kinks
|
|
* @param {Feature<LineString|MultiLineString|MultiPolygon|Polygon>} featureIn input feature
|
|
* @returns {FeatureCollection<Point>} self-intersections
|
|
* @example
|
|
* var poly = turf.polygon([[
|
|
* [-12.034835, 8.901183],
|
|
* [-12.060413, 8.899826],
|
|
* [-12.03638, 8.873199],
|
|
* [-12.059383, 8.871418],
|
|
* [-12.034835, 8.901183]
|
|
* ]]);
|
|
*
|
|
* var kinks = turf.kinks(poly);
|
|
*
|
|
* //addToMap
|
|
* var addToMap = [poly, kinks]
|
|
*/
|
|
export default function kinks(featureIn) {
|
|
var coordinates;
|
|
var feature;
|
|
var results = {
|
|
type: "FeatureCollection",
|
|
features: [],
|
|
};
|
|
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.apply([], 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");
|
|
}
|
|
coordinates.forEach(function (line1) {
|
|
coordinates.forEach(function (line2) {
|
|
for (var 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 (var 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;
|
|
}
|
|
}
|
|
var intersection = 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, line1StartY, line1EndX, line1EndY, line2StartX, line2StartY, line2EndX, line2EndY) {
|
|
// 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
|
|
var denominator;
|
|
var a;
|
|
var b;
|
|
var numerator1;
|
|
var numerator2;
|
|
var 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;
|
|
}
|
|
}
|