UNPKG

bentley-ottman-sweepline

Version:

Bentley-Ottman segments intersection algorithm

244 lines (215 loc) 5.73 kB
var EPS = 1E-9; /** * @param a vector * @param b vector * @param c vector */ function onSegment(a, b, c) { var x1 = a[0], x2 = b[0], x3 = c[0], y1 = a[1], y2 = b[1], y3 = c[1]; return (Math.min(x1, x2) <= x3) && (x3 <= Math.max(x1, x2)) && (Math.min(y1, y2) <= y3) && (y3 <= Math.max(y1, y2)); } /** * ac x bc * @param a vector * @param b vector * @param c vector */ function direction(a, b, c) { var x1 = a[0], x2 = b[0], x3 = c[0], y1 = a[1], y2 = b[1], y3 = c[1]; return (x3 - x1) * (y2 - y1) - (x2 - x1) * (y3 - y1); } /** * @param a segment1 * @param b segment2 */ function segmentsIntersect(a, b) { var p1 = a[0], p2 = a[1], p3 = b[0], p4 = b[1], d1 = direction(p3, p4, p1), d2 = direction(p3, p4, p2), d3 = direction(p1, p2, p3), d4 = direction(p1, p2, p4); if (((d1 > 0 && d2 < 0) || (d1 < 0 && d2 > 0)) && ((d3 > 0 && d4 < 0) || (d3 < 0 && d4 > 0))) { return true; } else if (d1 === 0 && onSegment(p3, p4, p1)) { return true; } else if (d2 === 0 && onSegment(p3, p4, p2)) { return true; } else if (d3 === 0 && onSegment(p1, p2, p3)) { return true; } else if (d4 === 0 && onSegment(p1, p2, p4)) { return true; } return false; } /** * @param a segment1 * @param b segment2 */ function findSegmentsIntersection (a, b) { var x1 = a[0][0], y1 = a[0][1], x2 = a[1][0], y2 = a[1][1], x3 = b[0][0], y3 = b[0][1], x4 = b[1][0], y4 = b[1][1]; var x = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)); var y = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)); if (isNaN(x)||isNaN(y)) { return false; } else { if (x1 >= x2) { if (!between(x2, x, x1)) {return false;} } else { if (!between(x1, x, x2)) {return false;} } if (y1 >= y2) { if (!between(y2, y, y1)) {return false;} } else { if (!between(y1, y, y2)) {return false;} } if (x3 >= x4) { if (!between(x4, x, x3)) {return false;} } else { if (!between(x3, x, x4)) {return false;} } if (y3 >= y4) { if (!between(y4, y, y3)) {return false;} } else { if (!between(y3, y, y4)) {return false;} } } return [x, y]; } function between (a, b, c) { return a - EPS <= b && b <= c + EPS; } /** * @param a segment1 * @param b segment2 */ function compareSegments(a, b) { var x1 = a[0][0], y1 = a[0][1], x2 = a[1][0], y2 = a[1][1], x3 = b[0][0], y3 = b[0][1], x4 = b[1][0], y4 = b[1][1]; var currentX, ay, by, deltaY, deltaX1, deltaX2; if (a === b) { return 0; } currentX = this.x; ay = getY(a, currentX); by = getY(b, currentX); deltaY = ay - by; if (Math.abs(deltaY) > EPS) { return deltaY < 0 ? -1 : 1; } else { var aSlope = getSlope(a), bSlope = getSlope(b); if (aSlope !== bSlope) { if (this.position === 'before') { return aSlope > bSlope ? -1 : 1; } else { return aSlope > bSlope ? 1 : -1; } } } deltaX1 = x1 - x3; if (deltaX1 !== 0) { return deltaX1 < 0 ? -1 : 1; } deltaX2 = x2 - x4; if (deltaX2 !== 0) { return deltaX2 < 0 ? -1 : 1; } return 0; }; /** * @param a point1 * @param b point2 */ function comparePoints(a, b) { var aIsArray = Array.isArray(a), bIsArray = Array.isArray(b), x1 = aIsArray ? a[0] : a.x, y1 = aIsArray ? a[1] : a.y, x2 = bIsArray ? b[0] : b.x, y2 = bIsArray ? b[1] : b.y; if (x1 - x2 > EPS || (Math.abs(x1 - x2) < EPS && y1 - y2 > EPS)) { return 1; } else if (x2 - x1 > EPS || (Math.abs(x1 - x2) < EPS && y2 - y1 > EPS)) { return -1; } else if (Math.abs(x1 - x2) < EPS && Math.abs(y1 - y2) < EPS ) { return 0; } } function getSlope(segment) { var x1 = segment[0][0], y1 = segment[0][1], x2 = segment[1][0], y2 = segment[1][1]; if (x1 === x2) { return (y1 < y2) ? Infinity : - Infinity; } else { return (y2 - y1) / (x2 - x1); } }; function getY(segment, x) { var begin = segment[0], end = segment[1], span = segment[1][0] - segment[0][0], deltaX0, deltaX1, ifac, fac; if (x <= begin[0]) { return begin[1]; } else if (x >= end[0]) { return end[1]; } deltaX0 = x - begin[0]; deltaX1 = end[0] - x; if (deltaX0 > deltaX1) { ifac = deltaX0 / span fac = 1 - ifac; } else { fac = deltaX1 / span ifac = 1 - fac; } return (begin[1] * fac) + (end[1] * ifac); }; module.exports = { EPS: EPS, onSegment: onSegment, direction: direction, segmentsIntersect: segmentsIntersect, findSegmentsIntersection: findSegmentsIntersection, compareSegments: compareSegments, comparePoints: comparePoints }