1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-13 16:13:34 +08:00

Refactor b-spline path conversion code to better handle linear segments

This commit is contained in:
Dean Herbert 2023-11-21 13:10:44 +09:00
parent 0a5444d091
commit e69e78ad41
No known key found for this signature in database

View File

@ -8,7 +8,6 @@ using System.Diagnostics;
using System.Linq;
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Input;
using osu.Framework.Input.Events;
@ -203,17 +202,44 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
private void updateSliderPathFromBSplineBuilder()
{
IReadOnlyList<Vector2> builderPoints = bSplineBuilder.ControlPoints;
BindableList<PathControlPoint> sliderPoints = HitObject.Path.ControlPoints;
sliderPoints.RemoveRange(1, sliderPoints.Count - 1);
if (builderPoints.Count == 0)
return;
// Add the control points from the BSpline builder while converting control points that repeat
// three or more times to a single PathControlPoint with linear type.
for (int i = 1; i < builderPoints.Count; i++)
int lastSegmentStart = 0;
PathType? lastPathType = null;
HitObject.Path.ControlPoints.Clear();
// Iterate through generated points, finding each segment and adding non-inheriting path types where appropriate.
// Importantly, the B-Spline builder returns three Vector2s at the same location when a new segment is to be started.
for (int i = 0; i < builderPoints.Count; i++)
{
bool isSharp = i < builderPoints.Count - 2 && builderPoints[i] == builderPoints[i + 1] && builderPoints[i] == builderPoints[i + 2];
sliderPoints.Add(new PathControlPoint(builderPoints[i], isSharp ? PathType.BSpline(3) : null));
if (isSharp) i += 2;
bool isLastPoint = i == builderPoints.Count - 1;
bool isNewSegment = i < builderPoints.Count - 2 && builderPoints[i] == builderPoints[i + 1] && builderPoints[i] == builderPoints[i + 2];
if (isNewSegment || isLastPoint)
{
int pointsInSegment = i - lastSegmentStart;
// Where possible, we can use the simpler LINEAR path type.
PathType? pathType = pointsInSegment == 1 ? PathType.LINEAR : PathType.BSpline(3);
// Linear segments can be combined, as two adjacent linear sections are computationally the same as one with the points combined.
if (lastPathType == pathType && lastPathType == PathType.LINEAR)
pathType = null;
HitObject.Path.ControlPoints.Add(new PathControlPoint(builderPoints[lastSegmentStart], pathType));
for (int j = lastSegmentStart + 1; j < i; j++)
HitObject.Path.ControlPoints.Add(new PathControlPoint(builderPoints[j]));
if (isLastPoint)
HitObject.Path.ControlPoints.Add(new PathControlPoint(builderPoints[i]));
// Skip the redundant duplicated points (see isNewSegment above) which have been coalesced into a path type.
lastSegmentStart = (i += 2);
if (pathType != null) lastPathType = pathType;
}
}
}