import { GRAPHICS_CURVES } from '../const'; import { PI_2 } from '@pixi/math'; /** * Utilities for arc curves * @class * @private */ export default class ArcUtils { /** * The arcTo() method creates an arc/curve between two tangents on the canvas. * * "borrowed" from https://code.google.com/p/fxcanvas/ - thanks google! * * @param {number} x1 - The x-coordinate of the beginning of the arc * @param {number} y1 - The y-coordinate of the beginning of the arc * @param {number} x2 - The x-coordinate of the end of the arc * @param {number} y2 - The y-coordinate of the end of the arc * @param {number} radius - The radius of the arc * @return {object} If the arc length is valid, return center of circle, radius and other info otherwise `null`. */ static curveTo(x1, y1, x2, y2, radius, points) { const fromX = points[points.length - 2]; const fromY = points[points.length - 1]; const a1 = fromY - y1; const b1 = fromX - x1; const a2 = y2 - y1; const b2 = x2 - x1; const mm = Math.abs((a1 * b2) - (b1 * a2)); if (mm < 1.0e-8 || radius === 0) { if (points[points.length - 2] !== x1 || points[points.length - 1] !== y1) { points.push(x1, y1); } return null; } const dd = (a1 * a1) + (b1 * b1); const cc = (a2 * a2) + (b2 * b2); const tt = (a1 * a2) + (b1 * b2); const k1 = radius * Math.sqrt(dd) / mm; const k2 = radius * Math.sqrt(cc) / mm; const j1 = k1 * tt / dd; const j2 = k2 * tt / cc; const cx = (k1 * b2) + (k2 * b1); const cy = (k1 * a2) + (k2 * a1); const px = b1 * (k2 + j1); const py = a1 * (k2 + j1); const qx = b2 * (k1 + j2); const qy = a2 * (k1 + j2); const startAngle = Math.atan2(py - cy, px - cx); const endAngle = Math.atan2(qy - cy, qx - cx); return { cx: (cx + x1), cy: (cy + y1), radius, startAngle, endAngle, anticlockwise: (b1 * a2 > b2 * a1), }; } /** * The arc method creates an arc/curve (used to create circles, or parts of circles). * * @param {number} startX - Start x location of arc * @param {number} startY - Start y location of arc * @param {number} cx - The x-coordinate of the center of the circle * @param {number} cy - The y-coordinate of the center of the circle * @param {number} radius - The radius of the circle * @param {number} startAngle - The starting angle, in radians (0 is at the 3 o'clock position * of the arc's circle) * @param {number} endAngle - The ending angle, in radians * @param {boolean} anticlockwise - Specifies whether the drawing should be * counter-clockwise or clockwise. False is default, and indicates clockwise, while true * indicates counter-clockwise. * @param {number} n - Number of segments * @param {number[]} points - Collection of points to add to */ static arc(startX, startY, cx, cy, radius, startAngle, endAngle, anticlockwise, points) { const sweep = endAngle - startAngle; const n = GRAPHICS_CURVES._segmentsCount( Math.abs(sweep) * radius, Math.ceil(Math.abs(sweep) / PI_2) * 40 ); const theta = (sweep) / (n * 2); const theta2 = theta * 2; const cTheta = Math.cos(theta); const sTheta = Math.sin(theta); const segMinus = n - 1; const remainder = (segMinus % 1) / segMinus; for (let i = 0; i <= segMinus; ++i) { const real = i + (remainder * i); const angle = ((theta) + startAngle + (theta2 * real)); const c = Math.cos(angle); const s = -Math.sin(angle); points.push( (((cTheta * c) + (sTheta * s)) * radius) + cx, (((cTheta * -s) + (sTheta * c)) * radius) + cy ); } } }