UNPKG

osu-utils

Version:

Basics Utils for osu projects

144 lines (119 loc) 4.26 kB
'use strict'; /** * Taken from osu_parser * https://github.com/nojhamster/osu-parser */ var curves = require('./curves'); var Bezier = curves.Bezier; /** * Get the endpoint of a slider * @param {String} sliderType slider curve type * @param {Float} sliderLength slider length * @param {Array} points list of slider points * @return {Object} endPoint the coordinates of the slider edge */ exports.getEndPoint = function (sliderType, sliderLength, points) { if (!sliderType || !sliderLength || !points) return; switch (sliderType) { case 'linear': return pointOnLine(points[0], points[1], sliderLength); case 'catmull': // not supported, anyway it's only used in old beatmaps return undefined; case 'bezier': if (!points || points.length < 2) { return undefined; } if (points.length == 2) { return pointOnLine(points[0], points[1], sliderLength); } var pts = points.slice(); var bezier; var previous; var point; for (var i = 0, l = pts.length; i < l; i++) { point = pts[i]; if (!previous) { previous = point; continue; } if (point[0] == previous[0] && point[1] == previous[1]) { bezier = new Bezier(pts.splice(0, i)); sliderLength -= bezier.pxlength; i = 0; l = pts.length; } previous = point; } bezier = new Bezier(pts); return bezier.pointAtDistance(sliderLength); case 'pass-through': if (!points || points.length < 2) { return undefined; } if (points.length == 2) { return pointOnLine(points[0], points[1], sliderLength); } if (points.length > 3) { return exports.getEndPoint('bezier', sliderLength, points); } var p1 = points[0]; var p2 = points[1]; var p3 = points[2]; var circumCicle = getCircumCircle(p1, p2, p3); var radians = sliderLength / circumCicle.radius; if (isLeft(p1, p2, p3)) radians *= -1; return rotate(circumCicle.cx, circumCicle.cy, p1[0], p1[1], radians); } }; function pointOnLine(p1, p2, length) { var fullLength = Math.sqrt(Math.pow(p2[0] - p1[0], 2) + Math.pow(p2[1] - p1[1], 2)); var n = fullLength - length; var x = (n * p1[0] + length * p2[0]) / fullLength; var y = (n * p1[1] + length * p2[1]) / fullLength; return [x, y]; } /** * Get coordinates of a point in a circle, given the center, a startpoint and a distance in radians * @param {Float} cx center x * @param {Float} cy center y * @param {Float} x startpoint x * @param {Float} y startpoint y * @param {Float} radians distance from the startpoint * @return {Object} the new point coordinates after rotation */ function rotate(cx, cy, x, y, radians) { var cos = Math.cos(radians); var sin = Math.sin(radians); return [ (cos * (x - cx)) - (sin * (y - cy)) + cx, (sin * (x - cx)) + (cos * (y - cy)) + cy ]; } /** * Check if C is on left side of [AB] * @param {Object} a startpoint of the segment * @param {Object} b endpoint of the segment * @param {Object} c the point we want to locate * @return {Boolean} true if on left side */ function isLeft(a, b, c) { return ((b[0] - a[0])*(c[1] - a[1]) - (b[1] - a[1])*(c[0] - a[0])) < 0; } /** * Get circum circle of 3 points * @param {Object} p1 first point * @param {Object} p2 second point * @param {Object} p3 third point * @return {Object} circumCircle */ function getCircumCircle(p1, p2, p3) { var x1 = p1[0]; var y1 = p1[1]; var x2 = p2[0]; var y2 = p2[1]; var x3 = p3[0]; var y3 = p3[1]; //center of circle var D = 2 * (x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2)); var Ux = ((x1 * x1 + y1 * y1) * (y2 - y3) + (x2 * x2 + y2 * y2) * (y3 - y1) + (x3 * x3 + y3 * y3) * (y1 - y2)) / D; var Uy = ((x1 * x1 + y1 * y1) * (x3 - x2) + (x2 * x2 + y2 * y2) * (x1 - x3) + (x3 * x3 + y3 * y3) * (x2 - x1)) / D; var px = Ux - x1; var py = Uy - y1; var r = Math.sqrt(px * px + py * py); return { cx: Ux, cy: Uy, radius: r }; }