frontend/osu/js/curves/EqualDistanceMultiCurve.js
2023-05-22 17:12:06 -04:00

86 lines
3.5 KiB
JavaScript

var CURVE_POINTS_SEPERATION = 5;
define(["curves/Curve"], function (Curve) {
// Adapted from EqualDistanceMultiCurve.java from github://itdelatrisu/opsu
function EqualDistanceMultiCurve(hit) {
Curve.call(this, hit);
this.ncurve = 0;
this.startAngle = 0;
this.endAngle = 0;
}
EqualDistanceMultiCurve.prototype.init = function init(curves) {
this.ncurve = Math.floor(this.hitObject.pixelLength / CURVE_POINTS_SEPERATION) + 1;
// number of segments, which have approximately same length
this.curve = [];
var distanceAt = 0; // accumulated length of new curve
var curPoint = 0;
var curCurveIndex = 0;
var curCurve = curves[0]; // current pointer of raw curve array
var lastCurve = curCurve.curve[0];
var lastDistanceAt = 0;
var pixelLength = this.hitObject.pixelLength; // This is the expected value of length
if (pixelLength < 0) console.error("osu curve: negative slider length");
for (var i = 0; i <= this.ncurve; i++) {
var prefDistance = i * pixelLength / this.ncurve; // expected current accumulated length
while (distanceAt < prefDistance) {
lastDistanceAt = distanceAt;
lastCurve = curCurve.curve[curPoint];
curPoint++;
if (curPoint >= curCurve.ncurve) {
if (curCurveIndex < curves.length - 1) {
curCurveIndex++;
curCurve = curves[curCurveIndex];
curPoint = 0;
} else {
curPoint = curCurve.ncurve - 1;
if (lastDistanceAt === distanceAt) {
if (distanceAt < pixelLength * 0.97) {
console.warn("[curve] L/B shorter than given", distanceAt / pixelLength);
}
// out of points even though the preferred distance hasn't been reached
break;
}
}
}
distanceAt += curCurve.curveDistance[curPoint];
}
var thisCurve = curCurve.curve[curPoint];
// linear interpolate between lastCurve & thisCurve
// this can always be done when lastCurve != thisCurve, since lastCurve is always available
// lastDistanceAt <= prefDistance <= distanceAt
if (lastCurve == thisCurve) {
this.curve[i] = thisCurve;
} else {
let t = (prefDistance - lastDistanceAt) / (distanceAt - lastDistanceAt);
this.curve[i] = {
x: Curve.lerp(lastCurve.x, thisCurve.x, t),
y: Curve.lerp(lastCurve.y, thisCurve.y, t),
};
}
this.curve[i].t = i / this.ncurve;
}
}
EqualDistanceMultiCurve.prototype.pointAt = function pointAt(t) {
var indexF = t * this.ncurve;
var index = Math.floor(indexF);
if (index >= this.ncurve) { // overflowing or at exact endpoint
return this.curve[this.ncurve];
} else {
// linear interpolation between two points
let poi = this.curve[index];
let poi2 = this.curve[index + 1];
let t = indexF - index;
return {
x: Curve.lerp(poi.x, poi2.x, t),
y: Curve.lerp(poi.y, poi2.y, t)
};
}
}
return EqualDistanceMultiCurve;
});