Created
November 27, 2019 20:28
-
-
Save Dubiy/7fb9fdf9e2ac4dd8132f44e8b53c3092 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let linesIntersect = (a, b, c, d, threshold = 0.0001, debug = false) => { | |
if (debug) { | |
console.warn('linesIntersect', 'debug') | |
} | |
let result = {type: 'none', isIntersects: false, points: []} | |
// https://web.archive.org/web/20120303204205/http://local.wasp.uwa.edu.au:80/~pbourke/geometry/lineline2d/ | |
let denominator = (d.y - c.y) * (b.x - a.x) - (d.x - c.x) * (b.y - a.y) | |
let numerator1 = (d.x - c.x) * (a.y - c.y) - (d.y - c.y) * (a.x - c.x) | |
let numerator2 = (b.x - a.x) * (a.y - c.y) - (b.y - a.y) * (a.x - c.x) | |
if (denominator === 0) { | |
// lines are parallel or collinear | |
if (numerator1 === 0 && numerator2 === 0) { | |
result.type = 'collinear' | |
} else { | |
result.type = 'parallel' | |
} | |
result.points = [{point: a, distance: distanceToLine(a, {geometry: {vertices: [c, d]}})}, { | |
point: b, | |
distance: distanceToLine(b, {geometry: {vertices: [c, d]}}) | |
}, {point: c, distance: distanceToLine(c, {geometry: {vertices: [a, b]}})}, { | |
point: d, | |
distance: distanceToLine(d, {geometry: {vertices: [a, b]}}) | |
}].sort((a, b) => { | |
return a.distance > b.distance | |
}).splice(0, 2).filter(point => point.distance <= threshold) | |
result.isIntersects = result.points.length > 0 | |
return result | |
} | |
const uA = numerator1 / denominator | |
const uB = numerator2 / denominator | |
if (uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1) { | |
result.type = 'intersecting' | |
result.isIntersects = true | |
result.points = [{distance: 0, point: {x: a.x + (uA * (b.x - a.x)), y: a.y + (uA * (b.y - a.y))}}] | |
return result | |
} else if (threshold > 0) { | |
// not intersected, but check if intersection point is closer than threshold | |
result.points = [{point: a, distance: distanceToLine(a, {geometry: {vertices: [c, d]}})}, { | |
point: b, | |
distance: distanceToLine(b, {geometry: {vertices: [c, d]}}) | |
}, {point: c, distance: distanceToLine(c, {geometry: {vertices: [a, b]}})}, { | |
point: d, | |
distance: distanceToLine(d, {geometry: {vertices: [a, b]}}) | |
}].sort((a, b) => { | |
return a.distance > b.distance | |
}).splice(0, 1).filter(point => point.distance < threshold) | |
if (result.points.length) { | |
result.type = 'intersecting' | |
result.isIntersects = true | |
return result | |
} | |
} | |
return result | |
}; | |
let distanceToLineSegment = (lx1, ly1, lx2, ly2, px, py) => { | |
// source from https://github.com/scottglz/distance-to-line-segment/blob/master/index.js | |
let ldx = lx2 - lx1 | |
let ldy = ly2 - ly1 | |
let lineLengthSquared = ldx * ldx + ldy * ldy | |
let t // t===0 at line pt 1 and t ===1 at line pt 2 | |
if (!lineLengthSquared) { | |
// 0-length line segment. Any t will return same result | |
t = 0 | |
} else { | |
t = ((px - lx1) * ldx + (py - ly1) * ldy) / lineLengthSquared | |
if (t < 0) { t = 0 } else if (t > 1) { t = 1 } | |
} | |
let lx = lx1 + t * ldx | |
let ly = ly1 + t * ldy | |
let dx = px - lx | |
let dy = py - ly | |
return Math.sqrt(dx * dx + dy * dy) | |
}; | |
let distanceToLine = (vertex, line) => { | |
let x1 = line.geometry.vertices[0].x; | |
let y1 = line.geometry.vertices[0].y; | |
let x2 = line.geometry.vertices[1].x; | |
let y2 = line.geometry.vertices[1].y; | |
return distanceToLineSegment(x1, y1, x2, y2, vertex.x, vertex.y); | |
}; | |
console.log(linesIntersect( | |
{x: 10, y: 10}, | |
{x: 20, y: 10}, | |
{x: 15, y: 5}, | |
{x: 15, y: 15}, | |
)); | |
console.log(linesIntersect( | |
{x: 10, y: 10}, | |
{x: 20, y: 10}, | |
{x: 15, y: 5}, | |
{x: 15, y: 7}, | |
)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment