mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 05:32:54 +08:00
Fix some post-rebase issues
This commit is contained in:
parent
4fa511043e
commit
a9f1484e8b
@ -4,7 +4,7 @@
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Edit.Masks.Slider;
|
||||
using osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Tests.Visual;
|
||||
|
@ -10,7 +10,7 @@ using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Edit.Masks.Slider.Components
|
||||
namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Todo: Move this out of SliderPlacementMask...
|
@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
@ -12,11 +13,11 @@ using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Osu.Edit.Masks.Slider.Components;
|
||||
using osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks.Components;
|
||||
using OpenTK;
|
||||
using OpenTK.Input;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Edit.Masks.Slider
|
||||
namespace osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks
|
||||
{
|
||||
public class SliderPlacementMask : PlacementMask
|
||||
{
|
||||
@ -41,7 +42,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.Slider
|
||||
{
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new BodyPiece(HitObject),
|
||||
new SliderBodyPiece(HitObject),
|
||||
new SliderCirclePiece(HitObject, SliderPosition.Start),
|
||||
new SliderCirclePiece(HitObject, SliderPosition.End),
|
||||
controlPointContainer = new Container<SliderControlPoint> { RelativeSizeAxes = Axes.Both }
|
||||
@ -113,8 +114,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.Slider
|
||||
|
||||
private void endCurve()
|
||||
{
|
||||
HitObject.ControlPoints = segments.SelectMany(s => s.ControlPoints).Concat(cursor.Yield()).ToList();
|
||||
HitObject.CurveType = HitObject.ControlPoints.Count > 2 ? CurveType.Bezier : CurveType.Linear;
|
||||
HitObject.ControlPoints = segments.SelectMany(s => s.ControlPoints).Concat(cursor.Yield()).ToArray();
|
||||
HitObject.CurveType = HitObject.ControlPoints.Length > 2 ? CurveType.Bezier : CurveType.Linear;
|
||||
HitObject.Distance = segments.Sum(s => s.Distance);
|
||||
|
||||
EndPlacement();
|
||||
@ -127,8 +128,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.Slider
|
||||
for (int i = 0; i < segments.Count; i++)
|
||||
segments[i].Calculate(i == segments.Count - 1 ? (Vector2?)cursor : null);
|
||||
|
||||
HitObject.ControlPoints = segments.SelectMany(s => s.ControlPoints).Concat(cursor.Yield()).ToList();
|
||||
HitObject.CurveType = HitObject.ControlPoints.Count > 2 ? CurveType.Bezier : CurveType.Linear;
|
||||
HitObject.ControlPoints = segments.SelectMany(s => s.ControlPoints).Concat(cursor.Yield()).ToArray();
|
||||
HitObject.CurveType = HitObject.ControlPoints.Length > 2 ? CurveType.Bezier : CurveType.Linear;
|
||||
HitObject.Distance = segments.Sum(s => s.Distance);
|
||||
}
|
||||
|
||||
@ -154,32 +155,31 @@ namespace osu.Game.Rulesets.Osu.Edit.Masks.Slider
|
||||
ControlPoints.Add(offset);
|
||||
}
|
||||
|
||||
public List<Vector2> Calculate(Vector2? cursor = null)
|
||||
public void Calculate(Vector2? cursor = null)
|
||||
{
|
||||
var allControlPoints = ControlPoints.ToList();
|
||||
Span<Vector2> allControlPoints = stackalloc Vector2[ControlPoints.Count + (cursor.HasValue ? 1 : 0)];
|
||||
|
||||
for (int i = 0; i < ControlPoints.Count; i++)
|
||||
allControlPoints[i] = ControlPoints[i];
|
||||
if (cursor.HasValue)
|
||||
allControlPoints.Add(cursor.Value);
|
||||
allControlPoints[allControlPoints.Length - 1] = cursor.Value;
|
||||
|
||||
IApproximator approximator;
|
||||
List<Vector2> result;
|
||||
|
||||
switch (allControlPoints.Count)
|
||||
switch (allControlPoints.Length)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
approximator = new LinearApproximator();
|
||||
result = new LinearApproximator(allControlPoints).CreateLinear();
|
||||
break;
|
||||
default:
|
||||
approximator = new BezierApproximator();
|
||||
result = new BezierApproximator(allControlPoints).CreateBezier();
|
||||
break;
|
||||
}
|
||||
|
||||
Distance = 0;
|
||||
|
||||
var points = approximator.Approximate(allControlPoints);
|
||||
for (int i = 0; i < points.Count - 1; i++)
|
||||
Distance += Vector2.Distance(points[i], points[i + 1]);
|
||||
|
||||
return points;
|
||||
for (int i = 0; i < result.Count - 1; i++)
|
||||
Distance += Vector2.Distance(result[i], result[i + 1]);
|
||||
}
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Edit.Tools;
|
||||
using osu.Game.Rulesets.Osu.Edit.Masks.Slider;
|
||||
using osu.Game.Rulesets.Osu.Edit.Masks.SliderMasks;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Edit
|
||||
|
@ -1,77 +1,29 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects
|
||||
{
|
||||
public class BezierApproximator : IApproximator
|
||||
public readonly ref struct BezierApproximator
|
||||
{
|
||||
private readonly int count;
|
||||
private readonly ReadOnlySpan<Vector2> controlPoints;
|
||||
private readonly Vector2[] subdivisionBuffer1;
|
||||
private readonly Vector2[] subdivisionBuffer2;
|
||||
|
||||
private const float tolerance = 0.25f;
|
||||
private const float tolerance_sq = tolerance * tolerance;
|
||||
|
||||
private int count;
|
||||
private Vector2[] subdivisionBuffer1;
|
||||
private Vector2[] subdivisionBuffer2;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a piecewise-linear approximation of a bezier curve, by adaptively repeatedly subdividing
|
||||
/// the control points until their approximation error vanishes below a given threshold.
|
||||
/// </summary>
|
||||
/// <returns>A list of vectors representing the piecewise-linear approximation.</returns>
|
||||
public List<Vector2> Approximate(List<Vector2> controlPoints)
|
||||
public BezierApproximator(ReadOnlySpan<Vector2> controlPoints)
|
||||
{
|
||||
count = controlPoints.Count;
|
||||
this.controlPoints = controlPoints;
|
||||
count = controlPoints.Length;
|
||||
|
||||
subdivisionBuffer1 = new Vector2[count];
|
||||
subdivisionBuffer2 = new Vector2[count * 2 - 1];
|
||||
|
||||
List<Vector2> output = new List<Vector2>();
|
||||
|
||||
if (count == 0)
|
||||
return output;
|
||||
|
||||
Stack<Vector2[]> toFlatten = new Stack<Vector2[]>();
|
||||
Stack<Vector2[]> freeBuffers = new Stack<Vector2[]>();
|
||||
|
||||
// "toFlatten" contains all the curves which are not yet approximated well enough.
|
||||
// We use a stack to emulate recursion without the risk of running into a stack overflow.
|
||||
// (More specifically, we iteratively and adaptively refine our curve with a
|
||||
// <a href="https://en.wikipedia.org/wiki/Depth-first_search">Depth-first search</a>
|
||||
// over the tree resulting from the subdivisions we make.)
|
||||
toFlatten.Push(controlPoints.ToArray());
|
||||
|
||||
Vector2[] leftChild = subdivisionBuffer2;
|
||||
|
||||
while (toFlatten.Count > 0)
|
||||
{
|
||||
Vector2[] parent = toFlatten.Pop();
|
||||
if (isFlatEnough(parent))
|
||||
{
|
||||
// If the control points we currently operate on are sufficiently "flat", we use
|
||||
// an extension to De Casteljau's algorithm to obtain a piecewise-linear approximation
|
||||
// of the bezier curve represented by our control points, consisting of the same amount
|
||||
// of points as there are control points.
|
||||
approximate(parent, output);
|
||||
freeBuffers.Push(parent);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If we do not yet have a sufficiently "flat" (in other words, detailed) approximation we keep
|
||||
// subdividing the curve we are currently operating on.
|
||||
Vector2[] rightChild = freeBuffers.Count > 0 ? freeBuffers.Pop() : new Vector2[count];
|
||||
subdivide(parent, leftChild, rightChild);
|
||||
|
||||
// We re-use the buffer of the parent for one of the children, so that we save one allocation per iteration.
|
||||
for (int i = 0; i < count; ++i)
|
||||
parent[i] = leftChild[i];
|
||||
|
||||
toFlatten.Push(rightChild);
|
||||
toFlatten.Push(parent);
|
||||
}
|
||||
|
||||
output.Add(controlPoints[count - 1]);
|
||||
return output;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -140,5 +92,60 @@ namespace osu.Game.Rulesets.Objects
|
||||
output.Add(p);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a piecewise-linear approximation of a bezier curve, by adaptively repeatedly subdividing
|
||||
/// the control points until their approximation error vanishes below a given threshold.
|
||||
/// </summary>
|
||||
/// <returns>A list of vectors representing the piecewise-linear approximation.</returns>
|
||||
public List<Vector2> CreateBezier()
|
||||
{
|
||||
List<Vector2> output = new List<Vector2>();
|
||||
|
||||
if (count == 0)
|
||||
return output;
|
||||
|
||||
Stack<Vector2[]> toFlatten = new Stack<Vector2[]>();
|
||||
Stack<Vector2[]> freeBuffers = new Stack<Vector2[]>();
|
||||
|
||||
// "toFlatten" contains all the curves which are not yet approximated well enough.
|
||||
// We use a stack to emulate recursion without the risk of running into a stack overflow.
|
||||
// (More specifically, we iteratively and adaptively refine our curve with a
|
||||
// <a href="https://en.wikipedia.org/wiki/Depth-first_search">Depth-first search</a>
|
||||
// over the tree resulting from the subdivisions we make.)
|
||||
toFlatten.Push(controlPoints.ToArray());
|
||||
|
||||
Vector2[] leftChild = subdivisionBuffer2;
|
||||
|
||||
while (toFlatten.Count > 0)
|
||||
{
|
||||
Vector2[] parent = toFlatten.Pop();
|
||||
if (isFlatEnough(parent))
|
||||
{
|
||||
// If the control points we currently operate on are sufficiently "flat", we use
|
||||
// an extension to De Casteljau's algorithm to obtain a piecewise-linear approximation
|
||||
// of the bezier curve represented by our control points, consisting of the same amount
|
||||
// of points as there are control points.
|
||||
approximate(parent, output);
|
||||
freeBuffers.Push(parent);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If we do not yet have a sufficiently "flat" (in other words, detailed) approximation we keep
|
||||
// subdividing the curve we are currently operating on.
|
||||
Vector2[] rightChild = freeBuffers.Count > 0 ? freeBuffers.Pop() : new Vector2[count];
|
||||
subdivide(parent, leftChild, rightChild);
|
||||
|
||||
// We re-use the buffer of the parent for one of the children, so that we save one allocation per iteration.
|
||||
for (int i = 0; i < count; ++i)
|
||||
parent[i] = leftChild[i];
|
||||
|
||||
toFlatten.Push(rightChild);
|
||||
toFlatten.Push(parent);
|
||||
}
|
||||
|
||||
output.Add(controlPoints[count - 1]);
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,32 +1,40 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects
|
||||
{
|
||||
public class CatmullApproximator : IApproximator
|
||||
public readonly ref struct CatmullApproximator
|
||||
{
|
||||
/// <summary>
|
||||
/// The amount of pieces to calculate for each controlpoint quadruplet.
|
||||
/// </summary>
|
||||
private const int detail = 50;
|
||||
|
||||
private readonly ReadOnlySpan<Vector2> controlPoints;
|
||||
|
||||
public CatmullApproximator(ReadOnlySpan<Vector2> controlPoints)
|
||||
{
|
||||
this.controlPoints = controlPoints;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a piecewise-linear approximation of a Catmull-Rom spline.
|
||||
/// </summary>
|
||||
/// <returns>A list of vectors representing the piecewise-linear approximation.</returns>
|
||||
public List<Vector2> Approximate(List<Vector2> controlPoints)
|
||||
public List<Vector2> CreateCatmull()
|
||||
{
|
||||
var result = new List<Vector2>();
|
||||
var result = new List<Vector2>((controlPoints.Length - 1) * detail * 2);
|
||||
|
||||
for (int i = 0; i < controlPoints.Count - 1; i++)
|
||||
for (int i = 0; i < controlPoints.Length - 1; i++)
|
||||
{
|
||||
var v1 = i > 0 ? controlPoints[i - 1] : controlPoints[i];
|
||||
var v2 = controlPoints[i];
|
||||
var v3 = i < controlPoints.Count - 1 ? controlPoints[i + 1] : v2 + v2 - v1;
|
||||
var v4 = i < controlPoints.Count - 2 ? controlPoints[i + 2] : v3 + v3 - v2;
|
||||
var v3 = i < controlPoints.Length - 1 ? controlPoints[i + 1] : v2 + v2 - v1;
|
||||
var v4 = i < controlPoints.Length - 2 ? controlPoints[i + 2] : v3 + v3 - v2;
|
||||
|
||||
for (int c = 0; c < detail; c++)
|
||||
{
|
||||
|
@ -8,19 +8,23 @@ using OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects
|
||||
{
|
||||
public class CircularArcApproximator : IApproximator
|
||||
public readonly ref struct CircularArcApproximator
|
||||
{
|
||||
private const float tolerance = 0.1f;
|
||||
|
||||
private readonly ReadOnlySpan<Vector2> controlPoints;
|
||||
|
||||
public CircularArcApproximator(ReadOnlySpan<Vector2> controlPoints)
|
||||
{
|
||||
this.controlPoints = controlPoints;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a piecewise-linear approximation of a circular arc curve.
|
||||
/// </summary>
|
||||
/// <returns>A list of vectors representing the piecewise-linear approximation.</returns>
|
||||
public List<Vector2> Approximate(List<Vector2> controlPoints)
|
||||
public List<Vector2> CreateArc()
|
||||
{
|
||||
if (controlPoints.Count != 3)
|
||||
throw new ArgumentException("Must have 3 control points to perform circular arc approximation.", nameof(controlPoints));
|
||||
|
||||
Vector2 a = controlPoints[0];
|
||||
Vector2 b = controlPoints[1];
|
||||
Vector2 c = controlPoints[2];
|
||||
|
@ -1,13 +0,0 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Collections.Generic;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects
|
||||
{
|
||||
public interface IApproximator
|
||||
{
|
||||
List<Vector2> Approximate(List<Vector2> controlPoints);
|
||||
}
|
||||
}
|
@ -1,13 +1,29 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Objects
|
||||
{
|
||||
public class LinearApproximator : IApproximator
|
||||
public readonly ref struct LinearApproximator
|
||||
{
|
||||
public List<Vector2> Approximate(List<Vector2> controlpoints) => controlpoints;
|
||||
private readonly ReadOnlySpan<Vector2> controlPoints;
|
||||
|
||||
public LinearApproximator(ReadOnlySpan<Vector2> controlPoints)
|
||||
{
|
||||
this.controlPoints = controlPoints;
|
||||
}
|
||||
|
||||
public List<Vector2> CreateLinear()
|
||||
{
|
||||
var result = new List<Vector2>(controlPoints.Length);
|
||||
|
||||
foreach (var c in controlPoints)
|
||||
result.Add(c);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,10 +14,12 @@ namespace osu.Game.Rulesets.Objects
|
||||
{
|
||||
public double Distance;
|
||||
|
||||
public Vector2[] ControlPoints;
|
||||
public Vector2[] ControlPoints = Array.Empty<Vector2>();
|
||||
|
||||
public CurveType CurveType = CurveType.PerfectCurve;
|
||||
|
||||
public Vector2 Offset;
|
||||
|
||||
private readonly List<Vector2> calculatedPath = new List<Vector2>();
|
||||
private readonly List<double> cumulativeLength = new List<double>();
|
||||
|
||||
@ -26,11 +28,7 @@ namespace osu.Game.Rulesets.Objects
|
||||
switch (CurveType)
|
||||
{
|
||||
case CurveType.Linear:
|
||||
var result = new List<Vector2>(subControlPoints.Length);
|
||||
foreach (var c in subControlPoints)
|
||||
result.Add(c);
|
||||
|
||||
return result;
|
||||
return new LinearApproximator(subControlPoints).CreateLinear();
|
||||
case CurveType.PerfectCurve:
|
||||
//we can only use CircularArc iff we have exactly three control points and no dissection.
|
||||
if (ControlPoints.Length != 3 || subControlPoints.Length != 3)
|
||||
@ -185,12 +183,12 @@ namespace osu.Game.Rulesets.Objects
|
||||
int i = 0;
|
||||
for (; i < calculatedPath.Count && cumulativeLength[i] < d0; ++i) { }
|
||||
|
||||
path.Add(interpolateVertices(i, d0));
|
||||
path.Add(interpolateVertices(i, d0) + Offset);
|
||||
|
||||
for (; i < calculatedPath.Count && cumulativeLength[i] <= d1; ++i)
|
||||
path.Add(calculatedPath[i]);
|
||||
path.Add(calculatedPath[i] + Offset);
|
||||
|
||||
path.Add(interpolateVertices(i, d1));
|
||||
path.Add(interpolateVertices(i, d1) + Offset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -205,7 +203,7 @@ namespace osu.Game.Rulesets.Objects
|
||||
Calculate();
|
||||
|
||||
double d = progressToDistance(progress);
|
||||
return interpolateVertices(indexOfDistance(d), d);
|
||||
return interpolateVertices(indexOfDistance(d), d) + Offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user