From a06d806fb911ddb1531eda8f5415c0e9a86dc7ff Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 3 Mar 2022 15:43:01 +0900 Subject: [PATCH] Fix hit distribution graph midpoint rounding not looking great around zero Not sure this will be accepted and it's likely only ever going to show in tests, but seems to be a better approach to midpoint rounding for this case? --- .../TestSceneHitEventTimingDistributionGraph.cs | 6 ++++++ .../HitEventTimingDistributionGraph.cs | 16 ++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs b/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs index 221001e40b..f31aec8975 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneHitEventTimingDistributionGraph.cs @@ -23,6 +23,12 @@ namespace osu.Game.Tests.Visual.Ranking createTest(CreateDistributedHitEvents()); } + [Test] + public void TestManyDistributedEventsOffset() + { + createTest(CreateDistributedHitEvents(-3.5)); + } + [Test] public void TestAroundCentre() { diff --git a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs index 93885b6e02..3a4641cba9 100644 --- a/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs +++ b/osu.Game/Screens/Ranking/Statistics/HitEventTimingDistributionGraph.cs @@ -64,10 +64,22 @@ namespace osu.Game.Screens.Ranking.Statistics // Prevent div-by-0 by enforcing a minimum bin size binSize = Math.Max(1, binSize); + bool roundUp = true; + foreach (var e in hitEvents) { - int binOffset = (int)Math.Round(e.TimeOffset / binSize, MidpointRounding.AwayFromZero); - bins[timing_distribution_centre_bin_index + binOffset]++; + double binOffset = e.TimeOffset / binSize; + + // .NET's round midpoint handling doesn't provide a behaviour that works amazingly for display + // purposes here. We want midpoint rounding to roughly distribute evenly to each adjacent bucket + // so the easiest way is to cycle between downwards and upwards rounding as we process events. + if (Math.Abs(binOffset - (int)binOffset) == 0.5) + { + binOffset += Math.Sign(binOffset) * (roundUp ? 1 : 0); + roundUp = !roundUp; + } + + bins[timing_distribution_centre_bin_index + (int)binOffset]++; } int maxCount = bins.Max();