import { GRAPHICS_CURVES } from '../const'; /** * Utilities for bezier curves * @class * @private */ export class BezierUtils { /** * Calculate length of bezier curve. * Analytical solution is impossible, since it involves an integral that does not integrate in general. * Therefore numerical solution is used. * * @private * @param {number} fromX - Starting point x * @param {number} fromY - Starting point y * @param {number} cpX - Control point x * @param {number} cpY - Control point y * @param {number} cpX2 - Second Control point x * @param {number} cpY2 - Second Control point y * @param {number} toX - Destination point x * @param {number} toY - Destination point y * @return {number} Length of bezier curve */ static curveLength(fromX, fromY, cpX, cpY, cpX2, cpY2, toX, toY) { const n = 10; let result = 0.0; let t = 0.0; let t2 = 0.0; let t3 = 0.0; let nt = 0.0; let nt2 = 0.0; let nt3 = 0.0; let x = 0.0; let y = 0.0; let dx = 0.0; let dy = 0.0; let prevX = fromX; let prevY = fromY; for (let i = 1; i <= n; ++i) { t = i / n; t2 = t * t; t3 = t2 * t; nt = (1.0 - t); nt2 = nt * nt; nt3 = nt2 * nt; x = (nt3 * fromX) + (3.0 * nt2 * t * cpX) + (3.0 * nt * t2 * cpX2) + (t3 * toX); y = (nt3 * fromY) + (3.0 * nt2 * t * cpY) + (3 * nt * t2 * cpY2) + (t3 * toY); dx = prevX - x; dy = prevY - y; prevX = x; prevY = y; result += Math.sqrt((dx * dx) + (dy * dy)); } return result; } /** * Calculate the points for a bezier curve and then draws it. * * Ignored from docs since it is not directly exposed. * * @ignore * @param {number} cpX - Control point x * @param {number} cpY - Control point y * @param {number} cpX2 - Second Control point x * @param {number} cpY2 - Second Control point y * @param {number} toX - Destination point x * @param {number} toY - Destination point y * @param {number[]} points - Path array to push points into */ static curveTo(cpX, cpY, cpX2, cpY2, toX, toY, points) { const fromX = points[points.length - 2]; const fromY = points[points.length - 1]; points.length -= 2; const n = GRAPHICS_CURVES._segmentsCount( BezierUtils.curveLength(fromX, fromY, cpX, cpY, cpX2, cpY2, toX, toY) ); let dt = 0; let dt2 = 0; let dt3 = 0; let t2 = 0; let t3 = 0; points.push(fromX, fromY); for (let i = 1, j = 0; i <= n; ++i) { j = i / n; dt = (1 - j); dt2 = dt * dt; dt3 = dt2 * dt; t2 = j * j; t3 = t2 * j; points.push( (dt3 * fromX) + (3 * dt2 * j * cpX) + (3 * dt * t2 * cpX2) + (t3 * toX), (dt3 * fromY) + (3 * dt2 * j * cpY) + (3 * dt * t2 * cpY2) + (t3 * toY) ); } } }