@pdfme/pdf-lib
Version:
Create and modify PDF files with JavaScript
256 lines • 10.2 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.intersections = intersections;
exports.intersection = intersection;
exports.intersectionLine = intersectionLine;
exports.intersectionCircleLine = intersectionCircleLine;
exports.intersectionCircle = intersectionCircle;
exports.getIntersections = getIntersections;
const Arc_1 = __importDefault(require("./elements/Arc"));
const Circle_1 = __importDefault(require("./elements/Circle"));
const Ellipse_1 = __importDefault(require("./elements/Ellipse"));
const Line_1 = __importDefault(require("./elements/Line"));
const Plot_1 = __importDefault(require("./elements/Plot"));
const Point_1 = __importDefault(require("./elements/Point"));
const Rectangle_1 = __importDefault(require("./elements/Rectangle"));
const Segment_1 = __importDefault(require("./elements/Segment"));
const maths_1 = require("./maths");
function 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;
}
function intersection(A, B) {
return intersections(A, B)[0];
}
function intersectionsLine(A, B) {
if (B instanceof Line_1.default)
return intersectionLine(A, B);
else if (B instanceof Segment_1.default) {
return intersectionLine(A, B.getLine()).filter((P) => B.includes(new Point_1.default(P)));
}
else if (B instanceof Circle_1.default)
return 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;
}
function 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;
}
function 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 delta = b ** 2 - (x ** 2 * b ** 2) / a ** 2;
if (delta < 0)
return [];
else if (delta === 0) {
return [{ x, y: 0 }].map(denormalize);
}
else {
const y1 = Math.sqrt((b ** 2 * (a ** 2 - x ** 2)) / 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 = a ** 2 * angular ** 2 + b ** 2;
const beta = 2 * a ** 2 * (angular * linear);
const gamma = a ** 2 * (linear ** 2 - b ** 2);
const delta = beta ** 2 - 4 * alpha * gamma;
if (delta < 0)
return [];
else if (delta === 0) {
const x = -(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);
}
}
function 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 }];
}
}
function 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) => intersections(s, B)).flat();
return inters;
}
function 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 intersections(new Plot_1.default([P1, P2, P3, P4, P1]), B);
}
function 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))];
}
}
function 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 intersectionCircleLine(A, new Line_1.default(H, H.plus((0, maths_1.orthogonal)(axis))));
}
}
function intersectionsCircle(A, B) {
if (B instanceof Circle_1.default)
return intersectionCircle(A, B);
else if (B instanceof Line_1.default)
return intersectionCircleLine(A, B);
else if (B instanceof Segment_1.default) {
return intersectionCircleLine(A, B.getLine()).filter((P) => B.includes(new Point_1.default(P)));
}
else if (B instanceof Arc_1.default) {
return 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;
}
function getIntersections(elements) {
const checked = [];
const inters = [];
elements.forEach((elt) => {
checked.forEach((e) => inters.push(...intersections(e, elt)));
checked.push(elt);
});
return inters;
}
//# sourceMappingURL=intersections.js.map