1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-15 10:23:02 +08:00

Move logic for caching segments and updating path types to PathControlPointVisualiser

This commit is contained in:
OliBomby 2024-01-13 14:47:40 +01:00
parent 3d3f58c252
commit f5d6d52d4c
2 changed files with 48 additions and 42 deletions

View File

@ -5,19 +5,15 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Framework.Utils;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Objects.Types;
@ -56,27 +52,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
private IBindable<Vector2> hitObjectPosition; private IBindable<Vector2> hitObjectPosition;
private IBindable<float> hitObjectScale; private IBindable<float> hitObjectScale;
[UsedImplicitly]
private readonly IBindable<int> hitObjectVersion;
public PathControlPointPiece(T hitObject, PathControlPoint controlPoint) public PathControlPointPiece(T hitObject, PathControlPoint controlPoint)
{ {
this.hitObject = hitObject; this.hitObject = hitObject;
ControlPoint = controlPoint; ControlPoint = controlPoint;
// we don't want to run the path type update on construction as it may inadvertently change the hit object.
cachePoints(hitObject);
hitObjectVersion = hitObject.Path.Version.GetBoundCopy();
// schedule ensure that updates are only applied after all operations from a single frame are applied.
// this avoids inadvertently changing the hit object path type for batch operations.
hitObjectVersion.BindValueChanged(_ => Scheduler.AddOnce(() =>
{
cachePoints(hitObject);
updatePathType();
}));
controlPoint.Changed += updateMarkerDisplay; controlPoint.Changed += updateMarkerDisplay;
Origin = Anchor.Centre; Origin = Anchor.Centre;
@ -214,28 +194,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
protected override void OnDragEnd(DragEndEvent e) => DragEnded?.Invoke(); protected override void OnDragEnd(DragEndEvent e) => DragEnded?.Invoke();
private void cachePoints(T hitObject) => PointsInSegment = hitObject.Path.PointsInSegment(ControlPoint);
/// <summary>
/// Handles correction of invalid path types.
/// </summary>
private void updatePathType()
{
if (ControlPoint.Type != PathType.PERFECT_CURVE)
return;
if (PointsInSegment.Count > 3)
ControlPoint.Type = PathType.BEZIER;
if (PointsInSegment.Count != 3)
return;
ReadOnlySpan<Vector2> points = PointsInSegment.Select(p => p.Position).ToArray();
RectangleF boundingBox = PathApproximator.CircularArcBoundingBox(points);
if (boundingBox.Width >= 640 || boundingBox.Height >= 480)
ControlPoint.Type = PathType.BEZIER;
}
/// <summary> /// <summary>
/// Updates the state of the circular control point marker. /// Updates the state of the circular control point marker.
/// </summary> /// </summary>

View File

@ -9,15 +9,18 @@ using System.Collections.Specialized;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using Humanizer; using Humanizer;
using JetBrains.Annotations;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.UserInterface; using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input; using osu.Framework.Input;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Framework.Utils;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
@ -52,6 +55,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
[Resolved(CanBeNull = true)] [Resolved(CanBeNull = true)]
private IDistanceSnapProvider distanceSnapProvider { get; set; } private IDistanceSnapProvider distanceSnapProvider { get; set; }
[UsedImplicitly]
private readonly IBindable<int> hitObjectVersion;
public PathControlPointVisualiser(T hitObject, bool allowSelection) public PathControlPointVisualiser(T hitObject, bool allowSelection)
{ {
this.hitObject = hitObject; this.hitObject = hitObject;
@ -64,6 +70,48 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
Connections = new Container<PathControlPointConnectionPiece<T>> { RelativeSizeAxes = Axes.Both }, Connections = new Container<PathControlPointConnectionPiece<T>> { RelativeSizeAxes = Axes.Both },
Pieces = new Container<PathControlPointPiece<T>> { RelativeSizeAxes = Axes.Both } Pieces = new Container<PathControlPointPiece<T>> { RelativeSizeAxes = Axes.Both }
}; };
hitObjectVersion = hitObject.Path.Version.GetBoundCopy();
// schedule ensure that updates are only applied after all operations from a single frame are applied.
// this avoids inadvertently changing the hit object path type for batch operations.
hitObjectVersion.BindValueChanged(_ => Scheduler.AddOnce(cachePointsAndEnsureValidPathTypes));
}
/// <summary>
/// Caches the PointsInSegment of Pieces and handles correction of invalid path types.
/// </summary>
private void cachePointsAndEnsureValidPathTypes()
{
List<PathControlPoint> pointsInCurrentSegment = new List<PathControlPoint>();
foreach (var controlPoint in controlPoints)
{
if (controlPoint.Type != null)
pointsInCurrentSegment = new List<PathControlPoint>();
pointsInCurrentSegment.Add(controlPoint);
// Pieces might not be ordered so we need to find the piece corresponding to the current control point.
Pieces.Single(o => o.ControlPoint == controlPoint).PointsInSegment = pointsInCurrentSegment;
}
foreach (var piece in Pieces)
{
if (piece.ControlPoint.Type != PathType.PERFECT_CURVE)
return;
if (piece.PointsInSegment.Count > 3)
piece.ControlPoint.Type = PathType.BEZIER;
if (piece.PointsInSegment.Count != 3)
return;
ReadOnlySpan<Vector2> points = piece.PointsInSegment.Select(p => p.Position).ToArray();
RectangleF boundingBox = PathApproximator.CircularArcBoundingBox(points);
if (boundingBox.Width >= 640 || boundingBox.Height >= 480)
piece.ControlPoint.Type = PathType.BEZIER;
}
} }
protected override void LoadComplete() protected override void LoadComplete()