1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-17 01:32:55 +08:00

use minimum enclosing circle selection centre in rotation

This commit is contained in:
OliBomby 2024-09-20 01:07:47 +02:00
parent 59ab71f786
commit ee00624751
4 changed files with 21 additions and 13 deletions

View File

@ -47,7 +47,6 @@ namespace osu.Game.Rulesets.Osu.Edit
private OsuHitObject[]? objectsInRotation; private OsuHitObject[]? objectsInRotation;
private Vector2? defaultOrigin;
private Dictionary<OsuHitObject, Vector2>? originalPositions; private Dictionary<OsuHitObject, Vector2>? originalPositions;
private Dictionary<IHasPath, Vector2[]>? originalPathControlPointPositions; private Dictionary<IHasPath, Vector2[]>? originalPathControlPointPositions;
@ -61,7 +60,7 @@ namespace osu.Game.Rulesets.Osu.Edit
changeHandler?.BeginChange(); changeHandler?.BeginChange();
objectsInRotation = selectedMovableObjects.ToArray(); objectsInRotation = selectedMovableObjects.ToArray();
defaultOrigin = GeometryUtils.GetSurroundingQuad(objectsInRotation).Centre; DefaultOrigin = GeometryUtils.MinimumEnclosingCircle(objectsInRotation).Item1;
originalPositions = objectsInRotation.ToDictionary(obj => obj, obj => obj.Position); originalPositions = objectsInRotation.ToDictionary(obj => obj, obj => obj.Position);
originalPathControlPointPositions = objectsInRotation.OfType<IHasPath>().ToDictionary( originalPathControlPointPositions = objectsInRotation.OfType<IHasPath>().ToDictionary(
obj => obj, obj => obj,
@ -73,9 +72,9 @@ namespace osu.Game.Rulesets.Osu.Edit
if (!OperationInProgress.Value) if (!OperationInProgress.Value)
throw new InvalidOperationException($"Cannot {nameof(Update)} a rotate operation without calling {nameof(Begin)} first!"); throw new InvalidOperationException($"Cannot {nameof(Update)} a rotate operation without calling {nameof(Begin)} first!");
Debug.Assert(objectsInRotation != null && originalPositions != null && originalPathControlPointPositions != null && defaultOrigin != null); Debug.Assert(objectsInRotation != null && originalPositions != null && originalPathControlPointPositions != null && DefaultOrigin != null);
Vector2 actualOrigin = origin ?? defaultOrigin.Value; Vector2 actualOrigin = origin ?? DefaultOrigin.Value;
foreach (var ho in objectsInRotation) foreach (var ho in objectsInRotation)
{ {
@ -103,7 +102,7 @@ namespace osu.Game.Rulesets.Osu.Edit
objectsInRotation = null; objectsInRotation = null;
originalPositions = null; originalPositions = null;
originalPathControlPointPositions = null; originalPathControlPointPositions = null;
defaultOrigin = null; DefaultOrigin = null;
} }
private IEnumerable<OsuHitObject> selectedMovableObjects => selectedItems.Cast<OsuHitObject>() private IEnumerable<OsuHitObject> selectedMovableObjects => selectedItems.Cast<OsuHitObject>()

View File

@ -46,7 +46,6 @@ namespace osu.Game.Overlays.SkinEditor
private Drawable[]? objectsInRotation; private Drawable[]? objectsInRotation;
private Vector2? defaultOrigin;
private Dictionary<Drawable, float>? originalRotations; private Dictionary<Drawable, float>? originalRotations;
private Dictionary<Drawable, Vector2>? originalPositions; private Dictionary<Drawable, Vector2>? originalPositions;
@ -60,7 +59,7 @@ namespace osu.Game.Overlays.SkinEditor
objectsInRotation = selectedItems.Cast<Drawable>().ToArray(); objectsInRotation = selectedItems.Cast<Drawable>().ToArray();
originalRotations = objectsInRotation.ToDictionary(d => d, d => d.Rotation); originalRotations = objectsInRotation.ToDictionary(d => d, d => d.Rotation);
originalPositions = objectsInRotation.ToDictionary(d => d, d => d.ToScreenSpace(d.OriginPosition)); originalPositions = objectsInRotation.ToDictionary(d => d, d => d.ToScreenSpace(d.OriginPosition));
defaultOrigin = GeometryUtils.GetSurroundingQuad(objectsInRotation.SelectMany(d => d.ScreenSpaceDrawQuad.GetVertices().ToArray())).Centre; DefaultOrigin = GeometryUtils.GetSurroundingQuad(objectsInRotation.SelectMany(d => d.ScreenSpaceDrawQuad.GetVertices().ToArray())).Centre;
base.Begin(); base.Begin();
} }
@ -70,7 +69,7 @@ namespace osu.Game.Overlays.SkinEditor
if (objectsInRotation == null) if (objectsInRotation == null)
throw new InvalidOperationException($"Cannot {nameof(Update)} a rotate operation without calling {nameof(Begin)} first!"); throw new InvalidOperationException($"Cannot {nameof(Update)} a rotate operation without calling {nameof(Begin)} first!");
Debug.Assert(originalRotations != null && originalPositions != null && defaultOrigin != null); Debug.Assert(originalRotations != null && originalPositions != null && DefaultOrigin != null);
if (objectsInRotation.Length == 1 && origin == null) if (objectsInRotation.Length == 1 && origin == null)
{ {
@ -79,7 +78,7 @@ namespace osu.Game.Overlays.SkinEditor
return; return;
} }
var actualOrigin = origin ?? defaultOrigin.Value; var actualOrigin = origin ?? DefaultOrigin.Value;
foreach (var drawableItem in objectsInRotation) foreach (var drawableItem in objectsInRotation)
{ {
@ -100,7 +99,7 @@ namespace osu.Game.Overlays.SkinEditor
objectsInRotation = null; objectsInRotation = null;
originalPositions = null; originalPositions = null;
originalRotations = null; originalRotations = null;
defaultOrigin = null; DefaultOrigin = null;
base.Commit(); base.Commit();
} }

View File

@ -113,9 +113,13 @@ namespace osu.Game.Screens.Edit.Compose.Components
private float convertDragEventToAngleOfRotation(DragEvent e) private float convertDragEventToAngleOfRotation(DragEvent e)
{ {
// Adjust coordinate system to the center of SelectionBox // Adjust coordinate system to the center of the selection
float startAngle = MathF.Atan2(e.LastMousePosition.Y - selectionBox.DrawHeight / 2, e.LastMousePosition.X - selectionBox.DrawWidth / 2); Vector2 center = rotationHandler?.DefaultOrigin is not null
float endAngle = MathF.Atan2(e.MousePosition.Y - selectionBox.DrawHeight / 2, e.MousePosition.X - selectionBox.DrawWidth / 2); ? selectionBox.ToLocalSpace(rotationHandler.ToScreenSpace(rotationHandler.DefaultOrigin.Value))
: selectionBox.DrawSize / 2;
float startAngle = MathF.Atan2(e.LastMousePosition.Y - center.Y, e.LastMousePosition.X - center.X);
float endAngle = MathF.Atan2(e.MousePosition.Y - center.Y, e.MousePosition.X - center.X);
return (endAngle - startAngle) * 180 / MathF.PI; return (endAngle - startAngle) * 180 / MathF.PI;
} }

View File

@ -27,6 +27,12 @@ namespace osu.Game.Screens.Edit.Compose.Components
/// </summary> /// </summary>
public Bindable<bool> CanRotateAroundPlayfieldOrigin { get; private set; } = new BindableBool(); public Bindable<bool> CanRotateAroundPlayfieldOrigin { get; private set; } = new BindableBool();
/// <summary>
/// Implementation-defined origin point to rotate around when no explicit origin is provided.
/// This field is only assigned during a rotation operation.
/// </summary>
public Vector2? DefaultOrigin { get; protected set; }
/// <summary> /// <summary>
/// Performs a single, instant, atomic rotation operation. /// Performs a single, instant, atomic rotation operation.
/// </summary> /// </summary>