Browse Source

Use Span<double> instead of _Vector

pull/9804/head
Max Katz 4 years ago
parent
commit
6d6ec49dd3
  1. 59
      src/Avalonia.Base/Input/GestureRecognizers/VelocityTracker.cs

59
src/Avalonia.Base/Input/GestureRecognizers/VelocityTracker.cs

@ -275,7 +275,7 @@ namespace Avalonia.Input.GestureRecognizers
// Apply the Gram-Schmidt process to A to obtain its QR decomposition.
// Orthonormal basis, column-major ordVectorer.
// Orthonormal basis, column-major order Vector.
_Matrix q = new _Matrix(n, m);
// Upper triangular matrix, row-major order.
_Matrix r = new _Matrix(n, n);
@ -287,14 +287,14 @@ namespace Avalonia.Input.GestureRecognizers
}
for (int i = 0; i < j; i += 1)
{
double dot = q.GetRow(j) * q.GetRow(i);
double dot = Multiply(q.GetRow(j), q.GetRow(i));
for (int h = 0; h < m; h += 1)
{
q[j, h] = q[j, h] - dot * q[i, h];
}
}
double norm = q.GetRow(j).Norm();
double norm = Norm(q.GetRow(j));
if (norm < PrecisionErrorTolerance)
{
// Vectors are linearly dependent or zero so no solution.
@ -308,20 +308,21 @@ namespace Avalonia.Input.GestureRecognizers
}
for (int i = 0; i < n; i += 1)
{
r.Set(j, i, i < j ? 0.0 : q.GetRow(j) * a.GetRow(i));
r[j, i] = i < j ? 0.0 : Multiply(q.GetRow(j), a.GetRow(i));
}
}
// Solve R B = Qt W Y to find B. This is easy because R is upper triangular.
// We just work from bottom-right to top-left calculating B's coefficients.
_Vector wy = new _Vector(m);
// "m" isn't expected to be bigger than HistorySize=20, so allocation on stack is safe.
Span<double> wy = stackalloc double[m];
for (int h = 0; h < m; h += 1)
{
wy[h] = y[h] * w[h];
}
for (int i = n - 1; i >= 0; i -= 1)
{
result.Coefficients[i] = q.GetRow(i) * wy;
result.Coefficients[i] = Multiply(q.GetRow(i), wy);
for (int j = n - 1; j > i; j -= 1)
{
result.Coefficients[i] -= r[i, j] * result.Coefficients[j];
@ -363,43 +364,19 @@ namespace Avalonia.Input.GestureRecognizers
return result;
}
private readonly struct _Vector
private static double Multiply(Span<double> v1, Span<double> v2)
{
private readonly int _offset;
private readonly int _length;
private readonly double[] _elements;
internal _Vector(int size)
{
_offset = 0;
_length = size;
_elements = new double[size];
}
internal _Vector(double[] values, int offset, int length)
{
_offset = offset;
_length = length;
_elements = values;
}
public double this[int i]
{
get => _elements[i + _offset];
set => _elements[i + _offset] = value;
}
public static double operator *(_Vector a, _Vector b)
double result = 0.0;
for (int i = 0; i < v1.Length; i += 1)
{
double result = 0.0;
for (int i = 0; i < a._length; i += 1)
{
result += a[i] * b[i];
}
return result;
result += v1[i] * v2[i];
}
public double Norm() => Math.Sqrt(this * this);
return result;
}
private static double Norm(Span<double> v)
{
return Math.Sqrt(Multiply(v, v));
}
private readonly struct _Matrix
@ -419,7 +396,7 @@ namespace Avalonia.Input.GestureRecognizers
set => _elements[row * _columns + col] = value;
}
public _Vector GetRow(int row) => new(_elements, row * _columns, _columns);
public Span<double> GetRow(int row) => _elements.AsSpan(row * _columns, _columns);
}
}
}

Loading…
Cancel
Save