UNPKG

@cantoo/pdf-lib

Version:

Create and modify PDF files with JavaScript

253 lines 10.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getIntersections = exports.intersectionCircle = exports.intersectionCircleLine = exports.intersectionLine = exports.intersection = exports.intersections = void 0; const tslib_1 = require("tslib"); const Arc_1 = tslib_1.__importDefault(require("./elements/Arc")); const Circle_1 = tslib_1.__importDefault(require("./elements/Circle")); const Ellipse_1 = tslib_1.__importDefault(require("./elements/Ellipse")); const Line_1 = tslib_1.__importDefault(require("./elements/Line")); const Plot_1 = tslib_1.__importDefault(require("./elements/Plot")); const Point_1 = tslib_1.__importDefault(require("./elements/Point")); const Rectangle_1 = tslib_1.__importDefault(require("./elements/Rectangle")); const Segment_1 = tslib_1.__importDefault(require("./elements/Segment")); const maths_1 = require("./maths"); const intersections = (A, B) => { if (A instanceof Point_1.default || B instanceof Point_1.default) return []; else if (A instanceof Text || B instanceof Text) return []; else if (A instanceof Image || B instanceof Image) return []; // TODO: calculate the coords of the intersection: https://www.emathzone.com/tutorials/geometry/intersection-of-line-and-ellipse.html else if (A instanceof Line_1.default) return intersectionsLine(A, B); else if (A instanceof Segment_1.default) { return intersectionsLine(A.getLine(), B).filter((P) => A.includes(new Point_1.default(P))); } else if (A instanceof Circle_1.default) return intersectionsCircle(A, B); else if (A instanceof Arc_1.default) { return intersectionsCircle(A.getCircle(), B).filter((P) => A.includes(new Point_1.default(P))); } else if (A instanceof Plot_1.default) return intersectionsPlot(A, B); else if (A instanceof Rectangle_1.default) return intersectionsRectangle(A, B); else if (A instanceof Ellipse_1.default) return intersectionsEllipse(A, B); return A; }; exports.intersections = intersections; const intersection = (A, B) => (0, exports.intersections)(A, B)[0]; exports.intersection = intersection; const intersectionsLine = (A, B) => { if (B instanceof Line_1.default) return (0, exports.intersectionLine)(A, B); else if (B instanceof Segment_1.default) { return (0, exports.intersectionLine)(A, B.getLine()).filter((P) => B.includes(new Point_1.default(P))); } else if (B instanceof Circle_1.default) return (0, exports.intersectionCircleLine)(B, A); else if (B instanceof Arc_1.default) { return intersectionsCircle(B.getCircle(), A).filter((P) => B.includes(new Point_1.default(P))); } else if (B instanceof Plot_1.default) return intersectionsPlot(B, A); else if (B instanceof Rectangle_1.default) return intersectionsRectangle(B, A); else if (B instanceof Ellipse_1.default) return intersectionsEllipse(B, A); return B; }; const intersectionsEllipse = (A, B) => { if (B instanceof Line_1.default) return intersectionsLineAndEllipse(A, B); else if (B instanceof Segment_1.default) { return intersectionsEllipse(A, B.getLine()).filter((P) => B.includes(new Point_1.default(P))); } // TODO: // else if (B instanceof Circle) return intersectionEllipseCircle(B, A) else if (B instanceof Circle_1.default) return []; // TODO: // else if (B instanceof Ellipse) return intersectionEllipseEllipse(B, A) else if (B instanceof Ellipse_1.default) return []; else if (B instanceof Arc_1.default) { return intersectionsEllipse(A, B.getCircle()).filter((P) => B.includes(new Point_1.default(P))); } else if (B instanceof Plot_1.default) return intersectionsPlot(B, A); else if (B instanceof Rectangle_1.default) return intersectionsRectangle(B, A); return B; }; const intersectionsLineAndEllipse = (A, B) => { const center = A.center().toCoords(); const a = A.a(); const b = A.b(); const rotation = A.rotation(); const isLineParallel2YAxis = (0, maths_1.isEqual)(B.dirVect().x, 0); // this is a dummy value to represent a point on the line const p1Y = isLineParallel2YAxis ? 1 : B.y(1); const p1X = isLineParallel2YAxis ? B.origin().toCoords().x : 1; const p1 = { x: p1X, y: p1Y }; // this is a dummy value to represent a point on the line const p2Y = isLineParallel2YAxis ? 2 : B.y(2); const p2X = isLineParallel2YAxis ? B.origin().toCoords().x : 2; const p2 = { x: p2X, y: p2Y }; const p1Normalized = (0, maths_1.rotate)({ x: p1.x - center.x, y: p1.y - center.y }, -rotation); const p2Normalized = (0, maths_1.rotate)({ x: p2.x - center.x, y: p2.y - center.y }, -rotation); const angular = (p1Normalized.y - p2Normalized.y) / (p1Normalized.x - p2Normalized.x); const linear = p1Normalized.y - angular * p1Normalized.x; const lineY = (x) => angular * x + linear; const denormalize = (coord) => { const rotated = (0, maths_1.rotate)(coord, rotation); return { x: rotated.x + center.x, y: rotated.y + center.y, }; }; // Intersection with vertical line if ((0, maths_1.isEqual)(p1Normalized.x - p2Normalized.x, 0)) { const x = p1Normalized.x; const vDelta = Math.pow(b, 2) - (Math.pow(x, 2) * Math.pow(b, 2)) / Math.pow(a, 2); if (vDelta < 0) return []; else if (vDelta === 0) { return [{ x, y: 0 }].map(denormalize); } else { const y1 = Math.sqrt((Math.pow(b, 2) * (Math.pow(a, 2) - Math.pow(x, 2))) / Math.pow(a, 2)); const y2 = -y1; return [ { x, y: y1 }, { x, y: y2 }, ].map(denormalize); } } // Intersection with any line // the quadratic equation is: // alpha * x ** 2 + beta * x + gamma = 0 const alpha = Math.pow(a, 2) * Math.pow(angular, 2) + Math.pow(b, 2); const beta = 2 * Math.pow(a, 2) * (angular * linear); const gamma = Math.pow(a, 2) * (Math.pow(linear, 2) - Math.pow(b, 2)); const delta = Math.pow(beta, 2) - 4 * alpha * gamma; if (delta < 0) return []; else if (delta === 0) { const x = -(Math.pow(beta, 2)) / (2 * alpha); const y = lineY(x); return [{ x, y }].map(denormalize); } else { const x1 = (-beta + Math.sqrt(delta)) / (2 * alpha); const y1 = lineY(x1); const x2 = (-beta - Math.sqrt(delta)) / (2 * alpha); const y2 = lineY(x2); return [ { x: x1, y: y1 }, { x: x2, y: y2 }, ].map(denormalize); } }; const intersectionLine = (A, B) => { if ((0, maths_1.isColinear)(A.dirVect(), B.dirVect())) return []; else { const { x: ux, y: uy } = A.dirVect(); const { x: vx, y: vy } = B.dirVect(); const { x: xA, y: yA } = A.origin().toCoords(); const { x: xB, y: yB } = B.origin().toCoords(); const x = (ux * (vx * (yA - yB) + vy * xB) - uy * vx * xA) / (ux * vy - uy * vx); const y = (uy * (vy * (xA - xB) + vx * yB) - ux * vy * yA) / (uy * vx - ux * vy); return [{ x, y }]; } }; exports.intersectionLine = intersectionLine; const intersectionsPlot = (A, B) => { const points = A.getPoints().map((pt) => new Point_1.default(pt)); const head = points.pop(); const segments = points.map((pt, i) => new Segment_1.default(pt, points[i + 1] || head)); // @ts-ignore const inters = segments.map((s) => (0, exports.intersections)(s, B)).flat(); return inters; }; const intersectionsRectangle = (A, B) => { const P1 = A.getCoords(); const P3 = A.getEnd(); const P2 = { x: P1.x, y: P3.y }; const P4 = { x: P3.x, y: P1.y }; return (0, exports.intersections)(new Plot_1.default([P1, P2, P3, P4, P1]), B); }; const intersectionCircleLine = (A, B) => { const rA = A.ray(); const O = A.center(); const H = B.orthoProjection(O); const OH = (0, maths_1.distance)(O, H); // The line is tangeant if ((0, maths_1.isEqual)(OH, rA)) return [H]; // The line is too far from the circle else if (OH > A.ray()) return []; // The line cut the circle in 2 points else { // Pythagore const HP = Math.sqrt(rA * rA - OH * OH); const vect = (0, maths_1.unitVector)(B.dirVect()); return [H.plus((0, maths_1.times)(vect, HP)), H.plus((0, maths_1.times)(vect, -HP))]; } }; exports.intersectionCircleLine = intersectionCircleLine; const intersectionCircle = (A, B) => { const oA = A.center(); const oB = B.center(); const rA = A.ray(); const rB = B.ray(); const axis = (0, maths_1.vector)(oA, oB); const CC = (0, maths_1.norm)(axis); // The circles are tangeant if ((0, maths_1.isEqual)(CC, rA + rB)) return [A.orthoProjection(oB).toCoords()]; // The circles are too far from eachother else if (CC > rA + rB) return []; // The intersections belong to an orthogonal axis else { const ratio = 1 / 2 + (rA * rA - rB * rB) / (CC * CC) / 2; const H = oA.plus((0, maths_1.times)(axis, ratio)); return (0, exports.intersectionCircleLine)(A, new Line_1.default(H, H.plus((0, maths_1.orthogonal)(axis)))); } }; exports.intersectionCircle = intersectionCircle; const intersectionsCircle = (A, B) => { if (B instanceof Circle_1.default) return (0, exports.intersectionCircle)(A, B); else if (B instanceof Line_1.default) return (0, exports.intersectionCircleLine)(A, B); else if (B instanceof Segment_1.default) { return (0, exports.intersectionCircleLine)(A, B.getLine()).filter((P) => B.includes(new Point_1.default(P))); } else if (B instanceof Arc_1.default) { return (0, exports.intersectionCircle)(A, B.getCircle()).filter((P) => B.includes(new Point_1.default(P))); } else if (B instanceof Plot_1.default) return intersectionsPlot(B, A); else if (B instanceof Rectangle_1.default) return intersectionsRectangle(B, A); else if (B instanceof Ellipse_1.default) return intersectionsEllipse(B, A); return B; }; const getIntersections = (elements) => { const checked = []; const inters = []; elements.forEach((elt) => { checked.forEach((e) => inters.push(...(0, exports.intersections)(e, elt))); checked.push(elt); }); return inters; }; exports.getIntersections = getIntersections; //# sourceMappingURL=intersections.js.map