From 859898d98f09b9f10e928eca51206be5519b3fbd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 28 Apr 2021 17:16:05 +0900 Subject: [PATCH] Refactor lookup methods to avoid linq and reduce `TimingPointAt` calls --- .../ControlPoints/ControlPointInfo.cs | 42 ++++++++++++------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index fa1c59bb08..e47d48edcf 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -170,35 +170,47 @@ namespace osu.Game.Beatmaps.ControlPoints public double GetClosestSnappedTime(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); - - return timingPoint.Time + beatLengths * beatLength; + return getClosestSnappedTime(timingPoint, time, beatDivisor); } /// - /// Returns the time on any valid beat divisor closest to the given time. + /// Returns the time on *ANY* valid beat divisor, favouring the divisor closest to the given time. /// /// The time to find the closest snapped time to. - /// An optional reference point to use for timing point lookup. - public double GetClosestSnappedTime(double time, double? referenceTime = null) - { - return GetClosestSnappedTime(time, GetClosestBeatDivisor(time, referenceTime), referenceTime); - } + public double GetClosestSnappedTime(double time) => GetClosestSnappedTime(time, GetClosestBeatDivisor(time)); /// - /// Returns the beat snap divisor closest to the given time. If two are equally close, the smallest is returned. + /// Returns the beat snap divisor closest to the given time. If two are equally close, the smallest divisor is returned. /// /// The time to find the closest beat snap divisor to. /// An optional reference point to use for timing point lookup. public int GetClosestBeatDivisor(double time, double? referenceTime = null) { - double getUnsnap(int divisor) => Math.Abs(time - GetClosestSnappedTime(time, divisor, referenceTime)); + TimingControlPoint timingPoint = TimingPointAt(referenceTime ?? time); - int[] divisors = BindableBeatDivisor.VALID_DIVISORS; - double smallestUnsnap = divisors.Min(getUnsnap); + int closestDivisor = 0; + double closestTime = double.MaxValue; - return divisors.FirstOrDefault(divisor => getUnsnap(divisor) == smallestUnsnap); + foreach (int divisor in BindableBeatDivisor.VALID_DIVISORS) + { + double distanceFromSnap = Math.Abs(time - getClosestSnappedTime(timingPoint, time, divisor)); + + if (distanceFromSnap < closestTime) + { + closestDivisor = divisor; + closestTime = distanceFromSnap; + } + } + + return closestDivisor; + } + + private static double getClosestSnappedTime(TimingControlPoint timingPoint, double time, int beatDivisor) + { + var beatLength = timingPoint.BeatLength / beatDivisor; + var beatLengths = (int)Math.Round((time - timingPoint.Time) / beatLength, MidpointRounding.AwayFromZero); + + return timingPoint.Time + beatLengths * beatLength; } ///