UNPKG

@osbjs/osbjs

Version:

a minimalist osu! storyboarding framework

101 lines (100 loc) 4.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CircleCurve = void 0; const Curve_1 = require("./Curve"); const Math_1 = require("../../Math"); class CircleCurve extends Curve_1.Curve { constructor(startPoint, midPoint, endPoint) { super(); this.startPoint = startPoint; this.midPoint = midPoint; this.endPoint = endPoint; this.startPosition = startPoint; this.endPosition = endPoint; this.distancePositions = []; this.length = this._initLength(); this.precision = this.length * 0.125; } getPositionAtProgress(t) { return this.getPositionAtDistance(this.precision * t); } getPositionAtDelta(delta) { return this.getPositionAtDistance(delta * this.length); } getPositionAtDistance(distance) { if (distance >= this.length) return this.endPosition; let previousDistance = 0.0; let previousPosition = this.startPosition; let nextDistance = this.length; let nextPosition = this.endPosition; let i = 0; while (i < this.distancePositions.length) { let distancePosition = this.distancePositions[i]; if (distancePosition.distance > distance) break; previousDistance = distancePosition.distance; previousPosition = distancePosition.position; i++; } if (i < this.distancePositions.length - 1) { let distancePosition = this.distancePositions[i + 1]; nextDistance = distancePosition.distance; nextPosition = distancePosition.position; } let delta = (distance - previousDistance) / (nextDistance - previousDistance); let prevNext = Math_1.Vector2.sub(nextPosition, previousPosition); return Math_1.Vector2.add(previousPosition, Math_1.Vector2.multiplyScalar(prevNext, delta)); } _initLength() { let d = 2 * (this.startPoint.x * (this.midPoint.y - this.endPoint.y) + this.midPoint.x * (this.endPoint.y - this.startPoint.y) + this.endPoint.x * (this.startPoint.y - this.midPoint.y)); if (d == 0) throw new Error('Invalid circle curve'); let startLengthSqr = this.startPoint.x * this.startPoint.x + this.startPoint.y * this.startPoint.y, midLengthSqr = this.midPoint.x * this.midPoint.x + this.midPoint.y * this.midPoint.y, endLengthSqr = this.endPoint.x * this.endPoint.x + this.endPoint.y * this.endPoint.y; let center = { x: (startLengthSqr * (this.midPoint.y - this.endPoint.y) + midLengthSqr * (this.endPoint.y - this.startPoint.y) + endLengthSqr * (this.startPoint.y - this.midPoint.y)) / d, y: (startLengthSqr * (this.endPoint.x - this.midPoint.x) + midLengthSqr * (this.startPoint.x - this.endPoint.x) + endLengthSqr * (this.midPoint.x - this.startPoint.x)) / d, }; let centerStart = { x: this.startPoint.x - center.x, y: this.startPoint.y - center.y, }; let radius = Math.sqrt(centerStart.x * centerStart.x + centerStart.y * centerStart.y); let startAngle = Math.atan2(this.startPoint.y - center.y, this.startPoint.x - center.x); let midAngle = Math.atan2(this.midPoint.y - center.y, this.midPoint.x - center.x); let endAngle = Math.atan2(this.endPoint.y - center.y, this.endPoint.x - center.x); while (midAngle < startAngle) midAngle += 2 * Math.PI; while (endAngle < startAngle) endAngle += 2 * Math.PI; if (midAngle > endAngle) endAngle -= 2 * Math.PI; let length = Math.abs((endAngle - startAngle) * radius); let precision = length * 0.125; for (let i = 1; i < precision; i++) { let progress = i / precision; let angle = endAngle * progress + startAngle * (1 - progress); let position = new Math_1.Vector2(Math.cos(angle) * radius + center.x, Math.sin(angle) * radius + center.y); this.distancePositions.push({ distance: progress * length, position }); } this.distancePositions.push({ distance: length, position: this.endPoint }); return length; } static isValid(startPoint, midPoint, endPoint) { return (startPoint.x != midPoint.x && startPoint.y != midPoint.y && midPoint.x != endPoint.x && midPoint.y != endPoint.y && 2 * (startPoint.x * (midPoint.y - endPoint.y) + midPoint.x * (endPoint.y - startPoint.y) + endPoint.x * (startPoint.y - midPoint.y)) != 0); } } exports.CircleCurve = CircleCurve;