Skip to content

Commit

Permalink
Merge pull request ppy#6066 from OliBomby/betterer-builder
Browse files Browse the repository at this point in the history
Improve incremental B-spline builder via stochastic optimisation
  • Loading branch information
peppy authored Dec 8, 2023
2 parents 44f2f93 + e7c7397 commit 67e11cc
Show file tree
Hide file tree
Showing 4 changed files with 310 additions and 122 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System.Linq;
using osu.Framework.Graphics;
using osuTK.Graphics;
using osu.Framework.Graphics.Containers;
Expand All @@ -18,6 +19,7 @@ public partial class TestSceneInteractivePathDrawing : FrameworkTestScene
{
private readonly Path rawDrawnPath;
private readonly Path approximatedDrawnPath;
private readonly Path controlPointPath;
private readonly Container controlPointViz;

private readonly IncrementalBSplineBuilder bSplineBuilder = new IncrementalBSplineBuilder();
Expand All @@ -39,6 +41,12 @@ public TestSceneInteractivePathDrawing()
Colour = Color4.Blue,
PathRadius = 3,
},
controlPointPath = new Path
{
Colour = Color4.LightGreen,
PathRadius = 1,
Alpha = 0.5f,
},
controlPointViz = new Container
{
RelativeSizeAxes = Axes.Both,
Expand All @@ -55,11 +63,11 @@ public TestSceneInteractivePathDrawing()
bSplineBuilder.Clear();
});

AddSliderStep($"{nameof(bSplineBuilder.Degree)}", 1, 5, 3, v =>
AddSliderStep($"{nameof(bSplineBuilder.Degree)}", 1, 4, 3, v =>
{
bSplineBuilder.Degree = v;
});
AddSliderStep($"{nameof(bSplineBuilder.Tolerance)}", 0f, 3f, 1.5f, v =>
AddSliderStep($"{nameof(bSplineBuilder.Tolerance)}", 0f, 3f, 2f, v =>
{
bSplineBuilder.Tolerance = v;
});
Expand All @@ -71,17 +79,21 @@ public TestSceneInteractivePathDrawing()

private void updateControlPointsViz()
{
controlPointPath.Vertices = bSplineBuilder.ControlPoints.SelectMany(o => o).ToArray();
controlPointViz.Clear();

foreach (var cp in bSplineBuilder.ControlPoints)
foreach (var segment in bSplineBuilder.ControlPoints)
{
controlPointViz.Add(new Box
foreach (var cp in segment)
{
Origin = Anchor.Centre,
Size = new Vector2(10),
Position = cp,
Colour = Color4.LightGreen,
});
controlPointViz.Add(new Box
{
Origin = Anchor.Centre,
Size = new Vector2(10),
Position = cp,
Colour = Color4.LightGreen,
});
}
}
}

Expand Down Expand Up @@ -109,5 +121,13 @@ protected override void OnDrag(DragEvent e)
{
bSplineBuilder.AddLinearPoint(rawDrawnPath.ToLocalSpace(ToScreenSpace(e.MousePosition)));
}

protected override void OnDragEnd(DragEndEvent e)
{
if (e.Button == MouseButton.Left)
bSplineBuilder.Finish();

base.OnDragEnd(e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
using System;
using System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Lines;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Utils;
using osu.Framework.Testing;
Expand Down Expand Up @@ -32,31 +34,27 @@ public TestScenePiecewiseLinearToBSpline()
Cell(0).AddRange(new[]
{
createLabel(nameof(PathApproximator.BezierToPiecewiseLinear)),
new ApproximatedPathTest(PathApproximator.BezierToPiecewiseLinear),
doubleApproximatedPathTests[^1],
});

doubleApproximatedPathTests.Add(new DoubleApproximatedPathTest(PathApproximator.CatmullToPiecewiseLinear));
Cell(1).AddRange(new[]
{
createLabel(nameof(PathApproximator.CatmullToPiecewiseLinear)),
new ApproximatedPathTest(PathApproximator.CatmullToPiecewiseLinear),
doubleApproximatedPathTests[^1],
});

doubleApproximatedPathTests.Add(new DoubleApproximatedPathTest(PathApproximator.CircularArcToPiecewiseLinear));
Cell(2).AddRange(new[]
{
createLabel(nameof(PathApproximator.CircularArcToPiecewiseLinear)),
new ApproximatedPathTest(PathApproximator.CircularArcToPiecewiseLinear),
doubleApproximatedPathTests[^1],
});

doubleApproximatedPathTests.Add(new DoubleApproximatedPathTest(PathApproximator.LagrangePolynomialToPiecewiseLinear));
Cell(3).AddRange(new[]
{
createLabel(nameof(PathApproximator.LagrangePolynomialToPiecewiseLinear)),
new ApproximatedPathTest(PathApproximator.LagrangePolynomialToPiecewiseLinear),
doubleApproximatedPathTests[^1],
});

Expand Down Expand Up @@ -134,26 +132,7 @@ private void updateTests()

public delegate List<Vector2> ApproximatorFunc(ReadOnlySpan<Vector2> controlPoints);

private partial class ApproximatedPathTest : SmoothPath
{
public ApproximatedPathTest(ApproximatorFunc approximator)
{
Vector2[] points = new Vector2[5];
points[0] = new Vector2(50, 250);
points[1] = new Vector2(150, 230);
points[2] = new Vector2(100, 150);
points[3] = new Vector2(200, 80);
points[4] = new Vector2(250, 50);

AutoSizeAxes = Axes.None;
RelativeSizeAxes = Axes.Both;
PathRadius = 2;
Vertices = approximator(points);
Colour = Color4.White;
}
}

private partial class DoubleApproximatedPathTest : SmoothPath
private partial class DoubleApproximatedPathTest : Container
{
private readonly Vector2[] inputPath;

Expand All @@ -173,6 +152,10 @@ private partial class DoubleApproximatedPathTest : SmoothPath

public bool OptimizePath { get; set; }

private readonly Path approximatedDrawnPath;
private readonly Path controlPointPath;
private readonly Container controlPointViz;

public DoubleApproximatedPathTest(ApproximatorFunc approximator)
{
Vector2[] points = new Vector2[5];
Expand All @@ -184,17 +167,54 @@ public DoubleApproximatedPathTest(ApproximatorFunc approximator)

AutoSizeAxes = Axes.None;
RelativeSizeAxes = Axes.Both;
PathRadius = 2;
Colour = Color4.Magenta;
inputPath = approximator(points).ToArray();

Children = new Drawable[]
{
new Path
{
Colour = Color4.White,
PathRadius = 2,
Vertices = inputPath,
},
approximatedDrawnPath = new Path
{
Colour = Color4.Magenta,
PathRadius = 2,
},
controlPointPath = new Path
{
Colour = Color4.LightGreen,
PathRadius = 1,
Alpha = 0.5f,
},
controlPointViz = new Container
{
RelativeSizeAxes = Axes.Both,
Alpha = 0.5f,
},
};
}

public void UpdatePath()
{
if (!OptimizePath) return;

var controlPoints = PathApproximator.PiecewiseLinearToBSpline(inputPath, NumControlPoints, Degree, NumTestPoints, MaxIterations, LearningRate, B1, B2);
Vertices = PathApproximator.BSplineToPiecewiseLinear(controlPoints.ToArray(), Degree);
approximatedDrawnPath.Vertices = PathApproximator.BSplineToPiecewiseLinear(controlPoints.ToArray(), Degree);
controlPointPath.Vertices = controlPoints;
controlPointViz.Clear();

foreach (var cp in controlPoints)
{
controlPointViz.Add(new Box
{
Origin = Anchor.Centre,
Size = new Vector2(10),
Position = cp,
Colour = Color4.LightGreen,
});
}
}
}
}
Expand Down
Loading

0 comments on commit 67e11cc

Please sign in to comment.