diff --git a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs index 505b84e699..c7be921a4e 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs @@ -6,6 +6,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Primitives; using osu.Framework.Input.Events; +using osu.Framework.Utils; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Screens.Edit.Compose.Components; @@ -22,24 +23,25 @@ public override ComposeSelectionBox CreateSelectionBox() CanScaleX = true, CanScaleY = true, - OperationStarted = onStart, - OperationEnded = onEnd, + OperationStarted = () => ChangeHandler.BeginChange(), + OperationEnded = () => + { + ChangeHandler.EndChange(); + referenceOrigin = null; + }, - OnRotation = handleRotation, + OnRotation = e => rotateSelection(e.Delta.X), OnScaleX = handleScaleX, OnScaleY = handleScaleY, }; - private void onEnd() - { - ChangeHandler.EndChange(); - centre = null; - } + public override bool HandleMovement(MoveSelectionEvent moveEvent) => + moveSelection(moveEvent.InstantDelta); - private void onStart() - { - ChangeHandler.BeginChange(); - } + /// + /// During a transform, the initial origin is stored so it can be used throughout the operation. + /// + private Vector2? referenceOrigin; private void handleScaleY(DragEvent e, Anchor reference) { @@ -61,7 +63,7 @@ private void handleScaleX(DragEvent e, Anchor reference) if (direction < 0) { - // when resizing from a top drag handle, we want to move the selection first + // when resizing from a left drag handle, we want to move the selection first if (!moveSelection(new Vector2(e.Delta.X, 0))) return; } @@ -69,21 +71,11 @@ private void handleScaleX(DragEvent e, Anchor reference) scaleSelection(new Vector2(direction * e.Delta.X, 0)); } - private Vector2? centre; - - private void handleRotation(DragEvent e) - { - rotateSelection(e.Delta.X); - } - - public override bool HandleMovement(MoveSelectionEvent moveEvent) => - moveSelection(moveEvent.InstantDelta); - private bool rotateSelection(in float delta) { Quad quad = getSelectionQuad(); - centre ??= quad.Centre; + referenceOrigin ??= quad.Centre; foreach (var h in SelectedHitObjects.OfType()) { @@ -93,13 +85,13 @@ private bool rotateSelection(in float delta) continue; } - h.Position = Rotate(h.Position, centre.Value, delta); + h.Position = rotatePointAroundOrigin(h.Position, referenceOrigin.Value, delta); if (h is IHasPath path) { foreach (var point in path.Path.ControlPoints) { - point.Position.Value = Rotate(point.Position.Value, Vector2.Zero, delta); + point.Position.Value = rotatePointAroundOrigin(point.Position.Value, Vector2.Zero, delta); } } } @@ -194,24 +186,24 @@ private Quad getSelectionQuad() } /// - /// Returns rotated position from a given point. + /// Rotate a point around an arbitrary origin. /// - /// The point. - /// The center to rotate around. + /// The point. + /// The centre origin to rotate around. /// The angle to rotate (in degrees). - internal static Vector2 Rotate(Vector2 p, Vector2 center, float angle) + private static Vector2 rotatePointAroundOrigin(Vector2 point, Vector2 origin, float angle) { angle = -angle; - p.X -= center.X; - p.Y -= center.Y; + point.X -= origin.X; + point.Y -= origin.Y; Vector2 ret; - ret.X = (float)(p.X * Math.Cos(angle / 180f * Math.PI) + p.Y * Math.Sin(angle / 180f * Math.PI)); - ret.Y = (float)(p.X * -Math.Sin(angle / 180f * Math.PI) + p.Y * Math.Cos(angle / 180f * Math.PI)); + ret.X = (float)(point.X * Math.Cos(MathUtils.DegreesToRadians(angle)) + point.Y * Math.Sin(angle / 180f * Math.PI)); + ret.Y = (float)(point.X * -Math.Sin(MathUtils.DegreesToRadians(angle)) + point.Y * Math.Cos(angle / 180f * Math.PI)); - ret.X += center.X; - ret.Y += center.Y; + ret.X += origin.X; + ret.Y += origin.Y; return ret; }