Move snap/divisor helper methods to inside `ControlPointInfo`

This commit is contained in:
Dean Herbert 2021-04-28 16:47:30 +09:00
parent b8b6d0e861
commit 48d6c9ac4b
7 changed files with 49 additions and 71 deletions

View File

@ -85,7 +85,7 @@ private void assertClosestDivisors(IReadOnlyList<double> divisors, IReadOnlyList
};
for (int i = 0; i < divisors.Count; ++i)
Assert.AreEqual(closestDivisors[i], beatmap.ClosestBeatDivisor(beatmap.HitObjects[i].StartTime), $"at index {i}");
Assert.AreEqual(closestDivisors[i], beatmap.ControlPointInfo.ClosestBeatDivisor(beatmap.HitObjects[i].StartTime), $"at index {i}");
}
}
}

View File

@ -9,7 +9,6 @@
using osu.Game.Beatmaps.ControlPoints;
using Newtonsoft.Json;
using osu.Game.IO.Serialization.Converters;
using osu.Game.Screens.Edit;
namespace osu.Game.Beatmaps
{
@ -75,31 +74,6 @@ public double GetMostCommonBeatLength()
return mostCommon.beatLength;
}
public int ClosestSnapTime(double time, int beatDivisor, double? referenceTime = null)
{
var timingPoint = ControlPointInfo.TimingPointAt(referenceTime ?? time);
var beatLength = timingPoint.BeatLength / beatDivisor;
var beatLengths = (int)Math.Round((time - timingPoint.Time) / beatLength, MidpointRounding.AwayFromZero);
// Casting to int matches stable.
return (int)(timingPoint.Time + beatLengths * beatLength);
}
public int ClosestSnapTime(double time, double? referenceTime = null)
{
return ClosestSnapTime(time, ClosestBeatDivisor(time, referenceTime), referenceTime);
}
public int ClosestBeatDivisor(double time, double? referenceTime = null)
{
double getUnsnap(int divisor) => Math.Abs(time - ClosestSnapTime(time, divisor, referenceTime));
int[] divisors = BindableBeatDivisor.VALID_DIVISORS;
double smallestUnsnap = divisors.Min(getUnsnap);
return divisors.FirstOrDefault(divisor => getUnsnap(divisor) == smallestUnsnap);
}
IBeatmap IBeatmap.Clone() => Clone();
public Beatmap<T> Clone() => (Beatmap<T>)MemberwiseClone();

View File

@ -7,6 +7,7 @@
using Newtonsoft.Json;
using osu.Framework.Bindables;
using osu.Framework.Lists;
using osu.Game.Screens.Edit;
namespace osu.Game.Beatmaps.ControlPoints
{
@ -160,6 +161,47 @@ public void RemoveGroup(ControlPointGroup group)
groups.Remove(group);
}
/// <summary>
/// Returns the time on the given beat divisor closest to the given time.
/// </summary>
/// <param name="time">The time to find the closest snapped time to.</param>
/// <param name="beatDivisor">The beat divisor to snap to.</param>
/// <param name="referenceTime">An optional reference point to use for timing point lookup.</param>
public int ClosestSnapTime(double time, int beatDivisor, double? referenceTime = null)
{
var timingPoint = TimingPointAt(referenceTime ?? time);
var beatLength = timingPoint.BeatLength / beatDivisor;
var beatLengths = (int)Math.Round((time - timingPoint.Time) / beatLength, MidpointRounding.AwayFromZero);
// Casting to int matches stable.
return (int)(timingPoint.Time + beatLengths * beatLength);
}
/// <summary>
/// Returns the time on any valid beat divisor closest to the given time.
/// </summary>
/// <param name="time">The time to find the closest snapped time to.</param>
/// <param name="referenceTime">An optional reference point to use for timing point lookup.</param>
public int ClosestSnapTime(double time, double? referenceTime = null)
{
return ClosestSnapTime(time, ClosestBeatDivisor(time, referenceTime), referenceTime);
}
/// <summary>
/// Returns the beat snap divisor closest to the given time. If two are equally close, the smallest is returned.
/// </summary>
/// <param name="time">The time to find the closest beat snap divisor to.</param>
/// <param name="referenceTime">An optional reference point to use for timing point lookup.</param>
public int ClosestBeatDivisor(double time, double? referenceTime = null)
{
double getUnsnap(int divisor) => Math.Abs(time - ClosestSnapTime(time, divisor, referenceTime));
int[] divisors = BindableBeatDivisor.VALID_DIVISORS;
double smallestUnsnap = divisors.Min(getUnsnap);
return divisors.FirstOrDefault(divisor => getUnsnap(divisor) == smallestUnsnap);
}
/// <summary>
/// Binary searches one of the control point lists to find the active control point at <paramref name="time"/>.
/// Includes logic for returning a specific point when no matching point is found.

View File

@ -51,28 +51,6 @@ public interface IBeatmap : IJsonSerializable
/// </summary>
double GetMostCommonBeatLength();
/// <summary>
/// Returns the time on the given beat divisor closest to the given time.
/// </summary>
/// <param name="time">The time to find the closest snapped time to.</param>
/// <param name="beatDivisor">The beat divisor to snap to.</param>
/// <param name="referenceTime">An optional reference point to use for timing point lookup.</param>
int ClosestSnapTime(double time, int beatDivisor, double? referenceTime = null);
/// <summary>
/// Returns the time on any valid beat divisor closest to the given time.
/// </summary>
/// <param name="time">The time to find the closest snapped time to.</param>
/// <param name="referenceTime">An optional reference point to use for timing point lookup.</param>
int ClosestSnapTime(double time, double? referenceTime = null);
/// <summary>
/// Returns the beat snap divisor closest to the given time. If two are equally close, the smallest is returned.
/// </summary>
/// <param name="time">The time to find the closest beat snap divisor to.</param>
/// <param name="referenceTime">An optional reference point to use for timing point lookup.</param>
int ClosestBeatDivisor(double time, double? referenceTime = null);
/// <summary>
/// Creates a shallow-clone of this beatmap and returns it.
/// </summary>

View File

@ -24,9 +24,11 @@ public class CheckUnsnappedObjects : ICheck
public IEnumerable<Issue> Run(IBeatmap playableBeatmap, IWorkingBeatmap workingBeatmap)
{
var controlPointInfo = playableBeatmap.ControlPointInfo;
foreach (var hitobject in playableBeatmap.HitObjects)
{
double startUnsnap = hitobject.StartTime - playableBeatmap.ClosestSnapTime(hitobject.StartTime);
double startUnsnap = hitobject.StartTime - controlPointInfo.ClosestSnapTime(hitobject.StartTime);
string startPostfix = hitobject is IHasDuration ? "start" : "";
foreach (var issue in getUnsnapIssues(hitobject, startUnsnap, hitobject.StartTime, startPostfix))
yield return issue;
@ -37,7 +39,7 @@ public IEnumerable<Issue> Run(IBeatmap playableBeatmap, IWorkingBeatmap workingB
{
double spanDuration = hasRepeats.Duration / (hasRepeats.RepeatCount + 1);
double repeatTime = hitobject.StartTime + spanDuration * (repeatIndex + 1);
double repeatUnsnap = repeatTime - playableBeatmap.ClosestSnapTime(repeatTime);
double repeatUnsnap = repeatTime - controlPointInfo.ClosestSnapTime(repeatTime);
foreach (var issue in getUnsnapIssues(hitobject, repeatUnsnap, repeatTime, "repeat"))
yield return issue;
}
@ -45,7 +47,7 @@ public IEnumerable<Issue> Run(IBeatmap playableBeatmap, IWorkingBeatmap workingB
if (hitobject is IHasDuration hasDuration)
{
double endUnsnap = hasDuration.EndTime - playableBeatmap.ClosestSnapTime(hasDuration.EndTime);
double endUnsnap = hasDuration.EndTime - controlPointInfo.ClosestSnapTime(hasDuration.EndTime);
foreach (var issue in getUnsnapIssues(hitobject, endUnsnap, hasDuration.EndTime, "end"))
yield return issue;
}

View File

@ -301,16 +301,7 @@ private int findInsertionIndex(IReadOnlyList<HitObject> list, double startTime)
return list.Count - 1;
}
public int ClosestSnapTime(double time, int beatDivisor, double? referenceTime = null)
{
return PlayableBeatmap.ClosestSnapTime(time, beatDivisor, referenceTime);
}
public int ClosestSnapTime(double time, double? referenceTime = null) => PlayableBeatmap.ClosestSnapTime(time, referenceTime);
public int ClosestBeatDivisor(double time, double? referenceTime = null) => PlayableBeatmap.ClosestBeatDivisor(time, referenceTime);
public double SnapTime(double time, double? referenceTime) => ClosestSnapTime(time, BeatDivisor, referenceTime);
public double SnapTime(double time, double? referenceTime) => ControlPointInfo.ClosestSnapTime(time, BeatDivisor, referenceTime);
public double GetBeatLengthAtTime(double referenceTime) => ControlPointInfo.TimingPointAt(referenceTime).BeatLength / BeatDivisor;

View File

@ -45,15 +45,6 @@ public ControlPointInfo ControlPointInfo
public double GetMostCommonBeatLength() => PlayableBeatmap.GetMostCommonBeatLength();
public int ClosestSnapTime(double time, int beatDivisor, double? referenceTime = null)
{
return PlayableBeatmap.ClosestSnapTime(time, beatDivisor, referenceTime);
}
public int ClosestSnapTime(double time, double? referenceTime = null) => PlayableBeatmap.ClosestSnapTime(time, referenceTime);
public int ClosestBeatDivisor(double time, double? referenceTime = null) => PlayableBeatmap.ClosestBeatDivisor(time, referenceTime);
public IBeatmap Clone() => PlayableBeatmap.Clone();
private readonly Bindable<JudgementResult> lastJudgementResult = new Bindable<JudgementResult>();