UNPKG

toosoon-utils

Version:
117 lines (116 loc) 4.16 kB
import { EPSILON, TWO_PI } from '../../constants'; import { Vector2 } from '../geometry'; import Curve from './Curve'; /** * Utility class for manipulating ellipses * * @exports * @class EllipseCurve * @extends Curve */ export default class EllipseCurve extends Curve { type = 'EllipseCurve'; /** * X-axis coordinate of the center of the ellipse */ cx; /** * Y-axis coordinate of the center of the ellipse */ cy; /** * X-radius of the ellipse */ rx; /** * Y-radius of the ellipse */ ry; /** * Rotation angle of the ellipse (in radians), counterclockwise from the positive X-axis */ rotation; /** * Start angle of the arc (in radians) */ startAngle; /** * End angle of the arc (in radians) */ endAngle; /** * Flag indicating the direction of the arc */ counterclockwise; /** * @param {number} cx X-axis coordinate of the center of the ellipse * @param {number} cy Y-axis coordinate of the center of the ellipse * @param {number} rx X-radius of the ellipse * @param {number} ry Y-radius of the ellipse * @param {number} [rotation=0] Rotation angle of the ellipse (in radians), counterclockwise from the positive X-axis * @param {number} [startAngle=0] Start angle of the arc (in radians) * @param {number} [endAngle=2*PI] End angle of the arc (in radians) * @param {boolean} [counterclockwise=false] Flag indicating the direction of the arc */ constructor(cx, cy, rx, ry, rotation = 0, startAngle = 0, endAngle = TWO_PI, counterclockwise = false) { super(); this.cx = cx; this.cy = cy; this.rx = rx; this.ry = ry; this.rotation = rotation; this.startAngle = startAngle; this.endAngle = endAngle; this.counterclockwise = counterclockwise; } /** * Interpolate a point on this curve * * @abstract * @param {number} t Normalized time value to interpolate * @returns {Vector2} Interpolated coordinates on this curve */ getPoint(t) { return new Vector2(...EllipseCurve.interpolate(t, this.cx, this.cy, this.rx, this.ry, this.rotation, this.startAngle, this.endAngle, this.counterclockwise)); } /** * Interpolate a point on an elliptical arc * * @param {number} t Normalized time value to interpolate * @param {number} cx X-axis coordinate of the center of the ellipse * @param {number} cy Y-axis coordinate of the center of the ellipse * @param {number} rx X-radius of the ellipse * @param {number} ry Y-radius of the ellipse * @param {number} [rotation=0] Rotation angle of the ellipse (in radians), counterclockwise from the positive X-axis * @param {number} [startAngle=0] Start angle of the arc (in radians) * @param {number} [endAngle=2*PI] End angle of the arc (in radians) * @param {boolean} [counterclockwise=false] Flag indicating the direction of the arc * @returns {Point2} Interpolated coordinates on the arc */ static interpolate(t, cx, cy, rx, ry, rotation = 0, startAngle = 0, endAngle = TWO_PI, counterclockwise = false) { let deltaAngle = endAngle - startAngle; const isEmpty = Math.abs(deltaAngle) <= EPSILON; while (deltaAngle < 0) deltaAngle += TWO_PI; while (deltaAngle > TWO_PI) deltaAngle -= TWO_PI; if (deltaAngle <= EPSILON) { deltaAngle = isEmpty ? 0 : TWO_PI; } if (counterclockwise && !isEmpty) { deltaAngle = deltaAngle === TWO_PI ? -TWO_PI : deltaAngle - TWO_PI; } const angle = startAngle + t * deltaAngle; let x = cx + rx * Math.cos(angle); let y = cy + ry * Math.sin(angle); if (Math.abs(rotation) > EPSILON) { const cos = Math.cos(rotation); const sin = Math.sin(rotation); const dx = x - cx; const dy = y - cy; x = cx + dx * cos - dy * sin; y = cy + dx * sin + dy * cos; } return [x, y]; } }