Avoid using SSDQ for validity computation

This commit is contained in:
Dean Herbert 2021-09-06 14:09:40 +09:00
parent f76f12d361
commit 458cde832d
2 changed files with 30 additions and 28 deletions

View File

@ -1,11 +1,9 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Handlers.Tablet; using osu.Framework.Input.Handlers.Tablet;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Framework.Utils; using osu.Framework.Utils;
@ -93,17 +91,9 @@ namespace osu.Game.Tests.Visual.Settings
ensureValid(); ensureValid();
} }
private void ensureValid() private void ensureValid() => AddAssert("area valid", () => settings.AreaSelection.IsWithinBounds);
{
AddUntilStep("wait for transforms", () => settings.AreaSelection.ChildrenOfType<Container>().All(c => !c.Transforms.Any()));
AddAssert("area valid", () => settings.AreaSelection.IsWithinBounds);
}
private void ensureInvalid() private void ensureInvalid() => AddAssert("area invalid", () => !settings.AreaSelection.IsWithinBounds);
{
AddUntilStep("wait for transforms", () => settings.AreaSelection.ChildrenOfType<Container>().All(c => !c.Transforms.Any()));
AddAssert("area invalid", () => !settings.AreaSelection.IsWithinBounds);
}
public class TestTabletHandler : ITabletHandler public class TestTabletHandler : ITabletHandler
{ {

View File

@ -114,29 +114,30 @@ namespace osu.Game.Overlays.Settings.Sections.Input
areaOffset.BindTo(handler.AreaOffset); areaOffset.BindTo(handler.AreaOffset);
areaOffset.BindValueChanged(val => areaOffset.BindValueChanged(val =>
{ {
usableAreaContainer.MoveTo(val.NewValue, 100, Easing.OutQuint) usableAreaContainer.MoveTo(val.NewValue, 100, Easing.OutQuint);
.OnComplete(_ => checkBounds()); // required as we are using SSDQ. checkBounds();
}, true); }, true);
areaSize.BindTo(handler.AreaSize); areaSize.BindTo(handler.AreaSize);
areaSize.BindValueChanged(val => areaSize.BindValueChanged(val =>
{ {
usableAreaContainer.ResizeTo(val.NewValue, 100, Easing.OutQuint) usableAreaContainer.ResizeTo(val.NewValue, 100, Easing.OutQuint);
.OnComplete(_ => checkBounds()); // required as we are using SSDQ.
int x = (int)val.NewValue.X; int x = (int)val.NewValue.X;
int y = (int)val.NewValue.Y; int y = (int)val.NewValue.Y;
int commonDivider = greatestCommonDivider(x, y); int commonDivider = greatestCommonDivider(x, y);
usableAreaText.Text = $"{(float)x / commonDivider}:{(float)y / commonDivider}"; usableAreaText.Text = $"{(float)x / commonDivider}:{(float)y / commonDivider}";
checkBounds();
}, true); }, true);
rotation.BindTo(handler.Rotation); rotation.BindTo(handler.Rotation);
rotation.BindValueChanged(val => rotation.BindValueChanged(val =>
{ {
usableAreaContainer.RotateTo(val.NewValue, 100, Easing.OutQuint) usableAreaContainer.RotateTo(val.NewValue, 100, Easing.OutQuint);
.OnComplete(_ => checkBounds()); // required as we are using SSDQ.
tabletContainer.RotateTo(-val.NewValue, 800, Easing.OutQuint); tabletContainer.RotateTo(-val.NewValue, 800, Easing.OutQuint);
checkBounds();
}, true); }, true);
tablet.BindTo(handler.Tablet); tablet.BindTo(handler.Tablet);
@ -174,22 +175,33 @@ namespace osu.Game.Overlays.Settings.Sections.Input
if (tablet.Value == null) if (tablet.Value == null)
return; return;
// All of this manual logic is just to get around floating point issues when doing a contains check on the screen quads. // allow for some degree of floating point error, as we don't care about being perfect here.
// This is best effort, as it's only used for display purposes. If we need for anything more, manual math on the raw values should be preferred. const float lenience = 0.5f;
var containerQuad = tabletContainer.ScreenSpaceDrawQuad.AABBFloat.Inflate(1);
var usableAreaQuad = Quad.FromRectangle(usableAreaContainer.ScreenSpaceDrawQuad.AABBFloat); var tabletArea = new Quad(-lenience, -lenience, tablet.Value.Size.X + lenience * 2, tablet.Value.Size.Y + lenience * 2);
var halfUsableArea = areaSize.Value / 2;
var offset = areaOffset.Value;
var usableAreaQuad = new Quad(
new Vector2(-halfUsableArea.X, -halfUsableArea.Y),
new Vector2(halfUsableArea.X, -halfUsableArea.Y),
new Vector2(-halfUsableArea.X, halfUsableArea.Y),
new Vector2(halfUsableArea.X, halfUsableArea.Y)
);
var matrix = Matrix3.Identity; var matrix = Matrix3.Identity;
MatrixExtensions.TranslateFromLeft(ref matrix, usableAreaQuad.Centre);
MatrixExtensions.TranslateFromLeft(ref matrix, offset);
MatrixExtensions.RotateFromLeft(ref matrix, MathUtils.DegreesToRadians(rotation.Value)); MatrixExtensions.RotateFromLeft(ref matrix, MathUtils.DegreesToRadians(rotation.Value));
MatrixExtensions.TranslateFromLeft(ref matrix, -usableAreaQuad.Centre);
usableAreaQuad *= matrix; usableAreaQuad *= matrix;
IsWithinBounds = IsWithinBounds =
containerQuad.Contains(usableAreaQuad.TopLeft) && tabletArea.Contains(usableAreaQuad.TopLeft) &&
containerQuad.Contains(usableAreaQuad.TopRight) && tabletArea.Contains(usableAreaQuad.TopRight) &&
containerQuad.Contains(usableAreaQuad.BottomLeft) && tabletArea.Contains(usableAreaQuad.BottomLeft) &&
containerQuad.Contains(usableAreaQuad.BottomRight); tabletArea.Contains(usableAreaQuad.BottomRight);
usableFill.FadeColour(IsWithinBounds ? colour.Blue : colour.RedLight, 100); usableFill.FadeColour(IsWithinBounds ? colour.Blue : colour.RedLight, 100);
} }