gramoloss
Version:
Graph theory package for edition and computation
249 lines (248 loc) • 8.74 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.isPrime = exports.booleanArrayToString = exports.isModSquare = exports.det = exports.isQuadraticBezierCurvesIntersection = exports.isTrianglesIntersection = exports.isPointInTriangle = exports.linesIntersection = exports.segmentsInteriorIntersection = exports.segmentsIntersection = exports.isSegmentsIntersection = exports.solveLinearEquation2D = exports.bezierCurvePoint = exports.binomialCoef = exports.bezierValue = exports.eqSet = void 0;
const coord_1 = require("./coord");
// ---------------------
// decide if there is equality between two sets xs and ys
function eqSet(xs, ys) {
return xs.size === ys.size && [...xs].every((x) => ys.has(x));
}
exports.eqSet = eqSet;
/**
* (1-t)^2 p0 + 2t(1-t)p1 + t^2 p2
*/
function bezierValue(t, p0, p1, p2) {
return (1.0 - t) * (1.0 - t) * p0 + 2.0 * (1.0 - t) * t * p1 + t * t * p2;
}
exports.bezierValue = bezierValue;
/**
* Compute the binomial coefficient C(n,k) by recurrence
* */
function binomialCoef(n, k) {
if (k == 0 || k == n) {
return 1;
}
else if (n < k) {
return 0;
}
else {
return binomialCoef(n - 1, k) + binomialCoef(n - 1, k - 1);
}
}
exports.binomialCoef = binomialCoef;
/**
* Compute B(t) where t is in [0,1] and B is a Bezier curve given by its list of points
* @param t in [0,1]
* @param points
* @returns Sum( points[i]*t^i*Binom(n,i))
*/
function bezierCurvePoint(t, points) {
const n = points.length - 1;
const q = 1 - t;
let r = new coord_1.Coord(0, 0);
let ti = 1; // ti = t^i
let qi = q ** n; // qi = q^(n-i)
for (let i = 0; i <= n; i++) {
const cni = binomialCoef(n, i);
r.x += cni * qi * ti * points[i].x;
r.y += cni * qi * ti * points[i].y;
ti *= t;
qi /= q;
}
return r;
}
exports.bezierCurvePoint = bezierCurvePoint;
// ---------------------
// Solve equation t u + t'v = c where u, v and c are 2d vectors
// return false if there is no solution
function solveLinearEquation2D(u, v, c) {
const det = u.x * v.y - u.y * v.x;
if (det == 0) {
return false;
}
const t1 = (c.x * v.y - c.y * v.x) / det;
const t2 = (c.y * u.x - c.x * u.y) / det;
return [t1, t2];
}
exports.solveLinearEquation2D = solveLinearEquation2D;
// ---------------------
// TODO : check the 0.01 precision
/**
* Search for an intersection between the segments [a,b] and [c,d].
* Returns an Option with the coord of the intersection if it exists.
*/
function isSegmentsIntersection(a, b, c, d) {
const r = segmentsIntersection(a, b, c, d);
return typeof r === "undefined" ? false : true;
}
exports.isSegmentsIntersection = isSegmentsIntersection;
/**
* UNTESTED
* Search for an intersection between the segments [a,b] and [c,d].
* Returns an Option with the coord of the intersection if it exists.
*/
function segmentsIntersection(a, b, c, d) {
const det = (a.x - b.x) * (d.y - c.y) - (a.y - b.y) * (d.x - c.x);
if (det == 0) {
return undefined;
}
const t1 = ((d.x - b.x) * (d.y - c.y) + (d.y - b.y) * (-(d.x - c.x))) / det;
const t2 = ((d.x - b.x) * (-(a.y - b.y)) + (d.y - b.y) * (a.x - b.x)) / det;
const condition = 0 <= t1 && t1 <= 1 && 0 <= t2 && t2 <= 1;
if (condition) {
return new coord_1.Coord(b.x + t1 * (a.x - b.x), b.y + t1 * (a.y - b.y));
}
else {
return undefined;
}
}
exports.segmentsIntersection = segmentsIntersection;
/**
* UNTESTED
* Search for an intersection between the segments ]a,b[ and ]c,d[.
* Returns an Option with the coord of the intersection if it exists.
*/
function segmentsInteriorIntersection(a, b, c, d) {
const e = 0.00001;
const det = (a.x - b.x) * (d.y - c.y) - (a.y - b.y) * (d.x - c.x);
if (det == 0) {
return undefined;
}
const t1 = ((d.x - b.x) * (d.y - c.y) + (d.y - b.y) * (-(d.x - c.x))) / det;
const t2 = ((d.x - b.x) * (-(a.y - b.y)) + (d.y - b.y) * (a.x - b.x)) / det;
const condition = 0 + e < t1 && t1 < 1 - e && 0 + e < t2 && t2 < 1 - e;
if (condition) {
return new coord_1.Coord(b.x + t1 * (a.x - b.x), b.y + t1 * (a.y - b.y));
}
else {
return undefined;
}
}
exports.segmentsInteriorIntersection = segmentsInteriorIntersection;
/**
* UNTESTED
* Search for an intersection between the lines (AB) and (CD).
* Returns an Option with the coord of the intersection if it exists.
*/
function linesIntersection(a, b, c, d) {
const det = (a.x - b.x) * (d.y - c.y) - (a.y - b.y) * (d.x - c.x);
if (det == 0) {
return undefined;
}
const t1 = ((d.x - b.x) * (d.y - c.y) + (d.y - b.y) * (-(d.x - c.x))) / det;
return new coord_1.Coord(b.x + t1 * (a.x - b.x), b.y + t1 * (a.y - b.y));
}
exports.linesIntersection = linesIntersection;
// ---------------------
// Given a point and triangle defined by its three corners q1, q2 and q3
// Returns true iff point is in the triangle
function isPointInTriangle(point, q1, q2, q3) {
const sol = solveLinearEquation2D(q1.sub(q3), q2.sub(q3), point.sub(q3));
if (typeof sol == "boolean") {
return false;
}
else {
const r = sol[0];
const s = sol[1];
return 0 <= r && 0 <= s && 0 <= 1 - r - s;
}
}
exports.isPointInTriangle = isPointInTriangle;
// ---------------------
// return true iff there is an intersection between two triangles given by their corners
// this includes convex hull intersection (if a triangle is included in the other triangle)
function isTrianglesIntersection(p1, p2, p3, q1, q2, q3) {
if (isPointInTriangle(p1, q1, q2, q3) && isPointInTriangle(p2, q1, q2, q3) && isPointInTriangle(p3, q1, q2, q3)) {
return true;
}
if (isPointInTriangle(q1, p1, p2, p3) && isPointInTriangle(q2, p1, p2, p3) && isPointInTriangle(q3, p1, p2, p3)) {
return true;
}
if (isSegmentsIntersection(p1, p2, q1, q2) ||
isSegmentsIntersection(p1, p2, q1, q3) ||
isSegmentsIntersection(p1, p2, q2, q3) ||
isSegmentsIntersection(p1, p3, q1, q2) ||
isSegmentsIntersection(p1, p3, q1, q3) ||
isSegmentsIntersection(p1, p3, q2, q3) ||
isSegmentsIntersection(p3, p2, q1, q2) ||
isSegmentsIntersection(p3, p2, q1, q3) ||
isSegmentsIntersection(p3, p2, q2, q3)) {
return true;
}
return false;
}
exports.isTrianglesIntersection = isTrianglesIntersection;
// --------------------
// Decide if there is an intersection between two quadratic Bezier curves
function isQuadraticBezierCurvesIntersection(p1, cp1, p2, q1, cp2, q2) {
if (isTrianglesIntersection(p1, cp1, p2, q1, cp2, q2) == false) {
return false;
}
const m = 10;
const bezier1 = new Array(p1, cp1, p2);
const bezier2 = new Array(q1, cp2, q2);
for (let i = 0; i < m; i++) {
const a = bezierCurvePoint(i / m, bezier1);
const b = bezierCurvePoint((i + 1) / m, bezier1);
for (let j = 0; j <= m; j++) {
const c = bezierCurvePoint(j / m, bezier2);
const d = bezierCurvePoint((j + 1) / m, bezier2);
if (isSegmentsIntersection(a, b, c, d)) {
return true;
}
}
}
return false;
}
exports.isQuadraticBezierCurvesIntersection = isQuadraticBezierCurvesIntersection;
/**
* Returns the determinant of the matrix.
* Algorithm: Leibniz formula (recursive).
* @param matrix is supposed to be square and not of size 0
* No error are triggered it is not the case.
*/
function det(matrix) {
const n = matrix.length;
if (n === 1) {
return matrix[0][0];
}
let d = 0;
for (let i = 0; i < n; i++) {
const subMatrix = matrix.slice(1).map(row => row.filter((_, j) => j !== i));
const sign = i % 2 === 0 ? 1 : -1;
d += sign * matrix[0][i] * det(subMatrix);
}
return d;
}
exports.det = det;
/**
* Return true if n is a square modulo m.
* @param n integer
* @param m integer
* @example
* isModSquare(4,5) == true // because 4 = 2^2 mod 5
* isModSquare(3,5) == false // because 0, 1 and 4 are the only squares in Z/5Z.
*/
function isModSquare(n, m) {
for (let i = 0; i < m; i++) {
if ((n - i * i) % m == 0) {
return true;
}
}
return false;
}
exports.isModSquare = isModSquare;
function booleanArrayToString(array) {
return array.map((value) => value ? '1' : '0').join('');
}
exports.booleanArrayToString = booleanArrayToString;
function isPrime(num) {
if (num <= 1)
return false;
for (let i = 2; i <= Math.sqrt(num); i++) {
if (num % i === 0)
return false;
}
return true;
}
exports.isPrime = isPrime;