import { feature, featureCollection, point, } from "@turf/helpers"; import { getCoords } from "@turf/invariant"; import lineSegment from "@turf/line-segment"; import { featureEach } from "@turf/meta"; import rbush from "geojson-rbush"; /** * Takes any LineString or Polygon GeoJSON and returns the intersecting point(s). * * @name lineIntersect * @param {GeoJSON} line1 any LineString or Polygon * @param {GeoJSON} line2 any LineString or Polygon * @returns {FeatureCollection} point(s) that intersect both * @example * var line1 = turf.lineString([[126, -11], [129, -21]]); * var line2 = turf.lineString([[123, -18], [131, -14]]); * var intersects = turf.lineIntersect(line1, line2); * * //addToMap * var addToMap = [line1, line2, intersects] */ function lineIntersect(line1, line2) { var unique = {}; var results = []; // First, normalize geometries to features // Then, handle simple 2-vertex segments if (line1.type === "LineString") { line1 = feature(line1); } if (line2.type === "LineString") { line2 = feature(line2); } if (line1.type === "Feature" && line2.type === "Feature" && line1.geometry !== null && line2.geometry !== null && line1.geometry.type === "LineString" && line2.geometry.type === "LineString" && line1.geometry.coordinates.length === 2 && line2.geometry.coordinates.length === 2) { var intersect = intersects(line1, line2); if (intersect) { results.push(intersect); } return featureCollection(results); } // Handles complex GeoJSON Geometries var tree = rbush(); tree.load(lineSegment(line2)); featureEach(lineSegment(line1), function (segment) { featureEach(tree.search(segment), function (match) { var intersect = intersects(segment, match); if (intersect) { // prevent duplicate points https://github.com/Turfjs/turf/issues/688 var key = getCoords(intersect).join(","); if (!unique[key]) { unique[key] = true; results.push(intersect); } } }); }); return featureCollection(results); } /** * Find a point that intersects LineStrings with two coordinates each * * @private * @param {Feature} line1 GeoJSON LineString (Must only contain 2 coordinates) * @param {Feature} line2 GeoJSON LineString (Must only contain 2 coordinates) * @returns {Feature} intersecting GeoJSON Point */ function intersects(line1, line2) { var coords1 = getCoords(line1); var coords2 = getCoords(line2); if (coords1.length !== 2) { throw new Error(" line1 must only contain 2 coordinates"); } if (coords2.length !== 2) { throw new Error(" line2 must only contain 2 coordinates"); } var x1 = coords1[0][0]; var y1 = coords1[0][1]; var x2 = coords1[1][0]; var y2 = coords1[1][1]; var x3 = coords2[0][0]; var y3 = coords2[0][1]; var x4 = coords2[1][0]; var y4 = coords2[1][1]; var denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); var numeA = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3); var numeB = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3); if (denom === 0) { if (numeA === 0 && numeB === 0) { return null; } return null; } var uA = numeA / denom; var uB = numeB / denom; if (uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1) { var x = x1 + uA * (x2 - x1); var y = y1 + uA * (y2 - y1); return point([x, y]); } return null; } export default lineIntersect;