From ce92286112282e5cead7fd5f9fc40590c4bb46cc Mon Sep 17 00:00:00 2001 From: JaggerJo Date: Mon, 22 Jul 2019 00:21:43 +0200 Subject: [PATCH 1/5] add basic operations as static methods and use them in the declared operators. - Dot - Cross - Normalize - Divide - Multiply - Add - Subtract - Negate --- src/Avalonia.Visuals/Vector.cs | 115 +++++++++++++++++++++++++++------ 1 file changed, 96 insertions(+), 19 deletions(-) diff --git a/src/Avalonia.Visuals/Vector.cs b/src/Avalonia.Visuals/Vector.cs index 2f1690184d..f185682dc0 100644 --- a/src/Avalonia.Visuals/Vector.cs +++ b/src/Avalonia.Visuals/Vector.cs @@ -65,9 +65,7 @@ namespace Avalonia /// Second vector /// The dot product public static double operator *(Vector a, Vector b) - { - return a.X * b.X + a.Y * b.Y; - } + => Dot(a, b); /// /// Scales a vector. @@ -76,9 +74,7 @@ namespace Avalonia /// The scaling factor. /// The scaled vector. public static Vector operator *(Vector vector, double scale) - { - return new Vector(vector._x * scale, vector._y * scale); - } + => Multiply(vector, scale); /// /// Scales a vector. @@ -87,9 +83,7 @@ namespace Avalonia /// The divisor. /// The scaled vector. public static Vector operator /(Vector vector, double scale) - { - return new Vector(vector._x / scale, vector._y / scale); - } + => Divide(vector, scale); /// /// Length of the vector @@ -102,9 +96,7 @@ namespace Avalonia /// The vector. /// The negated vector. public static Vector operator -(Vector a) - { - return new Vector(-a._x, -a._y); - } + => Negate(a); /// /// Adds two vectors. @@ -113,9 +105,7 @@ namespace Avalonia /// The second vector. /// A vector that is the result of the addition. public static Vector operator +(Vector a, Vector b) - { - return new Vector(a._x + b._x, a._y + b._y); - } + => Add(a, b); /// /// Subtracts two vectors. @@ -124,9 +114,7 @@ namespace Avalonia /// The second vector. /// A vector that is the result of the subtraction. public static Vector operator -(Vector a, Vector b) - { - return new Vector(a._x - b._x, a._y - b._y); - } + => Subtract(a, b); /// /// Check if two vectors are equal (bitwise). @@ -155,7 +143,8 @@ namespace Avalonia public override bool Equals(object obj) { - if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(null, obj)) + return false; return obj is Vector vector && Equals(vector); } @@ -206,5 +195,93 @@ namespace Avalonia { return new Vector(_x, y); } + + /// + /// Returns the dot product of two vectors. + /// + /// The first vector. + /// The second vector. + /// The dot product. + public static double Dot(Vector a, Vector b) + => a._x * b._x + a._y * b._y; + + /// + /// Returns the cross product of two vectors. + /// + /// The first vector. + /// The second vector. + /// The cross product. + public static double Cross(Vector a, Vector b) + => a._x * b._y - a._y * b._x; + + /// + /// Normalizes the given vector. + /// + /// The vector + /// The normalized vector. + public static Vector Normalize(Vector vector) + => Divide(vector, vector.Length); + + /// + /// Divides the first vector by the second. + /// + /// The first vector. + /// The second vector. + /// The scaled vector. + public static Vector Divide(Vector a, Vector b) + => new Vector(a._x / b._x, a._y / b._y); + + /// + /// Divides the vector by the given scalar. + /// + /// The vector + /// The scalar value + /// The scaled vector. + public static Vector Divide(Vector vector, double scalar) + => new Vector(vector._x / scalar, vector._y / scalar); + + /// + /// Multiplies the first vector by the second. + /// + /// The first vector. + /// The second vector. + /// The scaled vector. + public static Vector Multiply(Vector a, Vector b) + => new Vector(a._x * b._x, a._y * b._y); + + /// + /// Multiplies the vector by the given scalar. + /// + /// The vector + /// The scalar value + /// The scaled vector. + public static Vector Multiply(Vector vector, double scalar) + => new Vector(vector._x * scalar, vector._y * scalar); + + /// + /// Adds the second to the first vector + /// + /// The first vector. + /// The second vector. + /// The summed vector. + public static Vector Add(Vector a, Vector b) + => new Vector(a._x + b._x, a._y + b._y); + + /// + /// Subtracts the second from the first vector + /// + /// The first vector. + /// The second vector. + /// The difference vector. + public static Vector Subtract(Vector a, Vector b) + => new Vector(a._x - b._x, a._y - b._y); + + /// + /// Negates the vector + /// + /// The vector to negate. + /// The scaled vector. + public static Vector Negate(Vector vector) + => new Vector(-vector._x, -vector._y); } } From 7d96244e3c2480d63782245e0e52b2744d0dee5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josua=20J=C3=A4ger?= Date: Thu, 15 Aug 2019 20:17:58 +0200 Subject: [PATCH 2/5] add squared length --- src/Avalonia.Visuals/Vector.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Avalonia.Visuals/Vector.cs b/src/Avalonia.Visuals/Vector.cs index f185682dc0..78ed688295 100644 --- a/src/Avalonia.Visuals/Vector.cs +++ b/src/Avalonia.Visuals/Vector.cs @@ -90,6 +90,11 @@ namespace Avalonia /// public double Length => Math.Sqrt(X * X + Y * Y); + /// + /// Squared Length of the vector + /// + public double SquaredLength => Math.Sqrt(Length); + /// /// Negates a vector. /// From 22ac34d89b912cef0b5de1b5660201e27916e011 Mon Sep 17 00:00:00 2001 From: JaggerJo Date: Thu, 15 Aug 2019 20:28:42 +0200 Subject: [PATCH 3/5] add - Zero - One - UnitX - UnitY --- src/Avalonia.Visuals/Vector.cs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Avalonia.Visuals/Vector.cs b/src/Avalonia.Visuals/Vector.cs index f185682dc0..aede9f3905 100644 --- a/src/Avalonia.Visuals/Vector.cs +++ b/src/Avalonia.Visuals/Vector.cs @@ -283,5 +283,29 @@ namespace Avalonia /// The scaled vector. public static Vector Negate(Vector vector) => new Vector(-vector._x, -vector._y); + + /// + /// Returnes the vector (0.0, 0.0) + /// + public static Vector Zero + => new Vector(0, 0); + + /// + /// Returnes the vector (1.0, 1.0) + /// + public static Vector One + => new Vector(1, 1); + + /// + /// Returnes the vector (1.0, 0.0) + /// + public static Vector UnitX + => new Vector(1, 0); + + /// + /// Returnes the vector (0.0, 1.0) + /// + public static Vector UnitY + => new Vector(0, 1); } } From b475acab1e677c3d570e83fe791fdffac54f0e0b Mon Sep 17 00:00:00 2001 From: JaggerJo Date: Thu, 15 Aug 2019 21:17:38 +0200 Subject: [PATCH 4/5] - add tests - add instance methods for normalize & negate - make length squared simpler --- src/Avalonia.Visuals/Vector.cs | 18 ++- .../Avalonia.Visuals.UnitTests/VectorTests.cs | 112 ++++++++++++++++++ 2 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 tests/Avalonia.Visuals.UnitTests/VectorTests.cs 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)); + } + } +} From ba873bf33936234ad533c56da161a2890954c958 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josua=20J=C3=A4ger?= Date: Sat, 17 Aug 2019 17:48:01 +0200 Subject: [PATCH 5/5] use field directly instead of property Co-Authored-By: Benedikt Schroeder --- src/Avalonia.Visuals/Vector.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Visuals/Vector.cs b/src/Avalonia.Visuals/Vector.cs index 782a917c62..11bda8b00e 100644 --- a/src/Avalonia.Visuals/Vector.cs +++ b/src/Avalonia.Visuals/Vector.cs @@ -88,7 +88,7 @@ namespace Avalonia /// /// Length of the vector /// - public double Length => Math.Sqrt(_x * _x + _y * _y); + public double Length => Math.Sqrt(SquaredLength); /// /// Squared Length of the vector