UNPKG

lr-core

Version:
157 lines (142 loc) 4.38 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.lineLineIntersection = lineLineIntersection; exports.lineInBox = lineInBox; exports.lineInBoxOrdered = lineInBoxOrdered; exports.pointLineDistance = pointLineDistance; exports.pointLineDistanceSquared = pointLineDistanceSquared; /** * line 1 endpoints: (x0, y0), (x1, y1) * line 2 endpoints: (x2, y2), (x3, y3) * inclusive: include edge cases e.g. endpoint touching an edge or on a point (default false) * * returns: * if: there is an intersection * then: a value between 0 and 1 describing the position of intersection on line 1 * or true if lines are collinear and inclusive is true (undefined point of intersectoin) * else: null */ function lineLineIntersection(x0, y0, x1, y1, x2, y2, x3, y3, inclusive) { const x01 = x1 - x0; const y01 = y1 - y0; const x23 = x3 - x2; const y23 = y3 - y2; const _01cross23 = x01 * y23 - x23 * y01; if (_01cross23 === 0) { // collinear return inclusive ? true : null; } const orientation = _01cross23 > 0; const x02 = x2 - x0; const y02 = y2 - y0; const _02cross01 = x02 * y01 - y02 * x01; if (_02cross01 === 0 ? !inclusive : _02cross01 < 0 === orientation) { return null; } const _02cross23 = x02 * y23 - y02 * x23; if (_02cross23 === 0 ? !inclusive : _02cross23 < 0 === orientation) { return null; } if (_02cross01 === _01cross23 ? !inclusive : _02cross01 > _01cross23 === orientation) { return null; } if (_02cross23 === _01cross23 ? !inclusive : _02cross23 > _01cross23 === orientation) { return null; } return _02cross23 / _01cross23; } /** * line endpoints: (x0, y0), (x1, y1) * box corners diagonal from each other: (x2, y2), (x3, y3) * inclusive: include edge cases e.g. endpoint touching the box edge or corner (default false) * * returns true if the line is contained within or intersects with the box, false otherwise */ function lineInBox(x0, y0, x1, y1, x2, y2, x3, y3, inclusive) { if (x2 < x3) { if (y2 < y3) { return lineInBoxOrdered(x0, y0, x1, y1, x2, y2, x3, y3, inclusive); } else { return lineInBoxOrdered(x0, y0, x1, y1, x2, y3, x3, y2, inclusive); } } else { if (y2 < y3) { return lineInBoxOrdered(x0, y0, x1, y1, x3, y2, x2, y3, inclusive); } else { return lineInBoxOrdered(x0, y0, x1, y1, x3, y3, x2, y2, inclusive); } } } /** * same as lineInBox except * (x2, y2) is the top-left corner of the box * (x3, y3) is the bottom-right corner of the box */ function lineInBoxOrdered(x0, y0, x1, y1, x2, y2, x3, y3, inclusive) { let L0, R0, T0, B0, L1, R1, T1, B1; if (inclusive) { L0 = x0 < x2; R0 = x0 > x3; T0 = y0 < y2; B0 = y0 > y3; L1 = x1 < x2; R1 = x1 > x3; T1 = y1 < y2; B1 = y1 > y3; } else { L0 = x0 <= x2; R0 = x0 >= x3; T0 = y0 <= y2; B0 = y0 >= y3; L1 = x1 <= x2; R1 = x1 >= x3; T1 = y1 <= y2; B1 = y1 >= y3; } // both endpoints are totally on one side of the box if (L0 && L1 || R0 && R1 || T0 && T1 || B0 && B1) { return false; } // both endpoints are not on one side of the box // but between left/right or top/bottom sides // or one point inside if (!L0 && !R0 && (!T0 && !B0 || !L1 && !R1) || !T1 && !B1 && (!L1 && !R1 || !T0 && !B0)) { return true; } // TL - BR if ((L0 || B0 || R1 || T1) && (R0 || T0 || L1 || B1)) { return lineLineIntersection(x0, y0, x1, y1, x2, y3, x3, y2, inclusive) !== null; } else { // TR - BL return lineLineIntersection(x0, y0, x1, y1, x2, y2, x3, y3, inclusive) !== null; } } /** * point: (x0, y0) * line endpoints: (x1, y1), (x2, y2) * * returns: the closest distance between the point and the line segment */ function pointLineDistance(x0, y0, x1, y1, x2, y2) { return Math.sqrt(pointLineDistanceSquared(x0, y0, x1, y1, x2, y2)); } function pointLineDistanceSquared(x0, y0, x1, y1, x2, y2) { const x12 = x2 - x1; const y12 = y2 - y1; const x10 = x0 - x1; const y10 = y0 - y1; const dot = x10 * x12 + y10 * y12; if (dot <= 0) { return x10 * x10 + y10 * y10; } const lengthSq = x12 * x12 + y12 * y12; if (dot >= lengthSq) { const x20 = x0 - x2; const y20 = y0 - y2; return x20 * x20 + y20 * y20; } const cross = x10 * y12 - y10 * x12; return cross * cross / lengthSq; }