diff --git a/src/Avalonia.Visuals/Vector.cs b/src/Avalonia.Visuals/Vector.cs
index 2c02c00d00..782a917c62 100644
--- a/src/Avalonia.Visuals/Vector.cs
+++ b/src/Avalonia.Visuals/Vector.cs
@@ -88,12 +88,12 @@ namespace Avalonia
///
/// Length of the vector
///
- public double Length => Math.Sqrt(X * X + Y * Y);
+ public double Length => Math.Sqrt(_x * _x + _y * _y);
///
/// Squared Length of the vector
///
- public double SquaredLength => Math.Sqrt(Length);
+ public double SquaredLength => _x * _x + _y * _y;
///
/// Negates a vector.
@@ -201,6 +201,20 @@ namespace Avalonia
return new Vector(_x, y);
}
+ ///
+ /// Returns a normalized version of this vector.
+ ///
+ /// The normalized vector.
+ public Vector Normalize()
+ => Normalize(this);
+
+ ///
+ /// Returns a negated version of this vector.
+ ///
+ /// The negated vector.
+ public Vector Negate()
+ => Negate(this);
+
///
/// Returns the dot product of two vectors.
///
diff --git a/tests/Avalonia.Visuals.UnitTests/VectorTests.cs b/tests/Avalonia.Visuals.UnitTests/VectorTests.cs
new file mode 100644
index 0000000000..1bcc165aef
--- /dev/null
+++ b/tests/Avalonia.Visuals.UnitTests/VectorTests.cs
@@ -0,0 +1,112 @@
+// Copyright (c) The Avalonia Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using Xunit;
+using Avalonia;
+using System;
+
+namespace Avalonia.Visuals.UnitTests
+{
+ public class VectorTests
+ {
+ [Fact]
+ public void Length_Should_Return_Correct_Length_Of_Vector()
+ {
+ var vector = new Vector(2, 4);
+ var length = Math.Sqrt(2 * 2 + 4 * 4);
+
+ Assert.Equal(length, vector.Length);
+ }
+
+ [Fact]
+ public void Length_Squared_Should_Return_Correct_Length_Of_Vector()
+ {
+ var vectorA = new Vector(2, 4);
+ var squaredLengthA = 2 * 2 + 4 * 4;
+
+ Assert.Equal(squaredLengthA, vectorA.SquaredLength);
+ }
+
+ [Fact]
+ public void Normalize_Should_Return_Normalized_Vector()
+ {
+ // the length of a normalized vector must be 1
+
+ var vectorA = new Vector(13, 84);
+ var vectorB = new Vector(-34, 345);
+ var vectorC = new Vector(-34, -84);
+
+ Assert.Equal(1.0, vectorA.Normalize().Length);
+ Assert.Equal(1.0, vectorB.Normalize().Length);
+ Assert.Equal(1.0, vectorC.Normalize().Length);
+ }
+
+ [Fact]
+ public void Negate_Should_Return_Negated_Vector()
+ {
+ var vector = new Vector(2, 4);
+ var negated = new Vector(-2, -4);
+
+ Assert.Equal(negated, vector.Negate());
+ }
+
+ [Fact]
+ public void Dot_Should_Return_Correct_Value()
+ {
+ var a = new Vector(-6, 8.0);
+ var b = new Vector(5, 12.0);
+
+ Assert.Equal(66.0, Vector.Dot(a, b));
+ }
+
+ [Fact]
+ public void Cross_Should_Return_Correct_Value()
+ {
+ var a = new Vector(-6, 8.0);
+ var b = new Vector(5, 12.0);
+
+ Assert.Equal(-112.0, Vector.Cross(a, b));
+ }
+
+ [Fact]
+ public void Divied_By_Vector_Should_Return_Correct_Value()
+ {
+ var a = new Vector(10, 2);
+ var b = new Vector(5, 2);
+
+ var expected = new Vector(2, 1);
+
+ Assert.Equal(expected, Vector.Divide(a, b));
+ }
+
+ [Fact]
+ public void Divied_Should_Return_Correct_Value()
+ {
+ var vector = new Vector(10, 2);
+ var expected = new Vector(5, 1);
+
+ Assert.Equal(expected, Vector.Divide(vector, 2));
+ }
+
+ [Fact]
+ public void Multiply_By_Vector_Should_Return_Correct_Value()
+ {
+ var a = new Vector(10, 2);
+ var b = new Vector(2, 2);
+
+ var expected = new Vector(20, 4);
+
+ Assert.Equal(expected, Vector.Multiply(a, b));
+ }
+
+ [Fact]
+ public void Multiply_Should_Return_Correct_Value()
+ {
+ var vector = new Vector(10, 2);
+
+ var expected = new Vector(20, 4);
+
+ Assert.Equal(expected, Vector.Multiply(vector, 2));
+ }
+ }
+}