Skip to content

Instantly share code, notes, and snippets.

@Dubiy
Created November 27, 2019 20:28
Show Gist options
  • Save Dubiy/7fb9fdf9e2ac4dd8132f44e8b53c3092 to your computer and use it in GitHub Desktop.
Save Dubiy/7fb9fdf9e2ac4dd8132f44e8b53c3092 to your computer and use it in GitHub Desktop.
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