1
0
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:
smoogipoo 2018-10-26 14:18:48 +09:00
parent 4fa511043e
commit a9f1484e8b
10 changed files with 138 additions and 118 deletions

View File

@ -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;

View File

@ -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...

View File

@ -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]);
}
}
}

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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++)
{

View File

@ -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];

View File

@ -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);
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}