diff --git a/osu.Game/Screens/Edit/Compose/Components/LinedPositionSnapGrid.cs b/osu.Game/Screens/Edit/Compose/Components/LinedPositionSnapGrid.cs new file mode 100644 index 0000000000..642a125265 --- /dev/null +++ b/osu.Game/Screens/Edit/Compose/Components/LinedPositionSnapGrid.cs @@ -0,0 +1,173 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Layout; +using osu.Framework.Utils; +using osuTK; + +namespace osu.Game.Screens.Edit.Compose.Components +{ + public abstract partial class LinedPositionSnapGrid : CompositeDrawable + { + private Vector2 startPosition; + + /// + /// The position of the origin of this in local coordinates. + /// + public Vector2 StartPosition + { + get => startPosition; + set + { + startPosition = value; + GridCache.Invalidate(); + } + } + + protected readonly LayoutValue GridCache = new LayoutValue(Invalidation.RequiredParentSizeToFit); + + protected LinedPositionSnapGrid(Vector2 startPosition) + { + StartPosition = startPosition; + Masking = true; + + AddLayout(GridCache); + } + + protected override void Update() + { + base.Update(); + + if (!GridCache.IsValid) + { + ClearInternal(); + + if (DrawWidth > 0 && DrawHeight > 0) + CreateContent(); + + GridCache.Validate(); + } + } + + protected abstract void CreateContent(); + + protected void GenerateGridLines(Vector2 step, Vector2 drawSize) + { + int index = 0; + var currentPosition = startPosition; + + // Make lines the same width independent of display resolution. + float lineWidth = DrawWidth / ScreenSpaceDrawQuad.Width; + float lineLength = drawSize.Length * 2; + + List generatedLines = new List(); + + while (lineDefinitelyIntersectsBox(currentPosition, step.PerpendicularLeft, drawSize) || + isMovingTowardsBox(currentPosition, step, drawSize)) + { + var gridLine = new Box + { + Colour = Colour4.White, + Alpha = 0.1f, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.None, + Width = lineWidth, + Height = lineLength, + Position = currentPosition, + Rotation = MathHelper.RadiansToDegrees(MathF.Atan2(step.Y, step.X)), + }; + + generatedLines.Add(gridLine); + + index += 1; + currentPosition = startPosition + index * step; + } + + if (generatedLines.Count == 0) + return; + + generatedLines.First().Alpha = 0.3f; + + AddRangeInternal(generatedLines); + } + + private bool isMovingTowardsBox(Vector2 currentPosition, Vector2 step, Vector2 box) + { + return (currentPosition + step).LengthSquared < currentPosition.LengthSquared || + (currentPosition + step - box).LengthSquared < (currentPosition - box).LengthSquared; + } + + private bool lineDefinitelyIntersectsBox(Vector2 lineStart, Vector2 lineDir, Vector2 box) + { + var p2 = lineStart + lineDir; + + double d1 = det(Vector2.Zero); + double d2 = det(new Vector2(box.X, 0)); + double d3 = det(new Vector2(0, box.Y)); + double d4 = det(box); + + return definitelyDifferentSign(d1, d2) || definitelyDifferentSign(d3, d4) || + definitelyDifferentSign(d1, d3) || definitelyDifferentSign(d2, d4); + + double det(Vector2 p) => (p.X - lineStart.X) * (p2.Y - lineStart.Y) - (p.Y - lineStart.Y) * (p2.X - lineStart.X); + + bool definitelyDifferentSign(double a, double b) => !Precision.AlmostEquals(a, 0) && + !Precision.AlmostEquals(b, 0) && + Math.Sign(a) != Math.Sign(b); + } + + protected void GenerateOutline(Vector2 drawSize) + { + // Make lines the same width independent of display resolution. + float lineWidth = DrawWidth / ScreenSpaceDrawQuad.Width; + + AddRangeInternal(new[] + { + new Box + { + Colour = Colour4.White, + Alpha = 0.3f, + Origin = Anchor.CentreLeft, + RelativeSizeAxes = Axes.X, + Height = lineWidth, + Y = 0, + }, + new Box + { + Colour = Colour4.White, + Alpha = 0.3f, + Origin = Anchor.CentreLeft, + RelativeSizeAxes = Axes.X, + Height = lineWidth, + Y = drawSize.Y, + }, + new Box + { + Colour = Colour4.White, + Alpha = 0.3f, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.Y, + Width = lineWidth, + X = 0, + }, + new Box + { + Colour = Colour4.White, + Alpha = 0.3f, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.Y, + Width = lineWidth, + X = drawSize.X, + }, + }); + } + + public abstract Vector2 GetSnappedPosition(Vector2 original); + } +} diff --git a/osu.Game/Screens/Edit/Compose/Components/RectangularPositionSnapGrid.cs b/osu.Game/Screens/Edit/Compose/Components/RectangularPositionSnapGrid.cs index ea9eaf41bb..14a0e3625a 100644 --- a/osu.Game/Screens/Edit/Compose/Components/RectangularPositionSnapGrid.cs +++ b/osu.Game/Screens/Edit/Compose/Components/RectangularPositionSnapGrid.cs @@ -2,35 +2,15 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Collections.Generic; -using System.Linq; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; using osu.Framework.Layout; -using osu.Framework.Utils; using osu.Game.Utils; using osuTK; namespace osu.Game.Screens.Edit.Compose.Components { - public partial class RectangularPositionSnapGrid : CompositeDrawable + public partial class RectangularPositionSnapGrid : LinedPositionSnapGrid { - private Vector2 startPosition; - - /// - /// The position of the origin of this in local coordinates. - /// - public Vector2 StartPosition - { - get => startPosition; - set - { - startPosition = value; - gridCache.Invalidate(); - } - } - private Vector2 spacing = Vector2.One; /// @@ -67,154 +47,25 @@ namespace osu.Game.Screens.Edit.Compose.Components private readonly LayoutValue gridCache = new LayoutValue(Invalidation.RequiredParentSizeToFit); public RectangularPositionSnapGrid(Vector2 startPosition) + : base(startPosition) { - StartPosition = startPosition; - Masking = true; - - AddLayout(gridCache); } - protected override void Update() - { - base.Update(); - - if (!gridCache.IsValid) - { - ClearInternal(); - - if (DrawWidth > 0 && DrawHeight > 0) - createContent(); - - gridCache.Validate(); - } - } - - private void createContent() + protected override void CreateContent() { var drawSize = DrawSize; var rot = Quaternion.FromAxisAngle(Vector3.UnitZ, MathHelper.DegreesToRadians(GridLineRotation)); - generateGridLines(Vector2.Transform(new Vector2(0, -Spacing.Y), rot), GridLineRotation + 90, drawSize); - generateGridLines(Vector2.Transform(new Vector2(0, Spacing.Y), rot), GridLineRotation + 90, drawSize); + GenerateGridLines(Vector2.Transform(new Vector2(0, -Spacing.Y), rot), drawSize); + GenerateGridLines(Vector2.Transform(new Vector2(0, Spacing.Y), rot), drawSize); - generateGridLines(Vector2.Transform(new Vector2(-Spacing.X, 0), rot), GridLineRotation, drawSize); - generateGridLines(Vector2.Transform(new Vector2(Spacing.X, 0), rot), GridLineRotation, drawSize); + GenerateGridLines(Vector2.Transform(new Vector2(-Spacing.X, 0), rot), drawSize); + GenerateGridLines(Vector2.Transform(new Vector2(Spacing.X, 0), rot), drawSize); - generateOutline(drawSize); + GenerateOutline(drawSize); } - private void generateGridLines(Vector2 step, float rotation, Vector2 drawSize) - { - int index = 0; - var currentPosition = startPosition; - - // Make lines the same width independent of display resolution. - float lineWidth = DrawWidth / ScreenSpaceDrawQuad.Width; - float lineLength = drawSize.Length * 2; - - List generatedLines = new List(); - - while (lineDefinitelyIntersectsBox(currentPosition, step.PerpendicularLeft, drawSize) || - isMovingTowardsBox(currentPosition, step, drawSize)) - { - var gridLine = new Box - { - Colour = Colour4.White, - Alpha = 0.1f, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.None, - Width = lineWidth, - Height = lineLength, - Position = currentPosition, - Rotation = rotation, - }; - - generatedLines.Add(gridLine); - - index += 1; - currentPosition = startPosition + index * step; - } - - if (generatedLines.Count == 0) - return; - - generatedLines.First().Alpha = 0.3f; - - AddRangeInternal(generatedLines); - } - - private bool isMovingTowardsBox(Vector2 currentPosition, Vector2 step, Vector2 box) - { - return (currentPosition + step).LengthSquared < currentPosition.LengthSquared || - (currentPosition + step - box).LengthSquared < (currentPosition - box).LengthSquared; - } - - private bool lineDefinitelyIntersectsBox(Vector2 lineStart, Vector2 lineDir, Vector2 box) - { - var p2 = lineStart + lineDir; - - double d1 = det(Vector2.Zero); - double d2 = det(new Vector2(box.X, 0)); - double d3 = det(new Vector2(0, box.Y)); - double d4 = det(box); - - return definitelyDifferentSign(d1, d2) || definitelyDifferentSign(d3, d4) || - definitelyDifferentSign(d1, d3) || definitelyDifferentSign(d2, d4); - - double det(Vector2 p) => (p.X - lineStart.X) * (p2.Y - lineStart.Y) - (p.Y - lineStart.Y) * (p2.X - lineStart.X); - - bool definitelyDifferentSign(double a, double b) => !Precision.AlmostEquals(a, 0) && - !Precision.AlmostEquals(b, 0) && - Math.Sign(a) != Math.Sign(b); - } - - private void generateOutline(Vector2 drawSize) - { - // Make lines the same width independent of display resolution. - float lineWidth = DrawWidth / ScreenSpaceDrawQuad.Width; - - AddRangeInternal(new[] - { - new Box - { - Colour = Colour4.White, - Alpha = 0.3f, - Origin = Anchor.CentreLeft, - RelativeSizeAxes = Axes.X, - Height = lineWidth, - Y = 0, - }, - new Box - { - Colour = Colour4.White, - Alpha = 0.3f, - Origin = Anchor.CentreLeft, - RelativeSizeAxes = Axes.X, - Height = lineWidth, - Y = drawSize.Y, - }, - new Box - { - Colour = Colour4.White, - Alpha = 0.3f, - Origin = Anchor.TopCentre, - RelativeSizeAxes = Axes.Y, - Width = lineWidth, - X = 0, - }, - new Box - { - Colour = Colour4.White, - Alpha = 0.3f, - Origin = Anchor.TopCentre, - RelativeSizeAxes = Axes.Y, - Width = lineWidth, - X = drawSize.X, - }, - }); - } - - public Vector2 GetSnappedPosition(Vector2 original) + public override Vector2 GetSnappedPosition(Vector2 original) { Vector2 relativeToStart = GeometryUtils.RotateVector(original - StartPosition, GridLineRotation); Vector2 offset = Vector2.Divide(relativeToStart, Spacing); diff --git a/osu.Game/Screens/Edit/Compose/Components/TriangularPositionSnapGrid.cs b/osu.Game/Screens/Edit/Compose/Components/TriangularPositionSnapGrid.cs index 58889bd085..4b6c5dcfe4 100644 --- a/osu.Game/Screens/Edit/Compose/Components/TriangularPositionSnapGrid.cs +++ b/osu.Game/Screens/Edit/Compose/Components/TriangularPositionSnapGrid.cs @@ -2,35 +2,13 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Collections.Generic; -using System.Linq; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Layout; -using osu.Framework.Utils; using osu.Game.Utils; using osuTK; namespace osu.Game.Screens.Edit.Compose.Components { - public partial class TriangularPositionSnapGrid : CompositeDrawable + public partial class TriangularPositionSnapGrid : LinedPositionSnapGrid { - private Vector2 startPosition; - - /// - /// The position of the origin of this in local coordinates. - /// - public Vector2 StartPosition - { - get => startPosition; - set - { - startPosition = value; - gridCache.Invalidate(); - } - } - private float spacing = 1; /// @@ -45,7 +23,7 @@ namespace osu.Game.Screens.Edit.Compose.Components throw new ArgumentException("Grid spacing must be positive."); spacing = value; - gridCache.Invalidate(); + GridCache.Invalidate(); } } @@ -60,40 +38,20 @@ namespace osu.Game.Screens.Edit.Compose.Components set { gridLineRotation = value; - gridCache.Invalidate(); + GridCache.Invalidate(); } } - private readonly LayoutValue gridCache = new LayoutValue(Invalidation.RequiredParentSizeToFit); - public TriangularPositionSnapGrid(Vector2 startPosition) + : base(startPosition) { - StartPosition = startPosition; - Masking = true; - - AddLayout(gridCache); - } - - protected override void Update() - { - base.Update(); - - if (!gridCache.IsValid) - { - ClearInternal(); - - if (DrawWidth > 0 && DrawHeight > 0) - createContent(); - - gridCache.Validate(); - } } private const float sqrt3 = 1.73205080757f; private const float sqrt3_over2 = 0.86602540378f; private const float one_over_sqrt3 = 0.57735026919f; - private void createContent() + protected override void CreateContent() { var drawSize = DrawSize; float stepSpacing = Spacing * sqrt3_over2; @@ -101,130 +59,19 @@ namespace osu.Game.Screens.Edit.Compose.Components var step2 = GeometryUtils.RotateVector(new Vector2(stepSpacing, 0), -GridLineRotation - 90); var step3 = GeometryUtils.RotateVector(new Vector2(stepSpacing, 0), -GridLineRotation - 150); - generateGridLines(step1, drawSize); - generateGridLines(-step1, drawSize); + GenerateGridLines(step1, drawSize); + GenerateGridLines(-step1, drawSize); - generateGridLines(step2, drawSize); - generateGridLines(-step2, drawSize); + GenerateGridLines(step2, drawSize); + GenerateGridLines(-step2, drawSize); - generateGridLines(step3, drawSize); - generateGridLines(-step3, drawSize); + GenerateGridLines(step3, drawSize); + GenerateGridLines(-step3, drawSize); - generateOutline(drawSize); + GenerateOutline(drawSize); } - private void generateGridLines(Vector2 step, Vector2 drawSize) - { - int index = 0; - var currentPosition = startPosition; - - // Make lines the same width independent of display resolution. - float lineWidth = DrawWidth / ScreenSpaceDrawQuad.Width; - float lineLength = drawSize.Length * 2; - - List generatedLines = new List(); - - while (lineDefinitelyIntersectsBox(currentPosition, step.PerpendicularLeft, drawSize) || - isMovingTowardsBox(currentPosition, step, drawSize)) - { - var gridLine = new Box - { - Colour = Colour4.White, - Alpha = 0.1f, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.None, - Width = lineWidth, - Height = lineLength, - Position = currentPosition, - Rotation = MathHelper.RadiansToDegrees(MathF.Atan2(step.Y, step.X)), - }; - - generatedLines.Add(gridLine); - - index += 1; - currentPosition = startPosition + index * step; - } - - if (generatedLines.Count == 0) - return; - - generatedLines.First().Alpha = 0.3f; - - AddRangeInternal(generatedLines); - } - - private bool isMovingTowardsBox(Vector2 currentPosition, Vector2 step, Vector2 box) - { - return (currentPosition + step).LengthSquared < currentPosition.LengthSquared || - (currentPosition + step - box).LengthSquared < (currentPosition - box).LengthSquared; - } - - private bool lineDefinitelyIntersectsBox(Vector2 lineStart, Vector2 lineDir, Vector2 box) - { - var p2 = lineStart + lineDir; - - double d1 = det(Vector2.Zero); - double d2 = det(new Vector2(box.X, 0)); - double d3 = det(new Vector2(0, box.Y)); - double d4 = det(box); - - return definitelyDifferentSign(d1, d2) || definitelyDifferentSign(d3, d4) || - definitelyDifferentSign(d1, d3) || definitelyDifferentSign(d2, d4); - - double det(Vector2 p) => (p.X - lineStart.X) * (p2.Y - lineStart.Y) - (p.Y - lineStart.Y) * (p2.X - lineStart.X); - - bool definitelyDifferentSign(double a, double b) => !Precision.AlmostEquals(a, 0) && - !Precision.AlmostEquals(b, 0) && - Math.Sign(a) != Math.Sign(b); - } - - private void generateOutline(Vector2 drawSize) - { - // Make lines the same width independent of display resolution. - float lineWidth = DrawWidth / ScreenSpaceDrawQuad.Width; - - AddRangeInternal(new[] - { - new Box - { - Colour = Colour4.White, - Alpha = 0.3f, - Origin = Anchor.CentreLeft, - RelativeSizeAxes = Axes.X, - Height = lineWidth, - Y = 0, - }, - new Box - { - Colour = Colour4.White, - Alpha = 0.3f, - Origin = Anchor.CentreLeft, - RelativeSizeAxes = Axes.X, - Height = lineWidth, - Y = drawSize.Y, - }, - new Box - { - Colour = Colour4.White, - Alpha = 0.3f, - Origin = Anchor.TopCentre, - RelativeSizeAxes = Axes.Y, - Width = lineWidth, - X = 0, - }, - new Box - { - Colour = Colour4.White, - Alpha = 0.3f, - Origin = Anchor.TopCentre, - RelativeSizeAxes = Axes.Y, - Width = lineWidth, - X = drawSize.X, - }, - }); - } - - public Vector2 GetSnappedPosition(Vector2 original) + public override Vector2 GetSnappedPosition(Vector2 original) { Vector2 relativeToStart = GeometryUtils.RotateVector(original - StartPosition, GridLineRotation); Vector2 hex = pixelToHex(relativeToStart);