From f5d6d52d4c9160affc348e4dd81cbb9a1f5ed352 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Sat, 13 Jan 2024 14:47:40 +0100 Subject: [PATCH] Move logic for caching segments and updating path types to PathControlPointVisualiser --- .../Components/PathControlPointPiece.cs | 42 ---------------- .../Components/PathControlPointVisualiser.cs | 48 +++++++++++++++++++ 2 files changed, 48 insertions(+), 42 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs index 03792d8520..9b40b39a9d 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs @@ -5,19 +5,15 @@ using System; using System.Collections.Generic; -using System.Linq; -using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using osu.Framework.Localisation; -using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Types; @@ -56,27 +52,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components private IBindable hitObjectPosition; private IBindable hitObjectScale; - [UsedImplicitly] - private readonly IBindable hitObjectVersion; - public PathControlPointPiece(T hitObject, PathControlPoint controlPoint) { this.hitObject = hitObject; 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; Origin = Anchor.Centre; @@ -214,28 +194,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components protected override void OnDragEnd(DragEndEvent e) => DragEnded?.Invoke(); - private void cachePoints(T hitObject) => PointsInSegment = hitObject.Path.PointsInSegment(ControlPoint); - - /// - /// Handles correction of invalid path types. - /// - private void updatePathType() - { - if (ControlPoint.Type != PathType.PERFECT_CURVE) - return; - - if (PointsInSegment.Count > 3) - ControlPoint.Type = PathType.BEZIER; - - if (PointsInSegment.Count != 3) - return; - - ReadOnlySpan points = PointsInSegment.Select(p => p.Position).ToArray(); - RectangleF boundingBox = PathApproximator.CircularArcBoundingBox(points); - if (boundingBox.Width >= 640 || boundingBox.Height >= 480) - ControlPoint.Type = PathType.BEZIER; - } - /// /// Updates the state of the circular control point marker. /// diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs index 24e2210b45..aae6275d45 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs @@ -9,15 +9,18 @@ using System.Collections.Specialized; using System.Diagnostics; using System.Linq; using Humanizer; +using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; +using osu.Framework.Utils; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Objects; @@ -52,6 +55,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components [Resolved(CanBeNull = true)] private IDistanceSnapProvider distanceSnapProvider { get; set; } + [UsedImplicitly] + private readonly IBindable hitObjectVersion; + public PathControlPointVisualiser(T hitObject, bool allowSelection) { this.hitObject = hitObject; @@ -64,6 +70,48 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components Connections = new Container> { RelativeSizeAxes = Axes.Both }, Pieces = new Container> { 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)); + } + + /// + /// Caches the PointsInSegment of Pieces and handles correction of invalid path types. + /// + private void cachePointsAndEnsureValidPathTypes() + { + List pointsInCurrentSegment = new List(); + + foreach (var controlPoint in controlPoints) + { + if (controlPoint.Type != null) + pointsInCurrentSegment = new List(); + + 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 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()