Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add method to convert piecewise linear curves to spline control points #6056

Merged
merged 37 commits into from
Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
52390d5
implement bezier approximation algorithm
OliBomby Nov 17, 2023
e2c0d92
fixes and added test
OliBomby Nov 17, 2023
4133d6e
enable optimization process later to improve loading time
OliBomby Nov 17, 2023
54e96a8
clean up and rename stuff
OliBomby Nov 18, 2023
f8f6a4c
add benchmark
OliBomby Nov 18, 2023
b621984
numpy.net implementation
OliBomby Nov 18, 2023
d9358d1
Tensor.NET implementation
OliBomby Nov 18, 2023
adf7c83
add optimized B-Spline basis function matrix
OliBomby Nov 20, 2023
5d9b789
make method private
OliBomby Nov 20, 2023
e4172c0
Added B-Spline optimization and test
OliBomby Nov 20, 2023
345b81a
add initial control points arg
OliBomby Nov 20, 2023
f847b3f
Add naive use of optimizer to IncrementalBSplineBuilder
OliBomby Nov 20, 2023
b657ac1
Merge remote-tracking branch 'upstream/master' into bezier-approximat…
OliBomby Nov 20, 2023
c112ed0
use smooth path for shape
OliBomby Nov 20, 2023
6724305
increase max iterations
OliBomby Nov 20, 2023
27e5a9d
remove tensor.net and implement with pure c#
OliBomby Nov 21, 2023
cfa1a77
Merge pull request #1 from OliBomby/bezier-approximation-pure
OliBomby Nov 21, 2023
c7745ae
code quality fixes
OliBomby Nov 21, 2023
0ef8309
fix properties in test
OliBomby Nov 21, 2023
fddf1be
SIMD optimized matmul
OliBomby Nov 22, 2023
67db61b
remove matmulTranspose
OliBomby Nov 22, 2023
4ce570e
SIMD on other matrix ops
OliBomby Nov 22, 2023
69f9799
update comments
OliBomby Nov 22, 2023
1399a1e
simplify vectorizations
OliBomby Nov 22, 2023
2782512
Add useful comments
OliBomby Nov 24, 2023
fe9eb50
Revert "code quality fixes"
OliBomby Nov 24, 2023
8ab1d6c
Revert "increase max iterations"
OliBomby Nov 24, 2023
30daa08
Revert "use smooth path for shape"
OliBomby Nov 24, 2023
9368494
Revert "Add naive use of optimizer to IncrementalBSplineBuilder"
OliBomby Nov 24, 2023
506c2ae
remove interpolator resolution arg
OliBomby Dec 3, 2023
5882173
add xmldoc and fix comment
OliBomby Dec 3, 2023
23dc4e7
add checks for weight generating func arguments
OliBomby Dec 3, 2023
5e075ad
move comment
OliBomby Dec 3, 2023
30a924f
Changed binomialCoefficients to return n+1 terms
OliBomby Dec 3, 2023
46c9471
Add xmldoc to getDistanceDistribution
OliBomby Dec 3, 2023
0f8d3cc
Add argument check for matLerp
OliBomby Dec 3, 2023
a3f3fa6
Merge branch 'master' into bezier-approximation-tensor
bdach Dec 7, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions osu.Framework.Benchmarks/BenchmarkPiecewiseLinearToBezier.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// 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.Collections.Generic;
using BenchmarkDotNet.Attributes;
using osu.Framework.Utils;
using osuTK;

namespace osu.Framework.Benchmarks
{
public class BenchmarkPiecewiseLinearToBezier : BenchmarkTest
{
private Vector2[] inputPath = null!;

[Params(5, 25)]
public int NumControlPoints;

[Params(5, 200)]
public int NumTestPoints;

[Params(0, 100, 200)]
public int MaxIterations;

public override void SetUp()
{
base.SetUp();

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);
inputPath = PathApproximator.LagrangePolynomialToPiecewiseLinear(points).ToArray();
}

[Benchmark]
public List<Vector2> PiecewiseLinearToBezier()
{
return PathApproximator.PiecewiseLinearToBezier(inputPath, NumControlPoints, NumTestPoints, MaxIterations);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
// 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;
using System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Lines;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Utils;
using osu.Framework.Testing;
using osuTK;
using osuTK.Graphics;

namespace osu.Framework.Tests.Visual.Drawables
{
public partial class TestScenePiecewiseLinearToBSpline : GridTestScene
{
private int numControlPoints = 5;
private int degree = 2;
private int numTestPoints = 100;
private int maxIterations = 100;
private float learningRate = 8;
private float b1 = 0.8f;
private float b2 = 0.99f;

private readonly List<DoubleApproximatedPathTest> doubleApproximatedPathTests = new List<DoubleApproximatedPathTest>();

public TestScenePiecewiseLinearToBSpline()
: base(2, 2)
{
doubleApproximatedPathTests.Add(new DoubleApproximatedPathTest(PathApproximator.BezierToPiecewiseLinear));
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],
});

AddSliderStep($"{nameof(numControlPoints)}", 3, 25, 5, v =>
{
numControlPoints = v;
updateTests();
});

AddSliderStep($"{nameof(degree)}", 1, 5, 3, v =>
{
degree = v;
updateTests();
});

AddSliderStep($"{nameof(numTestPoints)}", 10, 200, 100, v =>
{
numTestPoints = v;
updateTests();
});

AddSliderStep($"{nameof(maxIterations)}", 0, 200, 10, v =>
{
maxIterations = v;
updateTests();
});

AddSliderStep($"{nameof(learningRate)}", 0, 10, 8f, v =>
{
learningRate = v;
updateTests();
});

AddSliderStep($"{nameof(b1)}", 0, 0.999f, 0.8f, v =>
{
b1 = v;
updateTests();
});

AddSliderStep($"{nameof(b2)}", 0, 0.999f, 0.99f, v =>
{
b2 = v;
updateTests();
});

AddStep("Enable optimization", () =>
{
foreach (var test in doubleApproximatedPathTests)
test.OptimizePath = true;
updateTests();
});
}

private void updateTests()
{
foreach (var test in doubleApproximatedPathTests)
{
test.NumControlPoints = numControlPoints;
test.Degree = degree;
test.NumTestPoints = numTestPoints;
test.MaxIterations = maxIterations;
test.LearningRate = learningRate;
test.B1 = b1;
test.B2 = b2;
test.UpdatePath();
}
}

private Drawable createLabel(string text) => new SpriteText
{
Text = text + "ToBSpline",
Font = new FontUsage(size: 20),
Colour = Color4.White,
};

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 readonly Vector2[] inputPath;

public int NumControlPoints { get; set; }

public int Degree { get; set; }

public int NumTestPoints { get; set; }

public int MaxIterations { get; set; }

public float LearningRate { get; set; }

public float B1 { get; set; }

public float B2 { get; set; }

public bool OptimizePath { get; set; }

public DoubleApproximatedPathTest(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;
Colour = Color4.Magenta;
inputPath = approximator(points).ToArray();
}

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

var controlPoints = PathApproximator.PiecewiseLinearToBSpline(inputPath, NumControlPoints, Degree, NumTestPoints, MaxIterations, LearningRate, B1, B2);
Vertices = PathApproximator.BSplineToPiecewiseLinear(controlPoints.ToArray(), Degree);
}
}
}
}
Loading
Loading