diff --git a/src/GShark.Test.XUnit/Core/IntervalTests.cs b/src/GShark.Test.XUnit/Core/IntervalTests.cs index 11ff2a6b..4f4f415b 100644 --- a/src/GShark.Test.XUnit/Core/IntervalTests.cs +++ b/src/GShark.Test.XUnit/Core/IntervalTests.cs @@ -64,7 +64,7 @@ public void It_Returns_True_If_Interval_Is_Decreasing() interval.IsIncreasing.Should().Be(false); interval.IsSingleton.Should().Be(false); } - + [Fact] public void It_Returns_True_If_Interval_Is_Increasing() { diff --git a/src/GShark.Test.XUnit/Core/KnotVectorTests.cs b/src/GShark.Test.XUnit/Core/KnotVectorTests.cs index 7ebad7e3..9f488158 100644 --- a/src/GShark.Test.XUnit/Core/KnotVectorTests.cs +++ b/src/GShark.Test.XUnit/Core/KnotVectorTests.cs @@ -29,7 +29,7 @@ public void It_Creates_A_Clamped_Uniform_KnotVector() int degree = 4; int ctrlPts = 12; KnotVector expectedKnotVector = new KnotVector { 0.0, 0.0, 0.0, 0.0, 0.0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1.0, 1.0, 1.0, 1.0, 1.0 }; - + // Act KnotVector knots = new KnotVector(degree, ctrlPts); diff --git a/src/GShark.Test.XUnit/Core/LinearAlgebraTests.cs b/src/GShark.Test.XUnit/Core/LinearAlgebraTests.cs index 4b00ff8a..ebc7de89 100644 --- a/src/GShark.Test.XUnit/Core/LinearAlgebraTests.cs +++ b/src/GShark.Test.XUnit/Core/LinearAlgebraTests.cs @@ -1,9 +1,5 @@ using FluentAssertions; using GShark.Core; -using GShark.Geometry; -using System; -using System.Collections.Generic; -using System.Linq; using Xunit; using Xunit.Abstractions; @@ -17,414 +13,6 @@ public LinearAlgebraTests(ITestOutputHelper testOutput) { _testOutput = testOutput; } - public static IEnumerable ControlPoints1D => new List - { - new object[] - { - new List {0.5, 0.5, 0.5}, - new List - { - new (0.0, 0.0, 0.0, 0.5), - new (1.25, -1.25, 0.0, 0.5), - new (2.5, 0.0, 0.0, 0.5) - } - }, - - new object[] - { - new List {0.5}, - new List - { - new (0.0, 0.0, 0.0, 0.5), - new (2.5, -2.5, 0.0, 1.0), - new (5.0, 0.0, 0.0, 1.0) - } - }, - }; - public static IEnumerable ControlPoints2D => new List - { - new object[] - { - new List> { - new() { 0.5, 0.5, 0.5 }, - new() { 0.5, 0.5, 0.5 }, - }, - new List>() - { - new() - { - new (0.0, 0.0, 0.0, 0.5), - new (1.25, -1.25, 0.0, 0.5), - new (2.5, 0.0, 0.0, 0.5) - }, - new() - { - new (0.0, 0.0, 0.0, 0.5), - new (1.25, -1.25, 0.0, 0.5), - new (2.5, 0.0, 0.0, 0.5) - } - } - }, - new object[] - { - new List> { new() { 0.5 }, new() { 0.5 }}, - new List> - { - new() - { - new (0.0, 0.0, 0.0, 0.5), - new (2.5, -2.5, 0.0, 1.0), - new (5.0, 0.0, 0.0, 1.0) - }, - new() - { - new (0.0, 0.0, 0.0, 0.5), - new (2.5, -2.5, 0.0, 1.0), - new (5.0, 0.0, 0.0, 1.0) - } - } - }, - - new object[] - { - null, - new List> - { - new() - { - new (0.0, 0.0, 0.0, 1.0), - new (2.5, -2.5, 0.0, 1.0), - new (5.0, 0.0, 0.0, 1.0) - }, - new() - { - new (0.0, 0.0, 0.0, 1.0), - new (2.5, -2.5, 0.0, 1.0), - new (5.0, 0.0, 0.0, 1.0) - } - } - } - }; - - [Fact] - public void PointsHomogeniser_Throws_An_Exception_If_The_Weight_Collection_Is_Bigger_Than_ControlPts() - { - // Arrange - List controlPts = new List(); - List weights = new List { 1.0, 1.5, 1.0 }; - - // Act - Func resultFunction = () => LinearAlgebra.PointsHomogeniser(controlPts, weights); - - // Assert - resultFunction.Should().Throw(); - } - - [Theory] - [MemberData(nameof(ControlPoints1D))] - public void It_Returns_A_New_Set_Of_Control_Points(List weights, List expectedControlPoints) - { - // Arrange - List controlPts = new List - { - new (0.0, 0.0, 0), - new (2.5, -2.5, 0), - new (5.0, 0.0, 0) - }; - - // Act - List newControlPts = LinearAlgebra.PointsHomogeniser(controlPts, weights); - - // Assert - newControlPts.SequenceEqual(expectedControlPoints).Should().BeTrue(); - } - - [Fact] - public void It_Returns_A_New_Set_Of_Control_Points_By_A_Given_Weight_Value() - { - // Arrange - List pts = new List - { - new (0.0, 0.0, 0), - new (2.5, -2.5, 0), - new (5.0, 0.0, 0) - }; - List expectedControlPoints = new List - { - new (0.0, 0.0, 0.0, 1.0), - new (2.5, -2.5, 0.0, 1.0), - new (5.0, 0.0, 0.0, 1.0) - }; - - // Act - List controlPts = LinearAlgebra.PointsHomogeniser(pts, 1.0); - - // Assert - controlPts.SequenceEqual(expectedControlPoints).Should().BeTrue(); - } - - [Theory] - [MemberData(nameof(ControlPoints2D))] - public void It_Returns_A_Set_Of_Control_Points(List> weights, List> expectedSetOfCtrlPts) - { - // Arrange - List> setOfPts = new List>() - { - new() - { - new (0.0, 0.0, 0), - new (2.5, -2.5, 0), - new (5.0, 0.0, 0) - }, - new() - { - new (0.0, 0.0, 0), - new (2.5, -2.5, 0), - new (5.0, 0.0, 0) - } - }; - - // Act - List> setOfCtrlPts = LinearAlgebra.PointsHomogeniser2d(setOfPts, weights); - - // Assert - for (int i = 0; i < setOfCtrlPts.Count; i++) - { - List ctrlPts = setOfCtrlPts[i]; - List expectedCtrlPts = expectedSetOfCtrlPts[i]; - - for (int j = 0; j < ctrlPts.Count; j++) - { - Point4 ctrlPt = ctrlPts[j]; - Point4 expectedPt = expectedCtrlPts[j]; - ctrlPt.Equals(expectedPt).Should().BeTrue(); - } - } - } - - [Fact] - public void It_Returns_A_Set_Of_Weights() - { - // Arrange - List ctrlPts = new List - { - new (0.0, 0.0, 0.0, 0.5), - new (1.25, -1.25, 0.0, 0.5), - new (2.5, 0.0, 0.0, 0.5) - }; - List expectedWeights = new List { 0.5, 0.5, 0.5 }; - - // Act - List weight1d = LinearAlgebra.GetWeights(ctrlPts); - - // Assert - weight1d.SequenceEqual(expectedWeights).Should().BeTrue(); - } - - [Fact] - public void It_Returns_A_Two_Dimensional_Set_Of_Weights() - { - // Arrange - List> ctrlPts = new List> - { - new() - { - new (0.0, 0.0, 0.0, 0.5), - new (1.25, -1.25, 0.0, 0.5), - new (2.5, 0.0, 0.0, 0.5) - }, - new() - { - new (0.0, 0.0, 0.0, 0.5), - new (1.25, -1.25, 0.0, 0.5), - new (2.5, 0.0, 0.0, 0.5) - } - }; - - List> expectedWeights = new List> - { - new() {0.5, 0.5, 0.5}, - new() {0.5, 0.5, 0.5} - }; - - // Act - List> weight2d = LinearAlgebra.GetWeights2d(ctrlPts); - - // Assert - for (int i = 0; i < ctrlPts.Count; i++) - { - var expectedWts = expectedWeights[i]; - var weights = weight2d[i]; - - for (int j = 0; j < expectedWts.Count; j++) - { - var expectedWt = expectedWts[j]; - var weight = weights[j]; - weight.Equals(expectedWt).Should().BeTrue(); - } - } - } - - [Fact] - public void It_Returns_A_Dehomogenized_Point() - { - // Arrange - Point4 ctrlPt = new Point4(1.25, -1.25, 0.0, 0.5); - Point3 expectedPt = new Point3(2.5, -2.5, 0); - - // Act - Point3 pt = LinearAlgebra.PointDehomogenizer(ctrlPt); - - // Assert - pt.Equals(expectedPt).Should().BeTrue(); - } - - [Fact] - public void It_Returns_A_Set_Of_Dehomogenized_Points() - { - // Arrange - List ctrlPts = new List - { - new (0.0, 0.0, 0.0, 0.5), - new (1.25, -1.25, 0.0, 0.5), - new (2.5, 0.0, 0.0, 0.5) - }; - - List expectedPts = new List - { - new (0.0, 0.0, 0), - new (2.5, -2.5, 0), - new (5.0, 0.0, 0) - }; - - // Act - List pts = LinearAlgebra.PointDehomogenizer1d(ctrlPts); - - // Assert - pts.SequenceEqual(expectedPts).Should().BeTrue(); - } - - [Fact] - public void It_Returns_A_Two_Dimensional_Set_Of_Dehomogenized_Points() - { - // Arrange - List> ctrlPts = new List> - { - new() - { - new(0.0, 0.0, 0.0, 0.5), - new(1.25, -1.25, 0.0, 0.5), - new(2.5, 0.0, 0.0, 0.5) - }, - new() - { - new(0.0, 0.0, 0.0, 0.5), - new(1.25, -1.25, 0.0, 0.5), - new(2.5, 0.0, 0.0, 0.5) - } - }; - - List> expectedPts = new List> - { - new() - { - new (0.0, 0.0, 0), - new (2.5, -2.5, 0), - new (5.0, 0.0, 0) - }, - new() - { - new (0.0, 0.0, 0), - new (2.5, -2.5, 0), - new (5.0, 0.0, 0) - } - }; - - // Act - var pts = LinearAlgebra.PointDehomogenizer2d(ctrlPts); - - // Arrange - pts.Should().BeEquivalentTo(expectedPts); - } - - [Fact] - public void It_Returns_A_Rationalized_Set_Of_Points() - { - // Arrange - List ctrlPts = new List - { - new (0.0, 0.0, 0.0, 0.5), - new (2.5, -2.5, 0.0, 1.0), - new (5.0, 0.0, 0.0, 1.0) - }; - - List expectedPts = new List - { - new (0.0, 0.0, 0.0), - new (2.5, -2.5, 0.0), - new (5.0, 0.0, 0.0) - }; - - // Act - List rationalPoints = LinearAlgebra.RationalPoints(ctrlPts); - - // Assert - rationalPoints.SequenceEqual(expectedPts).Should().BeTrue(); - } - - [Fact] - public void It_Returns_A_Rationalized_Two_Dimensional_Set_Of_Points() - { - // Arrange - List> ctrlPts = new List> - { - new() - { - new (0.0, 0.0, 0.0, 0.5), - new (2.5, -2.5, 0.0, 1.0), - new (5.0, 0.0, 0.0, 1.0) - }, - new() - { - new (0.0, 0.0, 0.0, 0.5), - new (2.5, -2.5, 0.0, 1.0), - new (5.0, 0.0, 0.0, 1.0) - } - }; - - List> expectedPoints = new List> - { - new() - { - new (0.0, 0.0, 0.0), - new (2.5, -2.5, 0.0), - new (5.0, 0.0, 0.0) - }, - new() - { - new (0.0, 0.0, 0.0), - new (2.5, -2.5, 0.0), - new (5.0, 0.0, 0.0) - } - }; - - // Act - List> rationalPoints = LinearAlgebra.Rational2d(ctrlPts); - - // Assert - for (int i = 0; i < ctrlPts.Count; i++) - { - var expectedPts = expectedPoints[i]; - var rationalPts = rationalPoints[i]; - - for (int j = 0; j < expectedPoints.Count; j++) - { - var expectedPt = expectedPts[j]; - var rationalPt = rationalPts[j]; - rationalPt.Equals(expectedPt).Should().BeTrue(); - } - } - } [Theory] [InlineData(0, 0, 1)] diff --git a/src/GShark.Test.XUnit/Core/MatrixTests.cs b/src/GShark.Test.XUnit/Core/MatrixTests.cs index 9f21a42d..e5df3ae6 100644 --- a/src/GShark.Test.XUnit/Core/MatrixTests.cs +++ b/src/GShark.Test.XUnit/Core/MatrixTests.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Newtonsoft.Json.Bson; using Xunit; using Xunit.Abstractions; @@ -37,11 +36,11 @@ public class MatrixTests public static TheoryData DecomposedMatrixLuData => new TheoryData { - {new Matrix {new List {2,1}, new List {-4,-6}}, + {new Matrix {new List {2,1}, new List {-4,-6}}, new Matrix {new List {-4,-6}, new List {-0.5,-2}}, new []{1,0} }, - {new Matrix {new List {2,1,-4}, new List {2,2,-2}, new List {6,3,11}}, + {new Matrix {new List {2,1,-4}, new List {2,2,-2}, new List {6,3,11}}, new Matrix {new List {6,3,11}, new List { 0.33333333333333, 1, -5.6666666666667 }, new List { 0.33333333333333, 0, -7.6666666666667 }}, new []{2,1,0} }, @@ -91,13 +90,13 @@ public void It_Creates_A_Matrix_By_Given_Rows_And_Columns() matrix[0].Count.Should().Be(3); matrix.Select(x => x.Sum()).Sum().Should().Be(0.0); } - + [Fact] public void It_Creates_An_Identity_Matrix() { // Act Matrix matrix = Matrix.Identity(3); - + // Assert matrix.Should().BeEquivalentTo(IdentityMatrix); } @@ -106,8 +105,8 @@ public void It_Creates_An_Identity_Matrix() public void It_Returns_A_Transpose_Matrix() { // Arrange - Matrix matrix = new Matrix {new List {1, 2}, new List {3, 4}, new List {5, 6}}; - Matrix expectedMatrix = new Matrix {new List {1, 3, 5}, new List {2, 4, 6}}; + Matrix matrix = new Matrix { new List { 1, 2 }, new List { 3, 4 }, new List { 5, 6 } }; + Matrix expectedMatrix = new Matrix { new List { 1, 3, 5 }, new List { 2, 4, 6 } }; // Act Matrix transposedMatrix = matrix.Transpose(); @@ -149,7 +148,7 @@ public void Matrix_Product_Throws_An_Exception_If_Two_Matrices_Are_Not_Compatibl { // Arrange Matrix matrixA = new Matrix { new List { 1, 2, 3 }, new List { 4, 5, 6 } }; - Matrix matrixB = new Matrix { new List { 7, 8 }, new List { 9, 10 }}; + Matrix matrixB = new Matrix { new List { 7, 8 }, new List { 9, 10 } }; // Act Func func = () => matrixA * matrixB; @@ -162,9 +161,9 @@ public void Matrix_Product_Throws_An_Exception_If_Two_Matrices_Are_Not_Compatibl public void It_Returns_The_Product_Between_Two_Matrices() { // Arrange - Matrix matrixA = new Matrix {new List {1, 2, 3}, new List {4, 5, 6}}; - Matrix matrixB = new Matrix {new List { 7, 8 }, new List { 9, 10 }, new List { 11, 12 }}; - Matrix matrixExpected = new Matrix { new List { 58,64 }, new List { 139,154 } }; + Matrix matrixA = new Matrix { new List { 1, 2, 3 }, new List { 4, 5, 6 } }; + Matrix matrixB = new Matrix { new List { 7, 8 }, new List { 9, 10 }, new List { 11, 12 } }; + Matrix matrixExpected = new Matrix { new List { 58, 64 }, new List { 139, 154 } }; // Act Matrix productMatrix = matrixA * matrixB; @@ -192,7 +191,7 @@ public void It_Returns_The_Sum_Between_Two_Matrices() { // Arrange Matrix matrixA = new Matrix { new List { 1, 2 }, new List { 4, 5 } }; - Matrix matrixB = new Matrix { new List { 7, 8 }, new List { 9, 10 }}; + Matrix matrixB = new Matrix { new List { 7, 8 }, new List { 9, 10 } }; Matrix matrixExpected = new Matrix { new List { 8, 10 }, new List { 13, 15 } }; // Act @@ -261,9 +260,9 @@ public void Compute_The_Equation_Between_A_LuMatrix_And_A_Vector(Matrix matrix, public void Solve_Returns_An_Exception_If_The_Matrix_Is_Singular() { // Arrange - Matrix matrix = new Matrix { new List { 2,4,6 }, new List { 2,0,2 }, new List { 6,8,14 } }; - Vector vector = new Vector {3, 13, 4}; - int[] pivot = new[] {1, 1, 1}; + Matrix matrix = new Matrix { new List { 2, 4, 6 }, new List { 2, 0, 2 }, new List { 6, 8, 14 } }; + Vector vector = new Vector { 3, 13, 4 }; + int[] pivot = new[] { 1, 1, 1 }; // Act Func func = () => Matrix.Solve(matrix, pivot, vector); @@ -276,8 +275,8 @@ public void Solve_Returns_An_Exception_If_The_Matrix_Is_Singular() public void Solve_Returns_An_Exception_If_The_Decomposition_Value_Dimension_Is_Different_Of_Matrix_Row_Dimension() { // Arrange - Matrix matrix = new Matrix {new List {1, 2, 4}, new List {3, 8, 14}, new List {2, 6, 13}}; - Vector vector = new Vector { 3, 13}; + Matrix matrix = new Matrix { new List { 1, 2, 4 }, new List { 3, 8, 14 }, new List { 2, 6, 13 } }; + Vector vector = new Vector { 3, 13 }; int[] pivot = new[] { 1, 1, 1 }; // Act @@ -295,8 +294,8 @@ public void It_Returns_The_Inverse_Of_A_Matrix() Matrix matrix = new Matrix { new List { 1, 2, 4 }, new List { 3, 8, 14 }, new List { 2, 6, 13 } }; Matrix matrixExpected = new Matrix { - new List { 3.333333333333334, -0.33333333333333304, -0.6666666666666671 }, - new List { -1.8333333333333337, 0.8333333333333331, -0.333333333333333 }, + new List { 3.333333333333334, -0.33333333333333304, -0.6666666666666671 }, + new List { -1.8333333333333337, 0.8333333333333331, -0.333333333333333 }, new List { 0.3333333333333334, -0.33333333333333326, 0.3333333333333332 } }; @@ -311,8 +310,8 @@ public void It_Returns_The_Inverse_Of_A_Matrix() public void Fill_Diagonal_Throw_An_Exception_If_The_Matrix_Is_Less_Than_2D() { // Arrange - Matrix matrix0 = new Matrix { new List { 1}, new List { 3, 8}, new List { 2 } }; - Matrix matrix1 = new Matrix { new List { 1}, new List { 3, 8}}; + Matrix matrix0 = new Matrix { new List { 1 }, new List { 3, 8 }, new List { 2 } }; + Matrix matrix1 = new Matrix { new List { 1 }, new List { 3, 8 } }; // Act Func func0 = () => matrix0.FillDiagonal(0, 0, 0); diff --git a/src/GShark.Test.XUnit/Core/SetsTests.cs b/src/GShark.Test.XUnit/Core/SetsTests.cs index eab5841e..e9c6f240 100644 --- a/src/GShark.Test.XUnit/Core/SetsTests.cs +++ b/src/GShark.Test.XUnit/Core/SetsTests.cs @@ -95,7 +95,7 @@ public void Range_Throws_An_Exception_If_The_Value_Is_Negative_Or_Zero(int maxVa { // Act Func resultFunction = () => Sets.Range(maxValue); - + // Assert resultFunction.Should().Throw().WithMessage("T1 value range can not be negative or zero."); } @@ -172,8 +172,8 @@ public void It_Returns_A_SetUnion_From_Two_Collections_Of_Numbers(double[] set1, } [Theory] - [InlineData(new double[]{ 3, 5, 7 }, new double[] { 5, 6 }, new double[] { 3, 7 })] - [InlineData(new double[] { 3, 5, 7, 9, 11 }, new double[] {}, new double[] { 3, 5, 7, 9, 11 })] + [InlineData(new double[] { 3, 5, 7 }, new double[] { 5, 6 }, new double[] { 3, 7 })] + [InlineData(new double[] { 3, 5, 7, 9, 11 }, new double[] { }, new double[] { 3, 5, 7, 9, 11 })] public void It_Returns_A_SetDifference_From_Two_Collections_Of_Numbers(double[] set1, double[] set2, double[] setExpected) { // Act @@ -209,7 +209,7 @@ public void It_Returns_A_Reversed_BiDimensional_Collection_Of_Points() new Point3( 10d, -10d, 10) }, new List - { + { new Point3( 0d, -30d, 0), new Point3( 10d, -30d, 0) diff --git a/src/GShark.Test.XUnit/Core/TransformTests.cs b/src/GShark.Test.XUnit/Core/TransformTests.cs index 97889dcd..9961dfb9 100644 --- a/src/GShark.Test.XUnit/Core/TransformTests.cs +++ b/src/GShark.Test.XUnit/Core/TransformTests.cs @@ -31,7 +31,7 @@ public void It_Returns_An_Instance_Of_Transform() public void It_Creates_A_Transform_By_Copying_Another_Transform() { // Arrange - Transform transform = new Transform {[0] = {[0] = 2}, [1] = {[0] = 2}}; + Transform transform = new Transform { [0] = { [0] = 2 }, [1] = { [0] = 2 } }; // Act Transform copyTransform = Transform.Copy(transform); @@ -76,7 +76,7 @@ public void It_Returns_A_Translated_Transformed_Matrix() public void It_Returns_A_Rotated_Transformed_Matrix() { // Arrange - var center = new Point3(5,5,0); + var center = new Point3(5, 5, 0); double angleInRadians = GeoSharkMath.ToRadians(30); // Act @@ -97,7 +97,7 @@ public void It_Returns_A_Scaled_Transformation_Matrix() { // Act Transform scale1 = Transform.Scale(new Point3(0, 0, 0), 0.5); - Transform scale2 = Transform.Scale(new Point3( 10, 10, 0), 0.5); + Transform scale2 = Transform.Scale(new Point3(10, 10, 0), 0.5); // Assert scale1[0][0].Should().Be(0.5); scale2[0][0].Should().Be(0.5); @@ -113,7 +113,7 @@ public void It_Returns_A_Scaled_Transformation_Matrix() public void It_Returns_A_Mirrored_Transformation_Matrix() { // Arrange - var pt = new Point3(10,10,0); + var pt = new Point3(10, 10, 0); Plane plane = new Plane(pt, Vector3.XAxis); // Act @@ -121,8 +121,8 @@ public void It_Returns_A_Mirrored_Transformation_Matrix() // Assert transform[0][0].Should().Be(-1.0); - transform[1][1].Should().Be(1.0); - transform[2][2].Should().Be(1.0); + transform[1][1].Should().Be(1.0); + transform[2][2].Should().Be(1.0); transform[3][3].Should().Be(1.0); transform[0][3].Should().Be(20); } @@ -152,7 +152,7 @@ public void It_Returns_A_Transformation_Projection_By_A_Plane() public void It_Returns_A_Plane_To_Plane_Transformation_Matrix() { // Arrange - var origin = new Point3( 5, 0, 0); + var origin = new Point3(5, 0, 0); var dir = new Vector3(-10, -15, 0); Plane plane = new Plane(origin, dir); diff --git a/src/GShark.Test.XUnit/Core/TrigonometryTests.cs b/src/GShark.Test.XUnit/Core/TrigonometryTests.cs index 0d38d41f..b23f2100 100644 --- a/src/GShark.Test.XUnit/Core/TrigonometryTests.cs +++ b/src/GShark.Test.XUnit/Core/TrigonometryTests.cs @@ -1,6 +1,5 @@ using FluentAssertions; using GShark.Core; -using GShark.ExtendedMethods; using GShark.Geometry; using System.Collections.Generic; using Xunit; @@ -13,11 +12,11 @@ public class TrigonometryTests public void It_Returns_True_If_Points_Are_Planar() { // Arrange - Point3 pt1 = new Point3( 0.0, 0.0, 0.0); - Point3 pt2 = new Point3( 10.0, 0.0, 0.0); - Point3 pt3 = new Point3( 5.0, 5.0, 0.0); - Point3 pt4 = new Point3( -5.0, -15.0, 0.0); - List points = new List{pt1,pt2,pt3,pt4}; + Point3 pt1 = new Point3(0.0, 0.0, 0.0); + Point3 pt2 = new Point3(10.0, 0.0, 0.0); + Point3 pt3 = new Point3(5.0, 5.0, 0.0); + Point3 pt4 = new Point3(-5.0, -15.0, 0.0); + List points = new List { pt1, pt2, pt3, pt4 }; // Arrange Trigonometry.ArePointsCoplanar(points).Should().BeTrue(); @@ -27,9 +26,9 @@ public void It_Returns_True_If_Points_Are_Planar() public void It_Returns_True_If_Three_Points_Are_Collinear() { // Arrange - Point3 pt1 = new Point3( 25.923, 27.057, 0.0); - Point3 pt2 = new Point3( 35.964, 31.367, 0.0); - Point3 pt3 = new Point3( 51.299, 37.950, 0.0); + Point3 pt1 = new Point3(25.923, 27.057, 0.0); + Point3 pt2 = new Point3(35.964, 31.367, 0.0); + Point3 pt3 = new Point3(51.299, 37.950, 0.0); // Assert Trigonometry.ArePointsCollinear(pt1, pt2, pt3, GeoSharkMath.MinTolerance).Should().BeTrue(); @@ -39,9 +38,9 @@ public void It_Returns_True_If_Three_Points_Are_Collinear() public void It_Returns_False_If_Three_Points_Are_Not_Collinear() { // Arrange - Point3 pt1 = new Point3( 25.923, 27.057, 0.0); - Point3 pt2 = new Point3( 35.964, 20.451, 0.0); - Point3 pt3 = new Point3( 51.299, 37.950, 0.0); + Point3 pt1 = new Point3(25.923, 27.057, 0.0); + Point3 pt2 = new Point3(35.964, 20.451, 0.0); + Point3 pt3 = new Point3(51.299, 37.950, 0.0); // Assert Trigonometry.ArePointsCollinear(pt1, pt2, pt3, GeoSharkMath.MinTolerance).Should().BeFalse(); @@ -58,8 +57,8 @@ public void It_Returns_The_Closest_Point_On_A_Segment(double[] ptToCheck, double // t values [0 and 1] and start and end point. var testPt = new Point3(ptToCheck[0], ptToCheck[1], ptToCheck[2]); var expectedPt = new Point3(ptExpected[0], ptExpected[1], ptExpected[2]); - Point3 pt0 = new Point3( 5, 5, 0); - Point3 pt1 = new Point3( 10, 10, 0); + Point3 pt0 = new Point3(5, 5, 0); + Point3 pt1 = new Point3(10, 10, 0); // Act (double tValue, Point3 pt) closestPt = Trigonometry.ClosestPointToSegment(testPt, pt0, pt1, 0, 1); diff --git a/src/GShark.Test.XUnit/Data/BoundingBoxCollection.cs b/src/GShark.Test.XUnit/Data/BoundingBoxCollection.cs index 572027c0..10e0c64e 100644 --- a/src/GShark.Test.XUnit/Data/BoundingBoxCollection.cs +++ b/src/GShark.Test.XUnit/Data/BoundingBoxCollection.cs @@ -60,14 +60,14 @@ public static IEnumerable BoundingBoxCollections { get { - yield return new object[] {BoundingBox2D(), BoundingBox2D()[0], BoundingBox2D()[2]}; - yield return new object[] {BoundingBox3D(), new Point3(74.264416, 13.940616, -4.22451), new Point3(100.92443, 45.16886, 3.812853)}; - yield return new object[] {NegativeBoundingBox(), NegativeBoundingBox()[0], NegativeBoundingBox()[1]}; + yield return new object[] { BoundingBox2D(), BoundingBox2D()[0], BoundingBox2D()[2] }; + yield return new object[] { BoundingBox3D(), new Point3(74.264416, 13.940616, -4.22451), new Point3(100.92443, 45.16886, 3.812853) }; + yield return new object[] { NegativeBoundingBox(), NegativeBoundingBox()[0], NegativeBoundingBox()[1] }; yield return new object[] { NegativeMinValuePositiveMaxValue(), NegativeMinValuePositiveMaxValue()[0], NegativeMinValuePositiveMaxValue()[1] }; - yield return new object[] {BoundingBoxWithZValue(), BoundingBoxWithZValue()[0], BoundingBoxWithZValue()[1]}; + yield return new object[] { BoundingBoxWithZValue(), BoundingBoxWithZValue()[0], BoundingBoxWithZValue()[1] }; } } @@ -75,12 +75,12 @@ public static IEnumerable BoundingBoxAxisLength { get { - yield return new object[] {BoundingBox2D(), 1, 10d}; - yield return new object[] {NegativeBoundingBox(), 2, 0d}; //Index 2 is equal axis Z. - yield return new object[] {NegativeMinValuePositiveMaxValue(), 0, 22d}; - yield return new object[] {BoundingBoxWithZValue(), 2, 15d}; - yield return new object[] {NegativeBoundingBox(), -2, 0}; - yield return new object[] {NegativeBoundingBox(), 4, 0}; + yield return new object[] { BoundingBox2D(), 1, 10d }; + yield return new object[] { NegativeBoundingBox(), 2, 0d }; //Index 2 is equal axis Z. + yield return new object[] { NegativeMinValuePositiveMaxValue(), 0, 22d }; + yield return new object[] { BoundingBoxWithZValue(), 2, 15d }; + yield return new object[] { NegativeBoundingBox(), -2, 0 }; + yield return new object[] { NegativeBoundingBox(), 4, 0 }; } } @@ -88,12 +88,12 @@ public static IEnumerable BoundingBoxIntersections { get { - yield return new object[] {BoundingBox2D(), NegativeMinValuePositiveMaxValue(), true}; - yield return new object[] {BoundingBox2D(), NegativeBoundingBox(), false}; + yield return new object[] { BoundingBox2D(), NegativeMinValuePositiveMaxValue(), true }; + yield return new object[] { BoundingBox2D(), NegativeBoundingBox(), false }; } } - public static TheoryData BoundingBoxIntersectionsUnset => + public static TheoryData BoundingBoxIntersectionsUnset => new TheoryData { {BoundingBox2D(), BoundingBox.Unset}, diff --git a/src/GShark.Test.XUnit/Data/NurbsCurveCollection.cs b/src/GShark.Test.XUnit/Data/NurbsCurveCollection.cs index bba61cfb..89160ecc 100644 --- a/src/GShark.Test.XUnit/Data/NurbsCurveCollection.cs +++ b/src/GShark.Test.XUnit/Data/NurbsCurveCollection.cs @@ -1,5 +1,4 @@ -using GShark.Core; -using GShark.Geometry; +using GShark.Geometry; using System.Collections.Generic; namespace GShark.Test.XUnit.Data diff --git a/src/GShark.Test.XUnit/Geometry/ArcTests.cs b/src/GShark.Test.XUnit/Geometry/ArcTests.cs index bc9d192a..5c987b04 100644 --- a/src/GShark.Test.XUnit/Geometry/ArcTests.cs +++ b/src/GShark.Test.XUnit/Geometry/ArcTests.cs @@ -1,5 +1,4 @@ -using System.Drawing; -using FluentAssertions; +using FluentAssertions; using GShark.Core; using GShark.Geometry; using GShark.Geometry.Interfaces; @@ -89,7 +88,7 @@ public void It_Returns_The_BoundingBox_Of_The_Arc() // Assert bBox2D.Min.EpsilonEquals(new Vector3(11.490667, 0, 0), 6).Should().BeTrue(); bBox2D.Max.EpsilonEquals(new Vector3(15, 9.641814, 0), 6).Should().BeTrue(); - + bBox3D.Min.EpsilonEquals(new Vector3(69.115079, 8.858347, -1.884313), 6).Should().BeTrue(); bBox3D.Max.EpsilonEquals(new Vector3(102.068402, 36.39316, 5.246477), 6).Should().BeTrue(); } @@ -111,7 +110,7 @@ public void It_Returns_A_Point_On_The_Arc_At_The_Given_Parameter(double t, doubl } [Theory] - [InlineData(new double[]{ 82.248292, 15.836914, 3.443127 }, new double[] { 80.001066, 9.815219, 5.041724 })] + [InlineData(new double[] { 82.248292, 15.836914, 3.443127 }, new double[] { 80.001066, 9.815219, 5.041724 })] [InlineData(new double[] { 85.591741, 24.79606, 1.064717 }, new double[] { 74.264416, 36.39316, -1.884313 })] public void It_Returns_The_Closest_Point_On_An_Arc(double[] ptToTest, double[] result) { @@ -164,7 +163,7 @@ public void It_Returns_The_Tangent_At_The_Give_Parameter_T(double t, double[] pt public void It_Is_A_Curve_Representation_Of_The_Arc_From_0_To_90_Deg() { // Arrange - double[] weightChecks = new[] {1.0, 0.9004471023526769, 1.0, 0.9004471023526769, 1.0}; + double[] weightChecks = new[] { 1.0, 0.9004471023526769, 1.0, 0.9004471023526769, 1.0 }; Point3[] ptChecks = new[] { new Point3(0, 20, 0), new Point3(0, 20, 9.661101312331581), @@ -229,7 +228,7 @@ public void It_Is_A_Curve_Representation_Of_ExampleArc3D() arc.Knots[i].Should().Be(0); arc.Knots[i + 7].Should().Be(1); } - else if(i<5) + else if (i < 5) { arc.Knots[i].Should().Be(0.3333333333333333); } diff --git a/src/GShark.Test.XUnit/Geometry/BoundingBoxTests.cs b/src/GShark.Test.XUnit/Geometry/BoundingBoxTests.cs index d0ae07d0..5c69e434 100644 --- a/src/GShark.Test.XUnit/Geometry/BoundingBoxTests.cs +++ b/src/GShark.Test.XUnit/Geometry/BoundingBoxTests.cs @@ -1,8 +1,8 @@ using FluentAssertions; +using GShark.Core; using GShark.Geometry; using GShark.Test.XUnit.Data; using System.Collections.Generic; -using GShark.Core; using Xunit; using Xunit.Abstractions; @@ -36,8 +36,8 @@ public void It_Creates_An_Aligned_BoundingBox() { // Arrange Plane orientedPlane = Plane.PlaneXY.Rotate(GeoSharkMath.ToRadians(30)); - var expectedMin = new Point3( 45.662928, 59.230957, -4.22451); - var expectedMax = new Point3( 77.622297, 78.520011, 3.812853); + var expectedMin = new Point3(45.662928, 59.230957, -4.22451); + var expectedMax = new Point3(77.622297, 78.520011, 3.812853); // Act var bBox = new BoundingBox(BoundingBoxCollection.BoundingBox3D(), orientedPlane); @@ -98,7 +98,7 @@ public void It_Returns_BooleanUnion_Between_Two_BoundingBoxes() // Arrange var pt1 = new Point3(5d, 5d, 0); var pt2 = new Point3(-15d, -13d, -5); - var pts = new List {pt1, pt2}; + var pts = new List { pt1, pt2 }; var pMax = new Point3(10, 10, 0); var bBox1 = new BoundingBox(BoundingBoxCollection.BoundingBox2D()); var bBox2 = new BoundingBox(pts); @@ -136,7 +136,7 @@ public void Intersect_Returns_BBox_As_Intersection_Of_Two_BBoxes() // Arrange var pt1 = new Point3(5d, 5d, 0); var pt2 = new Point3(15d, 15d, 0); - var pts2 = new List {pt1, pt2}; + var pts2 = new List { pt1, pt2 }; var bBox1 = new BoundingBox(BoundingBoxCollection.BoundingBox2D()); var bBox2 = new BoundingBox(pts2); @@ -194,7 +194,7 @@ public void Union_Returns_ValidBoundingBox_If_Other_IsNotValid() public void It_Returns_A_BoundingBox_In_Ascending_Way() { // Arrange - var bBox = new BoundingBox(new Point3(15,15,0), new Point3(5,0,0)); + var bBox = new BoundingBox(new Point3(15, 15, 0), new Point3(5, 0, 0)); // Act var bBoxMadeValid = bBox.MakeItValid(); diff --git a/src/GShark.Test.XUnit/Geometry/CircleTests.cs b/src/GShark.Test.XUnit/Geometry/CircleTests.cs index f9548741..bb142722 100644 --- a/src/GShark.Test.XUnit/Geometry/CircleTests.cs +++ b/src/GShark.Test.XUnit/Geometry/CircleTests.cs @@ -1,8 +1,7 @@ -using System.Collections.Generic; -using System.Linq; -using FluentAssertions; +using FluentAssertions; using GShark.Core; using GShark.Geometry; +using System.Collections.Generic; using Xunit; using Xunit.Abstractions; @@ -98,7 +97,7 @@ public void It_Returns_The_Circumference_Of_A_Plane() public void It_Returns_The_Point_On_The_Circle_At_The_Give_Parameter_T(double t, double[] pts) { // Arrange - Point3 expectedPt = new Point3(pts[0],pts[1],pts[2]); + Point3 expectedPt = new Point3(pts[0], pts[1], pts[2]); Circle circle = _circle2D; // Act diff --git a/src/GShark.Test.XUnit/Geometry/ConvexHullTests.cs b/src/GShark.Test.XUnit/Geometry/ConvexHullTests.cs index 0d9bf571..93a90305 100644 --- a/src/GShark.Test.XUnit/Geometry/ConvexHullTests.cs +++ b/src/GShark.Test.XUnit/Geometry/ConvexHullTests.cs @@ -1,7 +1,7 @@ -using GShark.Geometry; +using FluentAssertions; +using GShark.Geometry; using System.Collections.Generic; using System.Linq; -using FluentAssertions; using Xunit; using Xunit.Abstractions; @@ -10,12 +10,12 @@ namespace GShark.Test.XUnit.Geometry public class ConvexHullTests { private readonly ITestOutputHelper _testOutput; - + public ConvexHullTests(ITestOutputHelper testOutput) { _testOutput = testOutput; } - + [Fact] public void It_Generates_A_Convex_Hull_For_A_3d_Set_Of_Points() { @@ -52,7 +52,7 @@ public void It_Generates_A_Convex_Hull_For_A_3d_Set_Of_Points() //Act ConvexHull hull = new ConvexHull(); - hull.GenerateHull(pointSet,true, ref vertices, ref triangles, ref normals); + hull.GenerateHull(pointSet, true, ref vertices, ref triangles, ref normals); //Assert vertices.ForEach(x => _testOutput.WriteLine(x.ToString())); diff --git a/src/GShark.Test.XUnit/Geometry/NurbsCurveTests.cs b/src/GShark.Test.XUnit/Geometry/NurbsCurveTests.cs index c26e2f8c..a60cb3eb 100644 --- a/src/GShark.Test.XUnit/Geometry/NurbsCurveTests.cs +++ b/src/GShark.Test.XUnit/Geometry/NurbsCurveTests.cs @@ -2,10 +2,8 @@ using GShark.Core; using GShark.Geometry; using GShark.Test.XUnit.Data; -using System; using System.Collections.Generic; using System.Linq; -using GShark.ExtendedMethods; using Xunit; using Xunit.Abstractions; @@ -56,8 +54,8 @@ public void It_Returns_A_Closed_NurbsCurve() new Point3 (5,5,5), new Point3 (0,5,0) }; - Point3 expectedPt00 = new Point3 ( 3.25, 3.28125, 1.875); - Point3 expectedPt01 = new Point3 ( 4.75, 3.75, 3.75 ); + Point3 expectedPt00 = new Point3(3.25, 3.28125, 1.875); + Point3 expectedPt01 = new Point3(4.75, 3.75, 3.75); // Act NurbsCurve nurbsCurve = new NurbsCurve(controlPts, degree).Close(); @@ -167,8 +165,8 @@ public void It_Returns_The_Bounding_Box_Of_A_3D_Nurbs_Curve() public void It_Returns_The_Bounding_Box_Of_A_Periodic_Curve() { // Arrange - Point3 expectedPtMin = new Point3 ( 0, 0.208333, 0.208333 ); - Point3 expectedPtMax = new Point3 ( 4.354648, 5, 3.333333 ); + Point3 expectedPtMin = new Point3(0, 0.208333, 0.208333); + Point3 expectedPtMax = new Point3(4.354648, 5, 3.333333); // Act BoundingBox bBox = NurbsCurveCollection.PeriodicClosedNurbsCurve().BoundingBox; diff --git a/src/GShark.Test.XUnit/Geometry/PlaneTests.cs b/src/GShark.Test.XUnit/Geometry/PlaneTests.cs index 54c63535..b3591054 100644 --- a/src/GShark.Test.XUnit/Geometry/PlaneTests.cs +++ b/src/GShark.Test.XUnit/Geometry/PlaneTests.cs @@ -17,8 +17,8 @@ public PlaneTests(ITestOutputHelper testOutput) _testOutput = testOutput; } - public static Plane BasePlane => new Plane(new Point3(5, 0, 0 ), new Point3(10, 15, 0)); - public static Plane BasePlaneByPoints => new Plane(new Point3( 20, 20, 0 ), new Point3( 5, 5, 0), new Point3( -5, 10, 0)); + public static Plane BasePlane => new Plane(new Point3(5, 0, 0), new Point3(10, 15, 0)); + public static Plane BasePlaneByPoints => new Plane(new Point3(20, 20, 0), new Point3(5, 5, 0), new Point3(-5, 10, 0)); [Fact] public void It_Initializes_A_Plane() @@ -43,7 +43,7 @@ public void It_Checks_If_Plane_Is_Valid() //Arrange var validPlane = new Plane(new Point3(5, 5, 5), new Vector3(10, 0, 0), new Vector3(0, 5, 0)); var invalidPlane = new Plane(validPlane); - invalidPlane.XAxis = new Vector3(5,5,5); + invalidPlane.XAxis = new Vector3(5, 5, 5); //Assert validPlane.IsValid.Should().BeTrue(); @@ -118,14 +118,14 @@ public void It_Returns_A_Flipped_Plane() public void It_Returns_A_Transformed_Plane() { // Arrange - var pt1 = new Point3( 20, 20, 0); - var pt2 = new Point3( 5, 5, 0); - var pt3 = new Point3( -5, 10, 0); + var pt1 = new Point3(20, 20, 0); + var pt2 = new Point3(5, 5, 0); + var pt3 = new Point3(-5, 10, 0); Plane plane = new Plane(pt1, pt2, pt3); - Transform translation = Transform.Translation(new Point3( 10, 15, 0)); + Transform translation = Transform.Translation(new Point3(10, 15, 0)); Transform rotation = Transform.Rotation(GeoSharkMath.ToRadians(30), new Point3(0, 0, 0)); var expectedOrigin = new Point3(17.320508, 42.320508, 0); - var expectedZAxis = new Vector3( 0, 0, -1); + var expectedZAxis = new Vector3(0, 0, -1); // Act Transform combinedTransformations = translation.Combine(rotation); @@ -146,9 +146,9 @@ public void It_Returns_A_Rotated_Plane() Plane rotatedPlane = plane.Rotate(GeoSharkMath.ToRadians(30)); // Assert - rotatedPlane.XAxis.EpsilonEquals(new Vector3( -0.965926, -0.258819, 0), GeoSharkMath.MaxTolerance).Should().BeTrue(); - rotatedPlane.YAxis.EpsilonEquals(new Vector3( -0.258819, 0.965926, 0), GeoSharkMath.MaxTolerance).Should().BeTrue(); - rotatedPlane.ZAxis.EpsilonEquals(new Vector3( 0, 0, -1), GeoSharkMath.MaxTolerance).Should().BeTrue(); + rotatedPlane.XAxis.EpsilonEquals(new Vector3(-0.965926, -0.258819, 0), GeoSharkMath.MaxTolerance).Should().BeTrue(); + rotatedPlane.YAxis.EpsilonEquals(new Vector3(-0.258819, 0.965926, 0), GeoSharkMath.MaxTolerance).Should().BeTrue(); + rotatedPlane.ZAxis.EpsilonEquals(new Vector3(0, 0, -1), GeoSharkMath.MaxTolerance).Should().BeTrue(); } [Fact] @@ -162,8 +162,8 @@ public void It_Returns_A_Plane_Aligned_To_A_Given_Vector() // Assert alignedPlane.XAxis.EpsilonEquals(Vector3.XAxis, GeoSharkMath.MaxTolerance).Should().BeTrue(); - alignedPlane.YAxis.EpsilonEquals(new Vector3( 0.0, -1.0, 0.0), GeoSharkMath.MaxTolerance).Should().BeTrue(); - alignedPlane.ZAxis.EpsilonEquals(new Vector3( 0.0, 0.0, -1.0), GeoSharkMath.MaxTolerance).Should().BeTrue(); + alignedPlane.YAxis.EpsilonEquals(new Vector3(0.0, -1.0, 0.0), GeoSharkMath.MaxTolerance).Should().BeTrue(); + alignedPlane.ZAxis.EpsilonEquals(new Vector3(0.0, 0.0, -1.0), GeoSharkMath.MaxTolerance).Should().BeTrue(); } [Fact] @@ -171,7 +171,7 @@ public void It_Returns_A_Plane_With_A_New_Origin() { // Arrange Plane plane = BasePlaneByPoints; - var newOrigin = new Point3( 50, 60, 5); + var newOrigin = new Point3(50, 60, 5); // Act Plane translatedPlane = plane.SetOrigin(newOrigin); @@ -192,7 +192,7 @@ public void It_Returns_A_Plane_Which_Fits_Through_A_Set_Of_Points() new (78.805261, 45.16886, -4.22451), new (74.264416, 36.39316, -1.884313) }; var originCheck = new Point3(86.266409, 29.701102, -0.227864); - var normalCheck = new Point3( 0.008012, 0.253783, 0.967228); + var normalCheck = new Point3(0.008012, 0.253783, 0.967228); // Act Plane fitPlane = Plane.FitPlane(pts, out _); diff --git a/src/GShark.Test.XUnit/Geometry/Point4Tests.cs b/src/GShark.Test.XUnit/Geometry/Point4Tests.cs index f02aed27..22784bc3 100644 --- a/src/GShark.Test.XUnit/Geometry/Point4Tests.cs +++ b/src/GShark.Test.XUnit/Geometry/Point4Tests.cs @@ -1,6 +1,9 @@ using FluentAssertions; using GShark.Core; using GShark.Geometry; +using System; +using System.Collections.Generic; +using System.Linq; using Xunit; using Xunit.Abstractions; @@ -15,6 +18,95 @@ public Point4Tests(ITestOutputHelper testOutput) _testOutput = testOutput; } + public static IEnumerable ControlPoints1D => new List + { + new object[] + { + new List {0.5, 0.5, 0.5}, + new List + { + new (0.0, 0.0, 0.0, 0.5), + new (1.25, -1.25, 0.0, 0.5), + new (2.5, 0.0, 0.0, 0.5) + } + }, + + new object[] + { + new List {0.5}, + new List + { + new (0.0, 0.0, 0.0, 0.5), + new (2.5, -2.5, 0.0, 1.0), + new (5.0, 0.0, 0.0, 1.0) + } + }, + }; + public static IEnumerable ControlPoints2D => new List + { + new object[] + { + new List> { + new() { 0.5, 0.5, 0.5 }, + new() { 0.5, 0.5, 0.5 }, + }, + new List>() + { + new() + { + new (0.0, 0.0, 0.0, 0.5), + new (1.25, -1.25, 0.0, 0.5), + new (2.5, 0.0, 0.0, 0.5) + }, + new() + { + new (0.0, 0.0, 0.0, 0.5), + new (1.25, -1.25, 0.0, 0.5), + new (2.5, 0.0, 0.0, 0.5) + } + } + }, + new object[] + { + new List> { new() { 0.5 }, new() { 0.5 }}, + new List> + { + new() + { + new (0.0, 0.0, 0.0, 0.5), + new (2.5, -2.5, 0.0, 1.0), + new (5.0, 0.0, 0.0, 1.0) + }, + new() + { + new (0.0, 0.0, 0.0, 0.5), + new (2.5, -2.5, 0.0, 1.0), + new (5.0, 0.0, 0.0, 1.0) + } + } + }, + + new object[] + { + null, + new List> + { + new() + { + new (0.0, 0.0, 0.0, 1.0), + new (2.5, -2.5, 0.0, 1.0), + new (5.0, 0.0, 0.0, 1.0) + }, + new() + { + new (0.0, 0.0, 0.0, 1.0), + new (2.5, -2.5, 0.0, 1.0), + new (5.0, 0.0, 0.0, 1.0) + } + } + } + }; + [Fact] public void It_Returns_A_Transformed_Point() { @@ -40,5 +132,325 @@ public void It_Returns_True_If_Two_Points_Are_Equal() // Assert (p1 == p2).Should().BeTrue(); } + + [Theory] + [MemberData(nameof(ControlPoints1D))] + public void It_Returns_A_New_Set_Of_Control_Points(List weights, List expectedControlPoints) + { + // Arrange + List controlPts = new List + { + new (0.0, 0.0, 0), + new (2.5, -2.5, 0), + new (5.0, 0.0, 0) + }; + + // Act + List newControlPts = Point4.PointsHomogeniser(controlPts, weights); + + // Assert + newControlPts.SequenceEqual(expectedControlPoints).Should().BeTrue(); + } + + [Fact] + public void PointsHomogeniser_Throws_An_Exception_If_The_Weight_Collection_Is_Bigger_Than_ControlPts() + { + // Arrange + List controlPts = new List(); + List weights = new List { 1.0, 1.5, 1.0 }; + + // Act + Func resultFunction = () => Point4.PointsHomogeniser(controlPts, weights); + + // Assert + resultFunction.Should().Throw(); + } + + [Fact] + public void It_Returns_A_New_Set_Of_Control_Points_By_A_Given_Weight_Value() + { + // Arrange + List pts = new List + { + new (0.0, 0.0, 0), + new (2.5, -2.5, 0), + new (5.0, 0.0, 0) + }; + List expectedControlPoints = new List + { + new (0.0, 0.0, 0.0, 1.0), + new (2.5, -2.5, 0.0, 1.0), + new (5.0, 0.0, 0.0, 1.0) + }; + + // Act + List controlPts = Point4.PointsHomogeniser(pts, 1.0); + + // Assert + controlPts.SequenceEqual(expectedControlPoints).Should().BeTrue(); + } + + [Theory] + [MemberData(nameof(ControlPoints2D))] + public void It_Returns_A_Set_Of_Control_Points(List> weights, List> expectedSetOfCtrlPts) + { + // Arrange + List> setOfPts = new List>() + { + new() + { + new (0.0, 0.0, 0), + new (2.5, -2.5, 0), + new (5.0, 0.0, 0) + }, + new() + { + new (0.0, 0.0, 0), + new (2.5, -2.5, 0), + new (5.0, 0.0, 0) + } + }; + + // Act + List> setOfCtrlPts = Point4.PointsHomogeniser2d(setOfPts, weights); + + // Assert + for (int i = 0; i < setOfCtrlPts.Count; i++) + { + List ctrlPts = setOfCtrlPts[i]; + List expectedCtrlPts = expectedSetOfCtrlPts[i]; + + for (int j = 0; j < ctrlPts.Count; j++) + { + Point4 ctrlPt = ctrlPts[j]; + Point4 expectedPt = expectedCtrlPts[j]; + ctrlPt.Equals(expectedPt).Should().BeTrue(); + } + } + } + + [Fact] + public void It_Returns_A_Set_Of_Weights() + { + // Arrange + List ctrlPts = new List + { + new (0.0, 0.0, 0.0, 0.5), + new (1.25, -1.25, 0.0, 0.5), + new (2.5, 0.0, 0.0, 0.5) + }; + List expectedWeights = new List { 0.5, 0.5, 0.5 }; + + // Act + List weight1d = Point4.GetWeights(ctrlPts); + + // Assert + weight1d.SequenceEqual(expectedWeights).Should().BeTrue(); + } + + [Fact] + public void It_Returns_A_Two_Dimensional_Set_Of_Weights() + { + // Arrange + List> ctrlPts = new List> + { + new() + { + new (0.0, 0.0, 0.0, 0.5), + new (1.25, -1.25, 0.0, 0.5), + new (2.5, 0.0, 0.0, 0.5) + }, + new() + { + new (0.0, 0.0, 0.0, 0.5), + new (1.25, -1.25, 0.0, 0.5), + new (2.5, 0.0, 0.0, 0.5) + } + }; + + List> expectedWeights = new List> + { + new() {0.5, 0.5, 0.5}, + new() {0.5, 0.5, 0.5} + }; + + // Act + List> weight2d = Point4.GetWeights2d(ctrlPts); + + // Assert + for (int i = 0; i < ctrlPts.Count; i++) + { + var expectedWts = expectedWeights[i]; + var weights = weight2d[i]; + + for (int j = 0; j < expectedWts.Count; j++) + { + var expectedWt = expectedWts[j]; + var weight = weights[j]; + weight.Equals(expectedWt).Should().BeTrue(); + } + } + } + + [Fact] + public void It_Returns_A_Dehomogenized_Point() + { + // Arrange + Point4 ctrlPt = new Point4(1.25, -1.25, 0.0, 0.5); + Point3 expectedPt = new Point3(2.5, -2.5, 0); + + // Act + Point3 pt = Point4.PointDehomogenizer(ctrlPt); + + // Assert + pt.Equals(expectedPt).Should().BeTrue(); + } + + [Fact] + public void It_Returns_A_Set_Of_Dehomogenized_Points() + { + // Arrange + List ctrlPts = new List + { + new (0.0, 0.0, 0.0, 0.5), + new (1.25, -1.25, 0.0, 0.5), + new (2.5, 0.0, 0.0, 0.5) + }; + + List expectedPts = new List + { + new (0.0, 0.0, 0), + new (2.5, -2.5, 0), + new (5.0, 0.0, 0) + }; + + // Act + List pts = Point4.PointDehomogenizer1d(ctrlPts); + + // Assert + pts.SequenceEqual(expectedPts).Should().BeTrue(); + } + + [Fact] + public void It_Returns_A_Two_Dimensional_Set_Of_Dehomogenized_Points() + { + // Arrange + List> ctrlPts = new List> + { + new() + { + new(0.0, 0.0, 0.0, 0.5), + new(1.25, -1.25, 0.0, 0.5), + new(2.5, 0.0, 0.0, 0.5) + }, + new() + { + new(0.0, 0.0, 0.0, 0.5), + new(1.25, -1.25, 0.0, 0.5), + new(2.5, 0.0, 0.0, 0.5) + } + }; + + List> expectedPts = new List> + { + new() + { + new (0.0, 0.0, 0), + new (2.5, -2.5, 0), + new (5.0, 0.0, 0) + }, + new() + { + new (0.0, 0.0, 0), + new (2.5, -2.5, 0), + new (5.0, 0.0, 0) + } + }; + + // Act + var pts = Point4.PointDehomogenizer2d(ctrlPts); + + // Arrange + pts.Should().BeEquivalentTo(expectedPts); + } + + [Fact] + public void It_Returns_A_Rationalized_Set_Of_Points() + { + // Arrange + List ctrlPts = new List + { + new (0.0, 0.0, 0.0, 0.5), + new (2.5, -2.5, 0.0, 1.0), + new (5.0, 0.0, 0.0, 1.0) + }; + + List expectedPts = new List + { + new (0.0, 0.0, 0.0), + new (2.5, -2.5, 0.0), + new (5.0, 0.0, 0.0) + }; + + // Act + List rationalPoints = Point4.RationalPoints(ctrlPts); + + // Assert + rationalPoints.SequenceEqual(expectedPts).Should().BeTrue(); + } + + [Fact] + public void It_Returns_A_Rationalized_Two_Dimensional_Set_Of_Points() + { + // Arrange + List> ctrlPts = new List> + { + new() + { + new (0.0, 0.0, 0.0, 0.5), + new (2.5, -2.5, 0.0, 1.0), + new (5.0, 0.0, 0.0, 1.0) + }, + new() + { + new (0.0, 0.0, 0.0, 0.5), + new (2.5, -2.5, 0.0, 1.0), + new (5.0, 0.0, 0.0, 1.0) + } + }; + + List> expectedPoints = new List> + { + new() + { + new (0.0, 0.0, 0.0), + new (2.5, -2.5, 0.0), + new (5.0, 0.0, 0.0) + }, + new() + { + new (0.0, 0.0, 0.0), + new (2.5, -2.5, 0.0), + new (5.0, 0.0, 0.0) + } + }; + + // Act + List> rationalPoints = Point4.Rational2d(ctrlPts); + + // Assert + for (int i = 0; i < ctrlPts.Count; i++) + { + var expectedPts = expectedPoints[i]; + var rationalPts = rationalPoints[i]; + + for (int j = 0; j < expectedPoints.Count; j++) + { + var expectedPt = expectedPts[j]; + var rationalPt = rationalPts[j]; + rationalPt.Equals(expectedPt).Should().BeTrue(); + } + } + } } } diff --git a/src/GShark.Test.XUnit/Geometry/PolygonTests.cs b/src/GShark.Test.XUnit/Geometry/PolygonTests.cs index 32884908..27df3ee7 100644 --- a/src/GShark.Test.XUnit/Geometry/PolygonTests.cs +++ b/src/GShark.Test.XUnit/Geometry/PolygonTests.cs @@ -1,8 +1,8 @@ using FluentAssertions; using GShark.Core; using GShark.Geometry; -using System; using GShark.Geometry.Interfaces; +using System; using Xunit; using Xunit.Abstractions; @@ -18,10 +18,10 @@ public PolygonTests(ITestOutputHelper testOutput) public static Point3[] Planar2D => new[] { - new Point3(1d, 1d, 0d), + new Point3(1d, 1d, 0d), new Point3(10d, 1d, 0d), - new Point3(2d, 10d, 0d), - new Point3(1d, 10d, 0d), + new Point3(2d, 10d, 0d), + new Point3(1d, 10d, 0d), new Point3(1d, 1d, 0) }; @@ -104,8 +104,8 @@ public void It_Returns_The_Centroid_By_Vertices() Polygon poly2D = new Polygon(Planar2D); Polygon poly3D = new Polygon(Planar3D); - Point3 centroid2DExpected = new Point3( 3.5, 5.5, 0.0); - Point3 centroid3DExpected = new Point3( 86.266409, 29.701102, -0.227864); + Point3 centroid2DExpected = new Point3(3.5, 5.5, 0.0); + Point3 centroid3DExpected = new Point3(86.266409, 29.701102, -0.227864); // Act Point3 poly2DCentroid = poly2D.CentroidByVertices; @@ -123,8 +123,8 @@ public void It_Returns_The_Centroid_By_Area() Polygon poly2D = new Polygon(Planar2D); Polygon poly3D = new Polygon(Planar3D); - Point3 centroid2DExpected = new Point3( 4.033333, 4.3, 0); - Point3 centroid3DExpected = new Point3( 87.620479, 29.285305, -0.129984); + Point3 centroid2DExpected = new Point3(4.033333, 4.3, 0); + Point3 centroid3DExpected = new Point3(87.620479, 29.285305, -0.129984); // Act Point3 poly2DCentroid = poly2D.CentroidByArea; diff --git a/src/GShark.Test.XUnit/Geometry/PolylineTests.cs b/src/GShark.Test.XUnit/Geometry/PolylineTests.cs index 80e40345..ab22dd2f 100644 --- a/src/GShark.Test.XUnit/Geometry/PolylineTests.cs +++ b/src/GShark.Test.XUnit/Geometry/PolylineTests.cs @@ -48,7 +48,7 @@ public void It_Returns_A_Polyline() public void Polyline_Throws_An_Exception_If_Vertex_Count_Is_Less_Than_Two() { // Arrange - Point3[] pts = new Point3[]{ new Point3(5, 0, 0) }; + Point3[] pts = new Point3[] { new Point3(5, 0, 0) }; // Act Func func = () => new Polyline(pts); diff --git a/src/GShark.Test.XUnit/Geometry/RayTests.cs b/src/GShark.Test.XUnit/Geometry/RayTests.cs index 2ab85adb..84ed2291 100644 --- a/src/GShark.Test.XUnit/Geometry/RayTests.cs +++ b/src/GShark.Test.XUnit/Geometry/RayTests.cs @@ -1,7 +1,6 @@ using FluentAssertions; using GShark.Geometry; using System.Collections.Generic; -using verb.core; using Xunit; using Ray = GShark.Geometry.Ray; @@ -21,7 +20,7 @@ public class RayTests public void It_Returns_An_Point_Along_The_Ray(Vector expected, double amplitude) { // Arrange - Ray ray = new Ray(new Point3( -10, 5, 10), new Vector3(20, 10, -5)); + Ray ray = new Ray(new Point3(-10, 5, 10), new Vector3(20, 10, -5)); // Act Vector pointAlongTheRay = ray.OnRay(amplitude); @@ -34,9 +33,9 @@ public void It_Returns_An_Point_Along_The_Ray(Vector expected, double amplitude) public void It_Returns_The_Closest_Point() { // Arrange - Ray ray = new Ray(new Point3( 0, 0, 0), new Vector3(30, 45, 0)); - var pt = new Point3( 10, 20, 0); - var expectedPt = new Point3( 12.30769230769231, 18.461538461538463, 0); + Ray ray = new Ray(new Point3(0, 0, 0), new Vector3(30, 45, 0)); + var pt = new Point3(10, 20, 0); + var expectedPt = new Point3(12.30769230769231, 18.461538461538463, 0); // Act var closestPt = ray.ClosestPoint(pt); @@ -49,8 +48,8 @@ public void It_Returns_The_Closest_Point() public void It_Returns_The_Distance_To_A_Point() { // Arrange - Ray ray = new Ray(new Point3( 0, 0, 0), new Vector3(30, 45, 0)); - var pt = new Point3( 10, 20, 0); + Ray ray = new Ray(new Point3(0, 0, 0), new Vector3(30, 45, 0)); + var pt = new Point3(10, 20, 0); const double distanceExpected = 2.7735009811261464; // Act @@ -64,7 +63,7 @@ public void It_Returns_The_Distance_To_A_Point() public void It_Returns_A_Point_At_The_T_Parameter() { // Arrange - Ray ray = new Ray(new Point3( 0, 0, 0), new Vector3( -7, 10, -5)); + Ray ray = new Ray(new Point3(0, 0, 0), new Vector3(-7, 10, -5)); var expectedPt = new Point3(-8.75, 12.5, -6.25); // Act diff --git a/src/GShark.Test.XUnit/Operation/DivideTests.cs b/src/GShark.Test.XUnit/Operation/DivideTests.cs index 52771cff..62e69655 100644 --- a/src/GShark.Test.XUnit/Operation/DivideTests.cs +++ b/src/GShark.Test.XUnit/Operation/DivideTests.cs @@ -1,12 +1,12 @@ using FluentAssertions; using GShark.Core; +using GShark.ExtendedMethods; using GShark.Geometry; using GShark.Geometry.Interfaces; using GShark.Operation; using GShark.Test.XUnit.Data; using System.Collections.Generic; using System.Linq; -using GShark.ExtendedMethods; using Xunit; using Xunit.Abstractions; @@ -230,7 +230,7 @@ public void It_Calculates_Rotation_Minimized_Frames_Along_Curve() { _testOutput.WriteLine(perpFrame.ToString()); } - + //Assert for (var i = 0; i < perpFrames.Count; i++) { diff --git a/src/GShark.Test.XUnit/Operation/FittingTests.cs b/src/GShark.Test.XUnit/Operation/FittingTests.cs index 88bfcb9d..c82ed8ed 100644 --- a/src/GShark.Test.XUnit/Operation/FittingTests.cs +++ b/src/GShark.Test.XUnit/Operation/FittingTests.cs @@ -19,11 +19,11 @@ public FittingTests(ITestOutputHelper testOutput) public static List pts => new() { - new (0, 0, 0), - new (3, 4, 0), - new (-1, 4, 0), - new (-4, 0, 0), - new (-4, -3, 0), + new(0, 0, 0), + new(3, 4, 0), + new(-1, 4, 0), + new(-4, 0, 0), + new(-4, -3, 0), }; [Theory] @@ -55,7 +55,7 @@ public void Interpolates_With_End_And_Start_Tangent() var newPts = new List(pts); newPts.Insert(1, v1); - newPts.Insert(newPts.Count-1, v2); + newPts.Insert(newPts.Count - 1, v2); // Act NurbsCurve crv = Fitting.InterpolatedCurve(pts, 2, v1, v2); @@ -85,9 +85,9 @@ public void Returns_A_Sets_Of_Interpolated_Beziers_From_A_Collection_Of_Points() crvs.Count.Should().Be(4); for (int i = 0; i < crvs.Count - 1; i++) { - bool areCollinear = Trigonometry.ArePointsCollinear(crvs[i].LocationPoints[2], crvs[i].LocationPoints[3], - crvs[i + 1].LocationPoints[1]); - areCollinear.Should().BeTrue(); + bool areCollinear = Trigonometry.ArePointsCollinear(crvs[i].LocationPoints[2], crvs[i].LocationPoints[3], + crvs[i + 1].LocationPoints[1]); + areCollinear.Should().BeTrue(); } } diff --git a/src/GShark.Test.XUnit/Operation/IntersectionTests.cs b/src/GShark.Test.XUnit/Operation/IntersectionTests.cs index 2bb7e37f..9fe4801a 100644 --- a/src/GShark.Test.XUnit/Operation/IntersectionTests.cs +++ b/src/GShark.Test.XUnit/Operation/IntersectionTests.cs @@ -2,9 +2,9 @@ using GShark.Core; using GShark.Core.IntersectionResults; using GShark.Geometry; +using GShark.Geometry.Interfaces; using GShark.Operation; using System.Collections.Generic; -using GShark.Geometry.Interfaces; using Xunit; using Xunit.Abstractions; @@ -33,7 +33,7 @@ public void It_Returns_The_Intersection_Between_Two_Planes() // Assert intersection0.Should().BeTrue(); lineIntersect0.Start.Should().BeEquivalentTo(new Point3(10, 0, 0)); - lineIntersect0.Direction.Should().BeEquivalentTo(new Vector3( 0, 1, 0)); + lineIntersect0.Direction.Should().BeEquivalentTo(new Vector3(0, 1, 0)); intersection1.Should().BeTrue(); lineIntersect1.Start.Should().BeEquivalentTo(new Point3(10, -10, 0)); @@ -45,7 +45,7 @@ public void PlanePlane_Is_False_If_Planes_Are_Parallel() { // Arrange Plane pl0 = Plane.PlaneXY; - Plane pl1 = Plane.PlaneXY.SetOrigin(new Point3( 10, 10, 5)); + Plane pl1 = Plane.PlaneXY.SetOrigin(new Point3(10, 10, 5)); // Act bool intersection = Intersect.PlanePlane(pl0, pl1, out _); @@ -69,8 +69,8 @@ public void It_Returns_The_Intersection_Point_Between_A_Segment_And_A_Plane() // Assert intersection0.Should().BeTrue(); intersection1.Should().BeTrue(); - pt0.Equals(new Point3( 10, 10, 5)).Should().BeTrue(); - pt1.Equals(new Point3( 10, 10, 20)).Should().BeTrue(); + pt0.Equals(new Point3(10, 10, 5)).Should().BeTrue(); + pt1.Equals(new Point3(10, 10, 20)).Should().BeTrue(); } [Theory] @@ -80,7 +80,7 @@ public void It_Returns_The_Intersection_Point_Between_A_Segment_And_A_Plane() public void LinePlane_Is_False_If_Line_Is_Parallel(double[] startPt, double[] endPt) { // Arrange - Plane pl = Plane.PlaneYZ.SetOrigin(new Point3( 10, 20, 5)); + Plane pl = Plane.PlaneYZ.SetOrigin(new Point3(10, 20, 5)); Line ln = new Line(new Point3(startPt[0], startPt[1], startPt[2]), new Point3(endPt[0], endPt[1], endPt[2])); // Act @@ -145,7 +145,7 @@ public void It_Returns_The_Intersection_Points_Between_A_Polyline_And_A_Plane() }; Polyline poly = new Polyline(pts); - Plane pl = Plane.PlaneYZ.SetOrigin(new Point3( 10, 20, 5)); + Plane pl = Plane.PlaneYZ.SetOrigin(new Point3(10, 20, 5)); // Act var intersections = Intersect.PolylinePlane(poly, pl); @@ -162,7 +162,7 @@ public void It_Returns_The_Intersection_Points_Between_A_Polyline_And_A_Plane() public void It_Returns_The_Intersection_Points_Between_A_Circle_And_A_Line() { // Arrange - Plane pl = Plane.PlaneYZ.SetOrigin(new Point3( 10, 20, 5)); + Plane pl = Plane.PlaneYZ.SetOrigin(new Point3(10, 20, 5)); Circle cl = new Circle(pl, 20); Line ln0 = new Line(new Point3(10, 29.769674, 17.028815), new Point3(10, 37.594559, 24.680781)); Line ln1 = new Line(new Point3(10, 40, 25), new Point3(10, 40, 17)); @@ -173,7 +173,7 @@ public void It_Returns_The_Intersection_Points_Between_A_Circle_And_A_Line() new Point3( 10, 4.51962, -7.663248) }; - Point3 intersectionCheck = new Point3( 10, 40, 5); + Point3 intersectionCheck = new Point3(10, 40, 5); // Act _ = Intersect.LineCircle(cl, ln0, out Point3[] pts0); @@ -192,9 +192,9 @@ public void It_Returns_The_Intersection_Points_Between_A_Circle_And_A_Line() public void CircleLine_Intersection_Returns_False_If_No_Intersections_Are_Computed() { // Arrange - Plane pl = Plane.PlaneYZ.SetOrigin(new Point3( 10, 20, 5)); + Plane pl = Plane.PlaneYZ.SetOrigin(new Point3(10, 20, 5)); Circle cl = new Circle(pl, 20); - Line ln = new Line(new Point3( -15, 45, 17), new Point3(15, 45, 25)); + Line ln = new Line(new Point3(-15, 45, 17), new Point3(15, 45, 25)); // Act bool intersection = Intersect.LineCircle(cl, ln, out _); @@ -208,8 +208,8 @@ public void PlaneCircle_Is_False_If_Planes_Are_Parallel_Or_Intersection_Plane_Mi { // Arrange Plane pl0 = Plane.PlaneYZ; - Plane pl1 = Plane.PlaneYZ.SetOrigin(new Point3( 10, 20, 5)); - Plane pl2 = Plane.PlaneZX.SetOrigin(new Point3( 10, -10, -5)); + Plane pl1 = Plane.PlaneYZ.SetOrigin(new Point3(10, 20, 5)); + Plane pl2 = Plane.PlaneZX.SetOrigin(new Point3(10, -10, -5)); Circle cl = new Circle(pl1, 20); // Act @@ -225,9 +225,9 @@ public void PlaneCircle_Is_False_If_Planes_Are_Parallel_Or_Intersection_Plane_Mi public void It_Returns_The_Intersection_Points_Between_A_Plane_And_A_Circle() { // Arrange - Plane pl = Plane.PlaneYZ.SetOrigin(new Point3( 10, 20, 5)); + Plane pl = Plane.PlaneYZ.SetOrigin(new Point3(10, 20, 5)); Circle cl = new Circle(pl, 20); - Plane plSec = new Plane(new Point3( 10, 10, 10), new Point3(10, 20, 25)); + Plane plSec = new Plane(new Point3(10, 10, 10), new Point3(10, 20, 25)); Point3[] intersectionChecks = new[] { @@ -250,10 +250,10 @@ public void It_Returns_The_Intersection_Between_Two_Planar_Lines() { // Arrange int crvDegree0 = 1; - var crvPts0 = new List {new Point3(0, 0, 0), new Point3(2, 0, 0)}; + var crvPts0 = new List { new Point3(0, 0, 0), new Point3(2, 0, 0) }; int crvDegree1 = 1; - var crvPts1 = new List { new Point3(0.5, 0.5, 0), new Point3(0.5, -1.5, 0)}; + var crvPts1 = new List { new Point3(0.5, 0.5, 0), new Point3(0.5, -1.5, 0) }; NurbsCurve crv0 = new NurbsCurve(crvPts0, crvDegree0); NurbsCurve crv1 = new NurbsCurve(crvPts1, crvDegree1); @@ -271,14 +271,14 @@ public void It_Returns_The_Intersection_Between_Two_Planar_Lines() public void It_Returns_The_Intersection_Between_A_Curve_And_Line_Planar() { // Arrange - var p1 = new Point3( 0.0, 0.0, 0.0); - var p2 = new Point3( 2.0, 0.0, 0.0); + var p1 = new Point3(0.0, 0.0, 0.0); + var p2 = new Point3(2.0, 0.0, 0.0); Line ln = new Line(p1, p2); int crvDegree1 = 2; - var crvPts1 = new List { new Point3( 0.5, 0.5, 0), new Point3(0.7, 0, 0), new Point3(0.5, -1.5, 0)}; + var crvPts1 = new List { new Point3(0.5, 0.5, 0), new Point3(0.7, 0, 0), new Point3(0.5, -1.5, 0) }; ICurve crv = new NurbsCurve(crvPts1, crvDegree1); - + // Act List intersection = Intersect.CurveLine(crv, ln); @@ -293,10 +293,10 @@ public void It_Returns_The_Intersection_Between_A_Planar_Curves() { // Arrange int crvDegree0 = 2; - var crvPts0 = new List { new Point3( 0, 0, 0), new Point3(0.5, 0.1, 0), new Point3 (2, 0, 0) }; + var crvPts0 = new List { new Point3(0, 0, 0), new Point3(0.5, 0.1, 0), new Point3(2, 0, 0) }; int crvDegree1 = 2; - var crvPts1 = new List { new Point3(0.5, 0.5, 0), new Point3(0.7, 0, 0), new Point3(0.5, -1.5, 0)}; + var crvPts1 = new List { new Point3(0.5, 0.5, 0), new Point3(0.7, 0, 0), new Point3(0.5, -1.5, 0) }; NurbsCurve crv0 = new NurbsCurve(crvPts0, crvDegree0); NurbsCurve crv1 = new NurbsCurve(crvPts1, crvDegree1); @@ -383,9 +383,9 @@ public void It_Returns_The_Intersections_Between_A_Planar_Curve_And_A_Plane(doub { // Arrange int crvDegree = 2; - var crvCtrPts = new List {new Point3( 0, 0, 0), new Point3( 0.5, 0.5, 0), new Point3(2, 0, 0)}; + var crvCtrPts = new List { new Point3(0, 0, 0), new Point3(0.5, 0.5, 0), new Point3(2, 0, 0) }; NurbsCurve crv = new NurbsCurve(crvCtrPts, crvDegree); - Plane pl = Plane.PlaneYZ.SetOrigin(new Point3( xValue, 0.0, 0.0)); + Plane pl = Plane.PlaneYZ.SetOrigin(new Point3(xValue, 0.0, 0.0)); // Act List intersections = Intersect.CurvePlane(crv, pl); @@ -409,7 +409,7 @@ public void It_Returns_The_Intersections_Between_A_Curve3D_And_A_Rotated_Plane() }; NurbsCurve crv = new NurbsCurve(crvCtrPts, degree); - Transform xForm = Transform.Rotation(0.15, new Point3( 0.0, 0.0, 0.0)); + Transform xForm = Transform.Rotation(0.15, new Point3(0.0, 0.0, 0.0)); Plane pln = Plane.PlaneYZ; var testPln = pln.SetOrigin(new Point3(6, 0.0, 0.0)); var testPlnXformed = testPln.Transform(xForm); diff --git a/src/GShark.Test.XUnit/Operation/ModifyTests.cs b/src/GShark.Test.XUnit/Operation/ModifyTests.cs index 6ebbb92a..eed6458c 100644 --- a/src/GShark.Test.XUnit/Operation/ModifyTests.cs +++ b/src/GShark.Test.XUnit/Operation/ModifyTests.cs @@ -41,7 +41,7 @@ public void It_Refines_The_Curve_Knot(double val, int insertion) List pts = new List(); for (int i = 0; i <= 12 - degree - 2; i++) - pts.Add(new Point3( i, 0.0, 0.0)); + pts.Add(new Point3(i, 0.0, 0.0)); ICurve curve = new NurbsCurve(pts, degree); @@ -65,10 +65,10 @@ public void It_Decomposes_The_Curve_Of_Degree_Three_Into_Bezier_Curve_Segments() { // Arrange int degree = 3; - + List pts = new List(); for (int i = 0; i <= 12 - degree - 2; i++) - pts.Add(new Point3( i, 0.0, 0.0)); + pts.Add(new Point3(i, 0.0, 0.0)); ICurve curve = new NurbsCurve(pts, degree); diff --git a/src/GShark.Test.XUnit/Operation/OffsetTests.cs b/src/GShark.Test.XUnit/Operation/OffsetTests.cs index 607761db..87c1a690 100644 --- a/src/GShark.Test.XUnit/Operation/OffsetTests.cs +++ b/src/GShark.Test.XUnit/Operation/OffsetTests.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using FluentAssertions; +using FluentAssertions; using GShark.Core; using GShark.Geometry; using GShark.Geometry.Interfaces; diff --git a/src/GShark.Test.XUnit/Operation/TessellationTests.cs b/src/GShark.Test.XUnit/Operation/TessellationTests.cs index 30e930d2..0d6115d7 100644 --- a/src/GShark.Test.XUnit/Operation/TessellationTests.cs +++ b/src/GShark.Test.XUnit/Operation/TessellationTests.cs @@ -4,7 +4,6 @@ using GShark.Operation; using GShark.Test.XUnit.Data; using System.Collections.Generic; -using System.Linq; using Xunit; using Xunit.Abstractions; @@ -113,11 +112,11 @@ public void Return_Adaptive_Sample_Subdivision_Of_A_Line() public void Return_Adaptive_Sample_Subdivision_Of_A_Polyline() { // Arrange - var p1 = new Point3( 0, 0, 0); - var p2 = new Point3( 10, 10, 0); - var p3 = new Point3( 14, 20, 0); - var p4 = new Point3( 10, 32, 4); - var p5 = new Point3( 12, 16, 22); + var p1 = new Point3(0, 0, 0); + var p2 = new Point3(10, 10, 0); + var p3 = new Point3(14, 20, 0); + var p4 = new Point3(10, 32, 4); + var p5 = new Point3(12, 16, 22); List pts = new List { p1, p2, p3, p4, p5 }; Polyline poly = new Polyline(pts); diff --git a/src/GShark.Test.XUnit/VerbTests.cs b/src/GShark.Test.XUnit/VerbTests.cs index ec26149f..feec318a 100644 --- a/src/GShark.Test.XUnit/VerbTests.cs +++ b/src/GShark.Test.XUnit/VerbTests.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using System.Runtime.Intrinsics.Arm; -using verb.core; +using verb.core; using verb.eval; using Xunit; using Xunit.Abstractions; @@ -86,7 +80,7 @@ public void CurvesIntersections() Array pts0 = new Array(); Array pts1 = new Array(); - pts0.push(new Array(new double[] { -5,0,0 })); + pts0.push(new Array(new double[] { -5, 0, 0 })); pts0.push(new Array(new double[] { 10, 0, 0 })); pts0.push(new Array(new double[] { 10, 10, 0 })); pts0.push(new Array(new double[] { 0, 10, 0 })); @@ -105,7 +99,7 @@ public void CurvesIntersections() verb.geom.NurbsCurve curve1 = verb.geom.NurbsCurve.byKnotsControlPointsWeights(3, knots, pts1, weights); Array intersections = verb.eval.Intersect.curves(curve0._data, curve1._data, verb.core.Constants.TOLERANCE); - + _testOutput.WriteLine(intersections.length.ToString()); for (int i = 0; i < intersections.length; i++) { @@ -128,7 +122,7 @@ public void rationalCurveAdaptiveSample() pts.push(new Array(new double[] { 50, 5, 0 })); Array knots = new Array(new double[] { 0.0, 0.0, 0.0, 0.0, 0.333333, 0.666667, 1.0, 1.0, 1.0, 1.0 }); - Array knots2 = new Array(new double[] { 0.0, 0.2, 0.4, 0.6, 0.8, 1.0}); + Array knots2 = new Array(new double[] { 0.0, 0.2, 0.4, 0.6, 0.8, 1.0 }); Array weights = new Array(new double[] { 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 }); verb.geom.NurbsCurve curve = verb.geom.NurbsCurve.byKnotsControlPointsWeights(3, knots, pts, weights); @@ -168,15 +162,15 @@ public void rationalCurveRegularSample() [Fact] public void decomposeMatrix() { - Array matrix = new Array (); + Array matrix = new Array(); //matrix.push(new Array(new object[] {10, -7, 0})); //matrix.push(new Array(new object[] { -3, 2, 6 })); //matrix.push(new Array(new object[] { 5, -1, 5 })); - matrix.push(new Array(new object[] { 1,2,3 })); - matrix.push(new Array(new object[] { 2,4,5 })); - matrix.push(new Array(new object[] { 1,3,4 })); + matrix.push(new Array(new object[] { 1, 2, 3 })); + matrix.push(new Array(new object[] { 2, 4, 5 })); + matrix.push(new Array(new object[] { 1, 3, 4 })); //matrix.push(new Array(new object[] { 4,3 })); //matrix.push(new Array(new object[] { 6,3 })); @@ -185,7 +179,7 @@ public void decomposeMatrix() verb.core._Mat.LUDecomp matrixLU = Mat.LU(matrix); //var vector = new Array(new double[] {3,13,4}); - Array vector = new Array(new double[] { 0,4,17}); + Array vector = new Array(new double[] { 0, 4, 17 }); Array solved = Mat.LUsolve(matrixLU, vector); @@ -336,7 +330,7 @@ public void CurveKnotRefine() pts.push(new Array(new double[] { 10.0, 10.0, 2.0 })); Array knots = new Array(new double[] { 0.0, 0.0, 0.0, 1.0, 1.0, 1.0 }); - Array weights = new Array(new double[] { 1.0, 2.0, 1.0}); + Array weights = new Array(new double[] { 1.0, 2.0, 1.0 }); Array knotsToInsert = new Array(new double[] { 0.5, 0.5, 0.5 }); verb.geom.NurbsCurve curve = verb.geom.NurbsCurve.byKnotsControlPointsWeights(2, knots, pts, weights); @@ -416,12 +410,12 @@ public void SurfaceClosestPt() var surface = verb.geom.NurbsSurface.byKnotsControlPointsWeights(2, 1, knotsU, knotsV, pts, weight); Array derivatives = verb.eval.Eval.rationalSurfaceDerivatives(surface._data, 0.25, 0.25, 2); - var pt = new Array(new double[] {2.5, 1.5, 2}); + var pt = new Array(new double[] { 2.5, 1.5, 2 }); var rational = verb.eval.Analyze.rationalSurfaceClosestParam(surface._data, pt); - var ptd = (Array) derivatives.__a[0]; + var ptd = (Array)derivatives.__a[0]; var diff = verb.core.Vec.sub((Array)ptd.__a[0], pt); var Su = (Array)derivatives.__a[1]; @@ -433,7 +427,7 @@ public void SurfaceClosestPt() var Suv = (Array)derivatives.__a[1]; var Svu = (Array)derivatives.__a[1]; - var f = verb.core.Vec.dot((Array) Su.__a[0], diff); + var f = verb.core.Vec.dot((Array)Su.__a[0], diff); var g = verb.core.Vec.dot((Array)Sv.__a[1], diff); var k = new Array(new double[] { -f, -g }); diff --git a/src/GShark/Core/BoundingBoxTree/LazyCurveBBT.cs b/src/GShark/Core/BoundingBoxTree/LazyCurveBBT.cs index c33b37cf..627f23e5 100644 --- a/src/GShark/Core/BoundingBoxTree/LazyCurveBBT.cs +++ b/src/GShark/Core/BoundingBoxTree/LazyCurveBBT.cs @@ -1,8 +1,8 @@ using GShark.Geometry; +using GShark.Geometry.Interfaces; using GShark.Operation; using System; using System.Collections.Generic; -using GShark.Geometry.Interfaces; namespace GShark.Core.BoundingBoxTree { @@ -38,7 +38,7 @@ public BoundingBox BoundingBox() List curves = Divide.SplitCurve(_curve, t); return new Tuple, IBoundingBoxTree> - ( new LazyCurveBBT(curves[0], _knotTolerance), new LazyCurveBBT(curves[1], _knotTolerance)); + (new LazyCurveBBT(curves[0], _knotTolerance), new LazyCurveBBT(curves[1], _knotTolerance)); } public ICurve Yield() diff --git a/src/GShark/Core/GeoSharkMath.cs b/src/GShark/Core/GeoSharkMath.cs index cdcd15c7..de06b97a 100644 --- a/src/GShark/Core/GeoSharkMath.cs +++ b/src/GShark/Core/GeoSharkMath.cs @@ -136,7 +136,7 @@ internal static void KillNoise(ref double sinAngle, ref double cosAngle) /// The numerical value truncate. public static decimal Truncate(double value, byte decimals = 6) { - decimal d = (decimal) value; + decimal d = (decimal)value; decimal r = Math.Round(d, decimals); if (d > 0 && r > d) diff --git a/src/GShark/Core/Interfaces/ISerializable.cs b/src/GShark/Core/Interfaces/ISerializable.cs index 16dc2cc2..9ddc58e9 100644 --- a/src/GShark/Core/Interfaces/ISerializable.cs +++ b/src/GShark/Core/Interfaces/ISerializable.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace GShark.Core.Interfaces +namespace GShark.Core.Interfaces { public interface ISerializable { diff --git a/src/GShark/Core/Interval.cs b/src/GShark/Core/Interval.cs index ec7110b5..386ccb2a 100644 --- a/src/GShark/Core/Interval.cs +++ b/src/GShark/Core/Interval.cs @@ -1,5 +1,4 @@ using System; -using System.Data.SqlTypes; namespace GShark.Core { diff --git a/src/GShark/Core/KnotVector.cs b/src/GShark/Core/KnotVector.cs index 3ef97c6e..bc702371 100644 --- a/src/GShark/Core/KnotVector.cs +++ b/src/GShark/Core/KnotVector.cs @@ -219,7 +219,7 @@ public int Span(int n, int degree, double parameter) /// The multiplicity of the knot, or 0 if the knot is not part of the knot vector. public int Multiplicity(double knot) { - return this.Count(x => Math.Abs(x-knot) <= GeoSharkMath.MinTolerance); + return this.Count(x => Math.Abs(x - knot) <= GeoSharkMath.MinTolerance); } /// @@ -231,7 +231,7 @@ public int Multiplicity(double knot) Dictionary multiplicities = new Dictionary(Count); foreach (double knot in this) { - var multiplicity = Multiplicity(knot); + var multiplicity = Multiplicity(knot); if (!multiplicities.Keys.Contains(knot)) { multiplicities.Add(knot, multiplicity); diff --git a/src/GShark/Core/LinearAlgebra.cs b/src/GShark/Core/LinearAlgebra.cs index 6c107fe5..d2850431 100644 --- a/src/GShark/Core/LinearAlgebra.cs +++ b/src/GShark/Core/LinearAlgebra.cs @@ -1,7 +1,6 @@ using GShark.Geometry; using System; using System.Collections.Generic; -using System.Linq; namespace GShark.Core { @@ -10,185 +9,6 @@ namespace GShark.Core /// public class LinearAlgebra { - /// - /// Transforms a collection of points into their homogeneous equivalents.
- /// http://deltaorange.com/2012/03/08/the-truth-behind-homogenous-coordinates/ - ///
- /// Control points, a set of size (points count x points dimension). - /// Control point weights, the same size as the set of control points (points count x 1). - /// A set of control points where each point is (wi*pi, wi)
- /// where wi the ith control point weight and pi is the ith control point, hence the dimension of the point is dim + 1.
- public static List PointsHomogeniser(List controlPoints, List weights) - { - if (controlPoints.Count < weights.Count) - { - throw new ArgumentOutOfRangeException(nameof(weights), - "The weights set is bigger than the control points, it must be the same dimension"); - } - - if (controlPoints.Count > weights.Count) - { - int diff = controlPoints.Count - weights.Count; - List dataFilled = Sets.RepeatData(1.0, diff); - weights.AddRange(dataFilled); - } - - List controlPtsHomogenized = new List(); - - for (int i = 0; i < controlPoints.Count; i++) - { - Point4 tempPt = new Point4 - { - X = controlPoints[i].X * weights[i], - Y = controlPoints[i].Y * weights[i], - Z = controlPoints[i].Z * weights[i], - W = weights[i] - }; - - - controlPtsHomogenized.Add(tempPt); - } - - return controlPtsHomogenized; - } - - /// - /// Transforms a collection of points into their homogeneous equivalents, by a given weight value.
- /// http://deltaorange.com/2012/03/08/the-truth-behind-homogenous-coordinates/ - ///
- /// Control points, a set of size (points count x points dimension). - /// Weight value for each point. - /// A set of control points where each point is (wi*pi, wi)
- /// where wi the ith control point weight and pi is the ith control point, hence the dimension of the point is dim + 1.
- public static List PointsHomogeniser(List controlPoints, double weight) - { - List controlPtsHomogenized = new List(); - - foreach (var pt in controlPoints) - { - Point4 tempPt = new Point4 - { - X = pt.X * weight, Y = pt.Y * weight, Z = pt.Z * weight, W = weight - }; - - controlPtsHomogenized.Add(tempPt); - } - - return controlPtsHomogenized; - } - - /// - /// Transforms a two-dimension collection of points into their homogeneous equivalents.
- /// http://deltaorange.com/2012/03/08/the-truth-behind-homogenous-coordinates/ - ///
- /// Control points, a two-dimensional set of size (points count x points dimension). - /// Control point weights, the same size as the set of control points (points count x 1). - /// A two-dimensional set of control points where each point is (wi*pi, wi)
- /// where wi the ith control point weight and pi is the ith control point, hence the dimension of the point is dim + 1.
- public static List> PointsHomogeniser2d(List> controlPoints, List> weights = null) - { - int rows = controlPoints.Count; - List> controlPtsHomogenized = new List>(); - List> usedWeights = weights; - if (weights == null || weights.Count == 0) - { - usedWeights = new List>(); - for (int i = 0; i < rows; i++) - { - usedWeights.Add(Sets.RepeatData(1.0, controlPoints[i].Count)); - } - } - if (controlPoints.Count < usedWeights.Count) - { - throw new ArgumentOutOfRangeException(nameof(weights), "The weights set is bigger than the control points, it must be the same dimension"); - } - - for (int i = 0; i < rows; i++) - { - controlPtsHomogenized.Add(PointsHomogeniser(controlPoints[i], usedWeights[i])); - } - - return controlPtsHomogenized; - } - - /// - /// Obtains the weight from a collection of points in homogeneous space, assuming all are the same dimension. - /// - /// Points represented by an array (wi*pi, wi) with length (dim+1). - /// A set of values, represented by a set pi with length (dim). - public static List GetWeights(List homogenizedPoints) - { - return homogenizedPoints.Select(pt => pt.W).ToList(); - } - - /// - /// Obtains the weight from a two-dimensional collection of points in homogeneous space, assuming all are the same dimension. - /// - /// Two-dimensional set of points represented by an array (wi*pi, wi) with length (dim+1) - /// Two-dimensional set of values, each represented by an array pi with length (dim) - public static List> GetWeights2d(List> homogenizedPoints) - { - return homogenizedPoints.Select(pts => GetWeights(pts).ToList()).ToList(); - } - - /// - /// Gets a dehomogenized point from a homogenized curve point. - /// - /// A point represented by an array (wi*pi, wi) with length (dim+1). - /// A dehomogenized point. - public static Point3 PointDehomogenizer(Point4 homogenizedCurvePoint) - { - Point3 point = new Point3 - { - X = homogenizedCurvePoint.X / homogenizedCurvePoint.W, - Y = homogenizedCurvePoint.Y / homogenizedCurvePoint.W, - Z = homogenizedCurvePoint.Z / homogenizedCurvePoint.W - }; - - return point; - } - - /// - /// Gets a set of dehomogenized points. - /// - /// A collection of points represented by an array (wi*pi, wi) with length (dim+1). - /// Set of dehomogenized points. - public static List PointDehomogenizer1d(List homogenizedPoints) - { - return homogenizedPoints.Select(PointDehomogenizer).ToList(); - } - - /// - /// Gets a two-dimensional set of dehomogenized points. - /// - /// Two-dimensional set of points represented by an array (wi*pi, wi) with length (dim+1) - /// Two-dimensional set of dehomogenized points. - public static List> PointDehomogenizer2d(List> homogenizedPoints) - { - return homogenizedPoints.Select(PointDehomogenizer1d).ToList(); - } - - /// - /// Obtains the point from homogeneous point without dehomogenization, assuming all are the same length. - /// - /// Sets of points represented by an array (wi*pi, wi) with length (dim+1). - /// Set of rational points. - public static List RationalPoints(List homogenizedPoints) - { - - return homogenizedPoints.Select(pt => new Point3(pt.X, pt.Y, pt.Z)).ToList(); - } - - /// - /// Obtains the point from a two-dimensional set of homogeneous points without dehomogenization, assuming all are the same length. - /// - /// Two-dimensional set of points represented by an array (wi*pi, wi) with length (dim+1) - /// Two-dimensional set of rational points. - public static List> Rational2d(List> homogenizedPoints) - { - return homogenizedPoints.Select(hpts => RationalPoints(hpts)).ToList(); - } - /// /// Finds the Tait-Byran angles (also loosely called Euler angles) for a rotation transformation.
/// yaw - angle (in radians) to rotate about the Z axis.
@@ -205,7 +25,7 @@ public static List> Rational2d(List> homogenizedPoints (Math.Abs(transform[2][1]) < GeoSharkMath.MinTolerance && Math.Abs(transform[2][2]) < GeoSharkMath.MinTolerance) || (Math.Abs(transform[2][0]) >= 1.0)) { - values.Add("Pitch" , (transform[2][0] > 0) ? -Math.PI / 2.0 : Math.PI / 2.0); + values.Add("Pitch", (transform[2][0] > 0) ? -Math.PI / 2.0 : Math.PI / 2.0); values.Add("Yaw", Math.Atan2(-transform[0][1], transform[1][1])); values.Add("Roll", 0.0); return values; @@ -228,7 +48,7 @@ public static Vector3 GetRotationAxis(Transform transform) { Vector3 axis = Vector3.Unset; - if (Math.Abs(transform[0][1] + transform[1][0]) < GeoSharkMath.MinTolerance || + if (Math.Abs(transform[0][1] + transform[1][0]) < GeoSharkMath.MinTolerance || Math.Abs(transform[0][2] + transform[2][0]) < GeoSharkMath.MinTolerance || Math.Abs(transform[1][2] + transform[2][1]) < GeoSharkMath.MinTolerance) { diff --git a/src/GShark/Core/Matrix.cs b/src/GShark/Core/Matrix.cs index 0de0a179..ecf04f7d 100644 --- a/src/GShark/Core/Matrix.cs +++ b/src/GShark/Core/Matrix.cs @@ -2,9 +2,7 @@ using GShark.Geometry; using System; using System.Collections.Generic; -using System.Data; using System.Linq; -using System.Runtime.CompilerServices; namespace GShark.Core { @@ -89,7 +87,7 @@ public Matrix FillDiagonal(int row, int column, double valueToFill) int j = column; for (int i = row; i < this.Count; i++) { - if(j > this[0].Count-1) break; + if (j > this[0].Count - 1) break; copyMatrix[i][j] = valueToFill; j++; } @@ -160,7 +158,7 @@ public bool IsValid() int bRows = b.Count; int bCols = b[0].Count; - if(aCols != bRows) + if (aCols != bRows) { throw new Exception("Non-conformable matrices."); } @@ -404,7 +402,7 @@ public static Matrix Decompose(Matrix m, out int[] permutation) int rows = m.Count; int cols = m[0].Count; - if(rows != cols) + if (rows != cols) { throw new Exception("Attempt to decompose a non-squared matrix"); } @@ -490,7 +488,7 @@ public static Matrix Inverse(Matrix matrix) { Matrix matrixLu = Decompose(matrix, out int[] permutation); - if(!IsNonSingular(matrixLu)) + if (!IsNonSingular(matrixLu)) { throw new Exception("Matrix is singular"); } diff --git a/src/GShark/Core/Sets.cs b/src/GShark/Core/Sets.cs index 18dfe47f..397adfb6 100644 --- a/src/GShark/Core/Sets.cs +++ b/src/GShark/Core/Sets.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using GShark.Geometry; namespace GShark.Core { @@ -58,9 +57,9 @@ public static IList Range(Interval domain, int step) /// A collection of equally spaced numbers. public static IList LinearSpace(Interval domain, int step) { - if(Math.Abs(domain.T0 - domain.T1) <= GeoSharkMath.Epsilon) + if (Math.Abs(domain.T0 - domain.T1) <= GeoSharkMath.Epsilon) { - return new List(){ domain.T0 }; + return new List() { domain.T0 }; } List linearSpace = new List(); @@ -157,7 +156,7 @@ public static List SetUnion(IList a, IList b) /// The set difference. public static List SetDifference(IList a, IList b) { - if(a.Count == 0) + if (a.Count == 0) { throw new Exception("Set difference can't be computed, the first set is empty."); } diff --git a/src/GShark/Core/Transform.cs b/src/GShark/Core/Transform.cs index cebbbde0..68723496 100644 --- a/src/GShark/Core/Transform.cs +++ b/src/GShark/Core/Transform.cs @@ -34,22 +34,22 @@ public class Transform : List> public Transform() { AddRange(Matrix.Construct(4, 4)); - M00 = this[0][0]; - M01 = this[0][1]; - M02 = this[0][2]; - M03 = this[0][3]; - M10 = this[1][0]; - M11 = this[1][1]; - M12 = this[1][2]; - M13 = this[1][3]; - M20 = this[2][0]; - M21 = this[2][1]; - M22 = this[2][2]; - M23 = this[2][3]; - M30 = this[3][0]; - M31 = this[3][1]; - M32 = this[3][2]; - M33 = this[3][3]; + M00 = this[0][0]; + M01 = this[0][1]; + M02 = this[0][2]; + M03 = this[0][3]; + M10 = this[1][0]; + M11 = this[1][1]; + M12 = this[1][2]; + M13 = this[1][3]; + M20 = this[2][0]; + M21 = this[2][1]; + M22 = this[2][2]; + M23 = this[2][3]; + M30 = this[3][0]; + M31 = this[3][1]; + M32 = this[3][2]; + M33 = this[3][3]; } @@ -150,7 +150,7 @@ private static Transform Rotation(double sinAngle, double cosAngle, Vector3 axis transform[2][1] = axis[2] * axis[1] * oneMinusCosAngle + axis[0] * sAngle; transform[2][2] = axis[2] * axis[2] * oneMinusCosAngle + cAngle; - if (!origin.Equals(new Point3(0,0,0))) + if (!origin.Equals(new Point3(0, 0, 0))) { transform[0][3] = -((transform[0][0] - 1) * origin[0] + transform[0][1] * origin[1] + transform[0][2] * origin[2]); transform[1][3] = -(transform[1][0] * origin[0] + (transform[1][1] - 1) * origin[1] + transform[1][2] * origin[2]); @@ -186,7 +186,7 @@ public static Transform Scale(Point3 anchorPoint, double factorX, double factorY { var origin = new Point3(0.0, 0.0, 0.0); Transform scale = Scale(factorX, factorY, factorZ); - if(anchorPoint.Equals(origin)) + if (anchorPoint.Equals(origin)) { return scale; } @@ -243,22 +243,22 @@ public static Transform Copy(Transform other) { Transform t = new Transform { - [0] = {[0] = t0[0][0] * t1[0][0] + t0[0][1] * t1[1][0] + t0[0][2] * t1[2][0] + t0[0][3] * t1[3][0]}, - [0] = {[1] = t0[0][0] * t1[0][1] + t0[0][1] * t1[1][1] + t0[0][2] * t1[2][1] + t0[0][3] * t1[3][1]}, - [0] = {[2] = t0[0][0] * t1[0][2] + t0[0][1] * t1[1][2] + t0[0][2] * t1[2][2] + t0[0][3] * t1[3][2]}, - [0] = {[3] = t0[0][0] * t1[0][3] + t0[0][1] * t1[1][3] + t0[0][2] * t1[2][3] + t0[0][3] * t1[3][3]}, - [1] = {[0] = t0[1][0] * t1[0][0] + t0[1][1] * t1[1][0] + t0[1][2] * t1[2][0] + t0[1][3] * t1[3][0]}, - [1] = {[1] = t0[1][0] * t1[0][1] + t0[1][1] * t1[1][1] + t0[1][2] * t1[2][1] + t0[1][3] * t1[3][1]}, - [1] = {[2] = t0[1][0] * t1[0][2] + t0[1][1] * t1[1][2] + t0[1][2] * t1[2][2] + t0[1][3] * t1[3][2]}, - [1] = {[3] = t0[1][0] * t1[0][3] + t0[1][1] * t1[1][3] + t0[1][2] * t1[2][3] + t0[1][3] * t1[3][3]}, - [2] = {[0] = t0[2][0] * t1[0][0] + t0[2][1] * t1[1][0] + t0[2][2] * t1[2][0] + t0[2][3] * t1[3][0]}, - [2] = {[1] = t0[2][0] * t1[0][1] + t0[2][1] * t1[1][1] + t0[2][2] * t1[2][1] + t0[2][3] * t1[3][1]}, - [2] = {[2] = t0[2][0] * t1[0][2] + t0[2][1] * t1[1][2] + t0[2][2] * t1[2][2] + t0[2][3] * t1[3][2]}, - [2] = {[3] = t0[2][0] * t1[0][3] + t0[2][1] * t1[1][3] + t0[2][2] * t1[2][3] + t0[2][3] * t1[3][3]}, - [3] = {[0] = t0[3][0] * t1[0][0] + t0[3][1] * t1[1][0] + t0[3][2] * t1[2][0] + t0[3][3] * t1[3][0]}, - [3] = {[1] = t0[3][0] * t1[0][1] + t0[3][1] * t1[1][1] + t0[3][2] * t1[2][1] + t0[3][3] * t1[3][1]}, - [3] = {[2] = t0[3][0] * t1[0][2] + t0[3][1] * t1[1][2] + t0[3][2] * t1[2][2] + t0[3][3] * t1[3][2]}, - [3] = {[3] = t0[3][0] * t1[0][3] + t0[3][1] * t1[1][3] + t0[3][2] * t1[2][3] + t0[3][3] * t1[3][3]} + [0] = { [0] = t0[0][0] * t1[0][0] + t0[0][1] * t1[1][0] + t0[0][2] * t1[2][0] + t0[0][3] * t1[3][0] }, + [0] = { [1] = t0[0][0] * t1[0][1] + t0[0][1] * t1[1][1] + t0[0][2] * t1[2][1] + t0[0][3] * t1[3][1] }, + [0] = { [2] = t0[0][0] * t1[0][2] + t0[0][1] * t1[1][2] + t0[0][2] * t1[2][2] + t0[0][3] * t1[3][2] }, + [0] = { [3] = t0[0][0] * t1[0][3] + t0[0][1] * t1[1][3] + t0[0][2] * t1[2][3] + t0[0][3] * t1[3][3] }, + [1] = { [0] = t0[1][0] * t1[0][0] + t0[1][1] * t1[1][0] + t0[1][2] * t1[2][0] + t0[1][3] * t1[3][0] }, + [1] = { [1] = t0[1][0] * t1[0][1] + t0[1][1] * t1[1][1] + t0[1][2] * t1[2][1] + t0[1][3] * t1[3][1] }, + [1] = { [2] = t0[1][0] * t1[0][2] + t0[1][1] * t1[1][2] + t0[1][2] * t1[2][2] + t0[1][3] * t1[3][2] }, + [1] = { [3] = t0[1][0] * t1[0][3] + t0[1][1] * t1[1][3] + t0[1][2] * t1[2][3] + t0[1][3] * t1[3][3] }, + [2] = { [0] = t0[2][0] * t1[0][0] + t0[2][1] * t1[1][0] + t0[2][2] * t1[2][0] + t0[2][3] * t1[3][0] }, + [2] = { [1] = t0[2][0] * t1[0][1] + t0[2][1] * t1[1][1] + t0[2][2] * t1[2][1] + t0[2][3] * t1[3][1] }, + [2] = { [2] = t0[2][0] * t1[0][2] + t0[2][1] * t1[1][2] + t0[2][2] * t1[2][2] + t0[2][3] * t1[3][2] }, + [2] = { [3] = t0[2][0] * t1[0][3] + t0[2][1] * t1[1][3] + t0[2][2] * t1[2][3] + t0[2][3] * t1[3][3] }, + [3] = { [0] = t0[3][0] * t1[0][0] + t0[3][1] * t1[1][0] + t0[3][2] * t1[2][0] + t0[3][3] * t1[3][0] }, + [3] = { [1] = t0[3][0] * t1[0][1] + t0[3][1] * t1[1][1] + t0[3][2] * t1[2][1] + t0[3][3] * t1[3][1] }, + [3] = { [2] = t0[3][0] * t1[0][2] + t0[3][1] * t1[1][2] + t0[3][2] * t1[2][2] + t0[3][3] * t1[3][2] }, + [3] = { [3] = t0[3][0] * t1[0][3] + t0[3][1] * t1[1][3] + t0[3][2] * t1[2][3] + t0[3][3] * t1[3][3] } }; return t; @@ -276,14 +276,14 @@ public static Transform Reflection(Plane plane) Transform transform = Identity(); Vector3 unitizedN = normal.Unitize(); - Vector3 translation = unitizedN * (2.0 * (unitizedN[0]*pt[0] + unitizedN[1] * pt[1] + unitizedN[1] * pt[1])); + Vector3 translation = unitizedN * (2.0 * (unitizedN[0] * pt[0] + unitizedN[1] * pt[1] + unitizedN[1] * pt[1])); transform[0][0] = 1 - 2.0 * unitizedN[0] * unitizedN[0]; - transform[0][1] = - 2.0 * unitizedN[0] * unitizedN[1]; - transform[0][2] = - 2.0 * unitizedN[0] * unitizedN[2]; + transform[0][1] = -2.0 * unitizedN[0] * unitizedN[1]; + transform[0][2] = -2.0 * unitizedN[0] * unitizedN[2]; transform[0][3] = translation[0]; - transform[1][0] = - 2.0 * unitizedN[1] * unitizedN[0]; + transform[1][0] = -2.0 * unitizedN[1] * unitizedN[0]; transform[1][1] = 1 - 2.0 * unitizedN[1] * unitizedN[1]; transform[1][2] = -2.0 * unitizedN[1] * unitizedN[2]; transform[1][3] = translation[1]; @@ -338,13 +338,13 @@ public static Transform PlaneToPlane(Plane a, Plane b) var x0 = a.XAxis; var y0 = a.YAxis; var z0 = a.ZAxis; - + var pt1 = b.Origin; var x1 = b.XAxis; var y1 = b.YAxis; var z1 = b.ZAxis; - var origin = new Point3(0,0,0); + var origin = new Point3(0, 0, 0); // Translating point pt0 to (0,0,0) Transform translation0 = Translation(origin - pt0); diff --git a/src/GShark/ExtendedMethods/Curve.cs b/src/GShark/ExtendedMethods/Curve.cs index 6875145e..2638f4fb 100644 --- a/src/GShark/ExtendedMethods/Curve.cs +++ b/src/GShark/ExtendedMethods/Curve.cs @@ -119,7 +119,7 @@ public static List PerpendicularFrames(this ICurve curve, List uV var sNext = Vector3.CrossProduct(pointsOnCurveTan[i + 1], rNext); //compute vector s[i+1] of next frame //create output frame - var frameNext = new Plane {Origin = pointsOnCurve[i + 1], XAxis = rNext, YAxis = sNext}; + var frameNext = new Plane { Origin = pointsOnCurve[i + 1], XAxis = rNext, YAxis = sNext }; perpFrames[i + 1] = frameNext; //output frame } diff --git a/src/GShark/ExtendedMethods/ExtendedEnumerable.cs b/src/GShark/ExtendedMethods/ExtendedEnumerable.cs index c09ade19..4465a32e 100644 --- a/src/GShark/ExtendedMethods/ExtendedEnumerable.cs +++ b/src/GShark/ExtendedMethods/ExtendedEnumerable.cs @@ -43,7 +43,7 @@ public static List Unique(this IEnumerable enumerable, Func throw new InvalidOperationException("Cannot compute unique for a empty set."); } - List uniques = new List{ tempCollection[tempCollection.Count - 1] }; + List uniques = new List { tempCollection[tempCollection.Count - 1] }; tempCollection.RemoveAt(tempCollection.Count - 1); while (tempCollection.Count > 0) diff --git a/src/GShark/Geometry/Arc.cs b/src/GShark/Geometry/Arc.cs index 85b37020..7289501d 100644 --- a/src/GShark/Geometry/Arc.cs +++ b/src/GShark/Geometry/Arc.cs @@ -382,7 +382,7 @@ private void ToNurbsCurve() Knots = knots; LocationPoints = ctrPts.ToList(); - ControlPoints = LinearAlgebra.PointsHomogeniser(ctrPts.ToList(), weights.ToList()); + ControlPoints = Point4.PointsHomogeniser(ctrPts.ToList(), weights.ToList()); } /// diff --git a/src/GShark/Geometry/BoundingBox.cs b/src/GShark/Geometry/BoundingBox.cs index 675b8500..83dc977c 100644 --- a/src/GShark/Geometry/BoundingBox.cs +++ b/src/GShark/Geometry/BoundingBox.cs @@ -36,8 +36,8 @@ public BoundingBox(IList pts, Plane orientation = null) copyPt = pts.Select(pt => pt.Transform(transform)).ToList(); } - Point3 min = new Point3 (double.MaxValue, double.MaxValue, double.MaxValue); - Point3 max = new Point3 (double.MinValue, double.MinValue, double.MinValue); + Point3 min = new Point3(double.MaxValue, double.MaxValue, double.MaxValue); + Point3 max = new Point3(double.MinValue, double.MinValue, double.MinValue); foreach (var pt in copyPt) { @@ -299,7 +299,7 @@ public static BoundingBox Union(BoundingBox bBox1, BoundingBox bBox2) /// A BoundingBox made valid. public BoundingBox MakeItValid() { - if(!Min.IsValid || !Max.IsValid) + if (!Min.IsValid || !Max.IsValid) { return Unset; } diff --git a/src/GShark/Geometry/Circle.cs b/src/GShark/Geometry/Circle.cs index e652633d..413f4998 100644 --- a/src/GShark/Geometry/Circle.cs +++ b/src/GShark/Geometry/Circle.cs @@ -2,7 +2,6 @@ using GShark.Geometry.Interfaces; using System; using System.Collections.Generic; -using System.Drawing; using System.Linq; namespace GShark.Geometry @@ -101,7 +100,7 @@ public List ControlPoints List weights = Sets.RepeatData(1.0, 9); weights[1] = weights[3] = weights[5] = weights[7] = 1.0 / Math.Sqrt(2.0); - return LinearAlgebra.PointsHomogeniser(LocationPoints, weights.ToList()); + return Point4.PointsHomogeniser(LocationPoints, weights.ToList()); } } diff --git a/src/GShark/Geometry/ConvexHull.cs b/src/GShark/Geometry/ConvexHull.cs index f58deff1..aa55b6b3 100644 --- a/src/GShark/Geometry/ConvexHull.cs +++ b/src/GShark/Geometry/ConvexHull.cs @@ -30,56 +30,56 @@ namespace GShark.Geometry { - /// - /// Taken from https://github.com/OskarSigvardsson/unity-quickhull - /// - /// An implementation of the quickhull algorithm for generating 3d convex - /// hulls. - /// - /// The algorithm works like this: you start with an initial "seed" hull, - /// that is just a simple tetrahedron made up of four points in the point - /// cloud. This seed hull is then grown until it all the points in the - /// point cloud is inside of it, at which point it will be the convex hull - /// for the entire set. - /// - /// All of the points in the point cloud is divided into two parts, the - /// "open set" and the "closed set". The open set consists of all the - /// points outside of the tetrahedron, and the closed set is all of the - /// points inside the tetrahedron. After each iteration of the algorithm, - /// the closed set gets bigger and the open set get smaller. When the open - /// set is empty, the algorithm is finished. - /// - /// Each point in the open set is assigned to a face that it lies outside - /// of. To grow the hull, the point in the open set which is farthest from - /// it's face is chosen. All faces which are facing that point (I call - /// them "lit faces" in the code, because if you imagine the point as a - /// point light, it's the set of points which would be lit by that point - /// light) are removed, and a "horizon" of edges is found from where the - /// faces were removed. From this horizon, new faces are constructed in a - /// "cone" like fashion connecting the point to the edges. - /// - /// To keep track of the faces, I use a struct for each face which - /// contains the three vertices of the face in CCW order, as well as the - /// three triangles which share an edge. I was considering doing a - /// half-edge structure to store the mesh, but it's not needed. Using a - /// struct for each face and neighbors simplify the algorithm and makes it - /// easy to export it as a mesh. - /// - /// The most subtle part of the algorithm is finding the horizon. In order - /// to properly construct the cone so that all neighbors are kept - /// consistent, you can do a depth-first search from the first lit face. - /// If the depth-first search always proceeeds in a counter-clockwise - /// fashion, it guarantees that the horizon will be found in a - /// counter-clockwise order, which makes it easy to construct the cone of - /// new faces. - /// - /// A note: the code uses a right-handed coordinate system, where the - /// cross-product uses the right-hand rule and the faces are in CCW order. - /// At the end of the algorithm, the hull is exported in a Unity-friendly - /// fashion, with a left-handed mesh. - /// - public class ConvexHull - { + /// + /// Taken from https://github.com/OskarSigvardsson/unity-quickhull + /// + /// An implementation of the quickhull algorithm for generating 3d convex + /// hulls. + /// + /// The algorithm works like this: you start with an initial "seed" hull, + /// that is just a simple tetrahedron made up of four points in the point + /// cloud. This seed hull is then grown until it all the points in the + /// point cloud is inside of it, at which point it will be the convex hull + /// for the entire set. + /// + /// All of the points in the point cloud is divided into two parts, the + /// "open set" and the "closed set". The open set consists of all the + /// points outside of the tetrahedron, and the closed set is all of the + /// points inside the tetrahedron. After each iteration of the algorithm, + /// the closed set gets bigger and the open set get smaller. When the open + /// set is empty, the algorithm is finished. + /// + /// Each point in the open set is assigned to a face that it lies outside + /// of. To grow the hull, the point in the open set which is farthest from + /// it's face is chosen. All faces which are facing that point (I call + /// them "lit faces" in the code, because if you imagine the point as a + /// point light, it's the set of points which would be lit by that point + /// light) are removed, and a "horizon" of edges is found from where the + /// faces were removed. From this horizon, new faces are constructed in a + /// "cone" like fashion connecting the point to the edges. + /// + /// To keep track of the faces, I use a struct for each face which + /// contains the three vertices of the face in CCW order, as well as the + /// three triangles which share an edge. I was considering doing a + /// half-edge structure to store the mesh, but it's not needed. Using a + /// struct for each face and neighbors simplify the algorithm and makes it + /// easy to export it as a mesh. + /// + /// The most subtle part of the algorithm is finding the horizon. In order + /// to properly construct the cone so that all neighbors are kept + /// consistent, you can do a depth-first search from the first lit face. + /// If the depth-first search always proceeeds in a counter-clockwise + /// fashion, it guarantees that the horizon will be found in a + /// counter-clockwise order, which makes it easy to construct the cone of + /// new faces. + /// + /// A note: the code uses a right-handed coordinate system, where the + /// cross-product uses the right-hand rule and the faces are in CCW order. + /// At the end of the algorithm, the hull is exported in a Unity-friendly + /// fashion, with a left-handed mesh. + /// + public class ConvexHull + { /// /// Constant representing a point that has yet to be assigned to a @@ -102,115 +102,115 @@ public class ConvexHull /// private const double EPSILON = 0.0001f; - /// - /// Struct representing a single face. - /// - /// Vertex0, Vertex1 and Vertex2 are the vertices in CCW order. They - /// acutal points are stored in the points array, these are just - /// indexes into that array. - /// - /// Opposite0, Opposite1 and Opposite2 are the keys to the faces which - /// share an edge with this face. Opposite0 is the face opposite - /// Vertex0 (so it has an edge with Vertex2 and Vertex1), etc. - /// - /// Normal is (unsurprisingly) the normal of the triangle. - /// - public struct Face - { - public int Vertex0; - public int Vertex1; - public int Vertex2; - - public int Opposite0; - public int Opposite1; - public int Opposite2; - - public Vector3 Normal; - - public Face(int v0, int v1, int v2, int o0, int o1, int o2, Vector3 normal) - { - Vertex0 = v0; - Vertex1 = v1; - Vertex2 = v2; - Opposite0 = o0; - Opposite1 = o1; - Opposite2 = o2; - Normal = normal; - } - - public bool Equals(Face other) - { - return (Vertex0 == other.Vertex0) - && (Vertex1 == other.Vertex1) - && (Vertex2 == other.Vertex2) - && (Opposite0 == other.Opposite0) - && (Opposite1 == other.Opposite1) - && (Opposite2 == other.Opposite2) - && (Normal == other.Normal); - } - } - - /// - /// Struct representing a mapping between a point and a face. These - /// are used in the openSet array. - /// - /// Point is the index of the point in the points array, Face is the - /// key of the face in the Key dictionary, Distance is the distance - /// from the face to the point. - /// - private struct PointFace - { - public int Point; - public int Face; - public double Distance; - - public PointFace(int p, int f, double d) - { - Point = p; - Face = f; - Distance = d; - } - } - - /// - /// Struct representing a single edge in the horizon. - /// - /// Edge0 and Edge1 are the vertexes of edge in CCW order, Face is the - /// face on the other side of the horizon. - /// - /// TODO Edge1 isn't actually needed, you can just index the next item - /// in the horizon array. - /// - private struct HorizonEdge - { - public int Face; - public int Edge0; - public int Edge1; - } - - /// - /// A dictionary storing the faces of the currently generated convex - /// hull. The key is the id of the face, used in the Face, PointFace - /// and HorizonEdge struct. - /// - /// This is a Dictionary, because we need both random access to it, - /// the ability to loop through it, and ability to quickly delete - /// faces (in the ConstructCone method), and Dictionary is the obvious - /// candidate that can do all of those things. - /// - /// I'm wondering if using a Dictionary is best idea, though. It might - /// be better to just have them in a List and mark a face as - /// deleted by adding a field to the Face struct. The downside is that - /// we would need an extra field in the Face struct, and when we're - /// looping through the points in openSet, we would have to loop - /// through all the Faces EVER created in the algorithm, and skip the - /// ones that have been marked as deleted. However, looping through a - /// list is fairly fast, and it might be worth it to avoid Dictionary - /// overhead. - /// - /// TODO test converting to a List instead. - /// - private Dictionary _faces; + /// + /// Struct representing a single face. + /// + /// Vertex0, Vertex1 and Vertex2 are the vertices in CCW order. They + /// acutal points are stored in the points array, these are just + /// indexes into that array. + /// + /// Opposite0, Opposite1 and Opposite2 are the keys to the faces which + /// share an edge with this face. Opposite0 is the face opposite + /// Vertex0 (so it has an edge with Vertex2 and Vertex1), etc. + /// + /// Normal is (unsurprisingly) the normal of the triangle. + /// + public struct Face + { + public int Vertex0; + public int Vertex1; + public int Vertex2; + + public int Opposite0; + public int Opposite1; + public int Opposite2; + + public Vector3 Normal; + + public Face(int v0, int v1, int v2, int o0, int o1, int o2, Vector3 normal) + { + Vertex0 = v0; + Vertex1 = v1; + Vertex2 = v2; + Opposite0 = o0; + Opposite1 = o1; + Opposite2 = o2; + Normal = normal; + } + + public bool Equals(Face other) + { + return (Vertex0 == other.Vertex0) + && (Vertex1 == other.Vertex1) + && (Vertex2 == other.Vertex2) + && (Opposite0 == other.Opposite0) + && (Opposite1 == other.Opposite1) + && (Opposite2 == other.Opposite2) + && (Normal == other.Normal); + } + } + + /// + /// Struct representing a mapping between a point and a face. These + /// are used in the openSet array. + /// + /// Point is the index of the point in the points array, Face is the + /// key of the face in the Key dictionary, Distance is the distance + /// from the face to the point. + /// + private struct PointFace + { + public int Point; + public int Face; + public double Distance; + + public PointFace(int p, int f, double d) + { + Point = p; + Face = f; + Distance = d; + } + } + + /// + /// Struct representing a single edge in the horizon. + /// + /// Edge0 and Edge1 are the vertexes of edge in CCW order, Face is the + /// face on the other side of the horizon. + /// + /// TODO Edge1 isn't actually needed, you can just index the next item + /// in the horizon array. + /// + private struct HorizonEdge + { + public int Face; + public int Edge0; + public int Edge1; + } + + /// + /// A dictionary storing the faces of the currently generated convex + /// hull. The key is the id of the face, used in the Face, PointFace + /// and HorizonEdge struct. + /// + /// This is a Dictionary, because we need both random access to it, + /// the ability to loop through it, and ability to quickly delete + /// faces (in the ConstructCone method), and Dictionary is the obvious + /// candidate that can do all of those things. + /// + /// I'm wondering if using a Dictionary is best idea, though. It might + /// be better to just have them in a List and mark a face as + /// deleted by adding a field to the Face struct. The downside is that + /// we would need an extra field in the Face struct, and when we're + /// looping through the points in openSet, we would have to loop + /// through all the Faces EVER created in the algorithm, and skip the + /// ones that have been marked as deleted. However, looping through a + /// list is fairly fast, and it might be worth it to avoid Dictionary + /// overhead. + /// + /// TODO test converting to a List instead. + /// + private Dictionary _faces; /// /// The set of points to be processed. "openSet" is a misleading name, @@ -272,95 +272,95 @@ private struct HorizonEdge /// private int _faceCount = 0; - /// - /// Generate a convex hull from points in points array, and store the - /// mesh in Unity-friendly format in verts and tris. If splitVerts is - /// true, the the verts will be split, if false, the same vert will be - /// used for more than one triangle. - /// - public void GenerateHull( - List points, - bool splitVerts, - ref List verts, - ref List tris, - ref List normals) - { - if (points.Count < 4) - { - throw new System.ArgumentException("Need at least 4 points to generate a convex hull"); - } - - Initialize(points, splitVerts); - - GenerateInitialHull(points); - - while (_openSetTail >= 0) - { - GrowHull(points); - } - - ExportMesh(points, splitVerts, ref verts, ref tris, ref normals); - VerifyMesh(points, ref verts, ref tris); - } + /// + /// Generate a convex hull from points in points array, and store the + /// mesh in Unity-friendly format in verts and tris. If splitVerts is + /// true, the the verts will be split, if false, the same vert will be + /// used for more than one triangle. + /// + public void GenerateHull( + List points, + bool splitVerts, + ref List verts, + ref List tris, + ref List normals) + { + if (points.Count < 4) + { + throw new System.ArgumentException("Need at least 4 points to generate a convex hull"); + } + + Initialize(points, splitVerts); + + GenerateInitialHull(points); + + while (_openSetTail >= 0) + { + GrowHull(points); + } + + ExportMesh(points, splitVerts, ref verts, ref tris, ref normals); + VerifyMesh(points, ref verts, ref tris); + } /// /// Make sure all the buffers and variables needed for the algorithm /// are initialized. /// private void Initialize(List points, bool splitVerts) - { - _faceCount = 0; - _openSetTail = -1; - - if (_faces == null) - { - _faces = new Dictionary(); - _litFaces = new HashSet(); - _horizon = new List(); - _openSet = new List(points.Count); - } - else - { - _faces.Clear(); - _litFaces.Clear(); - _horizon.Clear(); - _openSet.Clear(); - - if (_openSet.Capacity < points.Count) - { - // i wonder if this is a good idea... if you call - // GenerateHull over and over with slightly increasing - // points counts, it's going to reallocate every time. Maybe - // i should just use .Add(), and let the List manage the - // capacity, increasing it geometrically every time we need - // to reallocate. - - // maybe do - // openSet.Capacity = Mathf.NextPowerOfTwo(points.Count) - // instead? - - _openSet.Capacity = points.Count; - } - } - - if (!splitVerts) - { - if (_hullVertices == null) - { - _hullVertices = new Dictionary(); - } - else - { - _hullVertices.Clear(); - } - } - } + { + _faceCount = 0; + _openSetTail = -1; + + if (_faces == null) + { + _faces = new Dictionary(); + _litFaces = new HashSet(); + _horizon = new List(); + _openSet = new List(points.Count); + } + else + { + _faces.Clear(); + _litFaces.Clear(); + _horizon.Clear(); + _openSet.Clear(); + + if (_openSet.Capacity < points.Count) + { + // i wonder if this is a good idea... if you call + // GenerateHull over and over with slightly increasing + // points counts, it's going to reallocate every time. Maybe + // i should just use .Add(), and let the List manage the + // capacity, increasing it geometrically every time we need + // to reallocate. + + // maybe do + // openSet.Capacity = Mathf.NextPowerOfTwo(points.Count) + // instead? + + _openSet.Capacity = points.Count; + } + } + + if (!splitVerts) + { + if (_hullVertices == null) + { + _hullVertices = new Dictionary(); + } + else + { + _hullVertices.Clear(); + } + } + } /// /// Create initial seed hull. /// private void GenerateInitialHull(List points) - { + { // Find points suitable for use as the seed hull. Some varieties of // this algorithm pick extreme points here, but I'm not convinced // you gain all that much from that. Currently what it does is just @@ -374,170 +374,170 @@ private void GenerateInitialHull(List points) bool above = Vector3.DotProduct(v3 - v1, Vector3.CrossProduct(v1 - v0, v2 - v0)) > 0.0f; - // Create the faces of the seed hull. You need to draw a diagram - // here, otherwise it's impossible to know what's going on :) - - // Basically: there are two different possible start-tetrahedrons, - // depending on whether the fourth point is above or below the base - // triangle. If you draw a tetrahedron with these coordinates (in a - // right-handed coordinate-system): - - // b0 = (0,0,0) - // b1 = (1,0,0) - // b2 = (0,1,0) - // b3 = (0,0,1) - - // you can see the first case (set b3 = (0,0,-1) for the second - // case). The faces are added with the proper references to the - // faces opposite each vertex - - _faceCount = 0; - if (above) - { - _faces[_faceCount++] = new Face(b0, b2, b1, 3, 1, 2, Normal(points[b0], points[b2], points[b1])); - _faces[_faceCount++] = new Face(b0, b1, b3, 3, 2, 0, Normal(points[b0], points[b1], points[b3])); - _faces[_faceCount++] = new Face(b0, b3, b2, 3, 0, 1, Normal(points[b0], points[b3], points[b2])); - _faces[_faceCount++] = new Face(b1, b2, b3, 2, 1, 0, Normal(points[b1], points[b2], points[b3])); - } - else - { - _faces[_faceCount++] = new Face(b0, b1, b2, 3, 2, 1, Normal(points[b0], points[b1], points[b2])); - _faces[_faceCount++] = new Face(b0, b3, b1, 3, 0, 2, Normal(points[b0], points[b3], points[b1])); - _faces[_faceCount++] = new Face(b0, b2, b3, 3, 1, 0, Normal(points[b0], points[b2], points[b3])); - _faces[_faceCount++] = new Face(b1, b3, b2, 2, 0, 1, Normal(points[b1], points[b3], points[b2])); - } - - VerifyFaces(points); - - // Create the openSet. Add all points except the points of the seed - // hull. - for (int i = 0; i < points.Count; i++) - { - if (i == b0 || i == b1 || i == b2 || i == b3) + // Create the faces of the seed hull. You need to draw a diagram + // here, otherwise it's impossible to know what's going on :) + + // Basically: there are two different possible start-tetrahedrons, + // depending on whether the fourth point is above or below the base + // triangle. If you draw a tetrahedron with these coordinates (in a + // right-handed coordinate-system): + + // b0 = (0,0,0) + // b1 = (1,0,0) + // b2 = (0,1,0) + // b3 = (0,0,1) + + // you can see the first case (set b3 = (0,0,-1) for the second + // case). The faces are added with the proper references to the + // faces opposite each vertex + + _faceCount = 0; + if (above) + { + _faces[_faceCount++] = new Face(b0, b2, b1, 3, 1, 2, Normal(points[b0], points[b2], points[b1])); + _faces[_faceCount++] = new Face(b0, b1, b3, 3, 2, 0, Normal(points[b0], points[b1], points[b3])); + _faces[_faceCount++] = new Face(b0, b3, b2, 3, 0, 1, Normal(points[b0], points[b3], points[b2])); + _faces[_faceCount++] = new Face(b1, b2, b3, 2, 1, 0, Normal(points[b1], points[b2], points[b3])); + } + else + { + _faces[_faceCount++] = new Face(b0, b1, b2, 3, 2, 1, Normal(points[b0], points[b1], points[b2])); + _faces[_faceCount++] = new Face(b0, b3, b1, 3, 0, 2, Normal(points[b0], points[b3], points[b1])); + _faces[_faceCount++] = new Face(b0, b2, b3, 3, 1, 0, Normal(points[b0], points[b2], points[b3])); + _faces[_faceCount++] = new Face(b1, b3, b2, 2, 0, 1, Normal(points[b1], points[b3], points[b2])); + } + + VerifyFaces(points); + + // Create the openSet. Add all points except the points of the seed + // hull. + for (int i = 0; i < points.Count; i++) + { + if (i == b0 || i == b1 || i == b2 || i == b3) { continue; } _openSet.Add(new PointFace(i, UNASSIGNED, 0.0f)); - } - - // Add the seed hull verts to the tail of the list. - _openSet.Add(new PointFace(b0, INSIDE, double.NaN)); - _openSet.Add(new PointFace(b1, INSIDE, double.NaN)); - _openSet.Add(new PointFace(b2, INSIDE, double.NaN)); - _openSet.Add(new PointFace(b3, INSIDE, double.NaN)); - - // Set the openSetTail value. Last item in the array is - // openSet.Count - 1, but four of the points (the verts of the seed - // hull) are part of the closed set, so move openSetTail to just - // before those. - _openSetTail = _openSet.Count - 5; - - Assert(_openSet.Count == points.Count); - - // Assign all points of the open set. This does basically the same - // thing as ReassignPoints() - for (int i = 0; i <= _openSetTail; i++) - { - Assert(_openSet[i].Face == UNASSIGNED); - Assert(_openSet[_openSetTail].Face == UNASSIGNED); - Assert(_openSet[_openSetTail + 1].Face == INSIDE); + } + + // Add the seed hull verts to the tail of the list. + _openSet.Add(new PointFace(b0, INSIDE, double.NaN)); + _openSet.Add(new PointFace(b1, INSIDE, double.NaN)); + _openSet.Add(new PointFace(b2, INSIDE, double.NaN)); + _openSet.Add(new PointFace(b3, INSIDE, double.NaN)); + + // Set the openSetTail value. Last item in the array is + // openSet.Count - 1, but four of the points (the verts of the seed + // hull) are part of the closed set, so move openSetTail to just + // before those. + _openSetTail = _openSet.Count - 5; + + Assert(_openSet.Count == points.Count); + + // Assign all points of the open set. This does basically the same + // thing as ReassignPoints() + for (int i = 0; i <= _openSetTail; i++) + { + Assert(_openSet[i].Face == UNASSIGNED); + Assert(_openSet[_openSetTail].Face == UNASSIGNED); + Assert(_openSet[_openSetTail + 1].Face == INSIDE); bool assigned = false; PointFace fp = _openSet[i]; - Assert(_faces.Count == 4); - Assert(_faces.Count == _faceCount); - for (int j = 0; j < 4; j++) - { - Assert(_faces.ContainsKey(j)); + Assert(_faces.Count == 4); + Assert(_faces.Count == _faceCount); + for (int j = 0; j < 4; j++) + { + Assert(_faces.ContainsKey(j)); Face face = _faces[j]; double dist = PointFaceDistance(points[fp.Point], points[face.Vertex0], face); - if (dist > 0) - { - fp.Face = j; - fp.Distance = dist; - _openSet[i] = fp; - - assigned = true; - break; - } - } - - if (!assigned) - { - // Point is inside - fp.Face = INSIDE; - fp.Distance = double.NaN; - - // Point is inside seed hull: swap point with tail, and move - // openSetTail back. We also have to decrement i, because - // there's a new item at openSet[i], and we need to process - // it next iteration - _openSet[i] = _openSet[_openSetTail]; - _openSet[_openSetTail] = fp; - - _openSetTail -= 1; - i -= 1; - } - } - - VerifyOpenSet(points); - } + if (dist > 0) + { + fp.Face = j; + fp.Distance = dist; + _openSet[i] = fp; + + assigned = true; + break; + } + } + + if (!assigned) + { + // Point is inside + fp.Face = INSIDE; + fp.Distance = double.NaN; + + // Point is inside seed hull: swap point with tail, and move + // openSetTail back. We also have to decrement i, because + // there's a new item at openSet[i], and we need to process + // it next iteration + _openSet[i] = _openSet[_openSetTail]; + _openSet[_openSetTail] = fp; + + _openSetTail -= 1; + i -= 1; + } + } + + VerifyOpenSet(points); + } /// /// Find four points in the point cloud that are not coplanar for the /// seed hull /// private void FindInitialHullIndices(List points, out int b0, out int b1, out int b2, out int b3) - { + { int count = points.Count; - for (int i0 = 0; i0 < count - 3; i0++) - { - for (int i1 = i0 + 1; i1 < count - 2; i1++) - { + for (int i0 = 0; i0 < count - 3; i0++) + { + for (int i1 = i0 + 1; i1 < count - 2; i1++) + { Vector3 p0 = points[i0]; Vector3 p1 = points[i1]; - if (p0.EpsilonEquals(p1, GeoSharkMath.MinTolerance)) + if (p0.EpsilonEquals(p1, GeoSharkMath.MinTolerance)) { continue; } for (int i2 = i1 + 1; i2 < count - 1; i2++) - { + { Vector3 p2 = points[i2]; - if (Trigonometry.ArePointsCollinear(p0, p1, p2)) + if (Trigonometry.ArePointsCollinear(p0, p1, p2)) { continue; } for (int i3 = i2 + 1; i3 < count - 0; i3++) - { + { Vector3 p3 = points[i3]; - if (Trigonometry.ArePointsCoplanar(new List{p0, p1, p2, p3})) + if (Trigonometry.ArePointsCoplanar(new List { p0, p1, p2, p3 })) { continue; } b0 = i0; - b1 = i1; - b2 = i2; - b3 = i3; - return; - } - } - } - } - - throw new System.ArgumentException("Can't generate hull, points are coplanar"); - } + b1 = i1; + b2 = i2; + b3 = i3; + return; + } + } + } + } + + throw new System.ArgumentException("Can't generate hull, points are coplanar"); + } /// /// Grow the hull. This method takes the current hull, and expands it @@ -545,41 +545,41 @@ private void FindInitialHullIndices(List points, out int b0, out int b1, /// from its face. /// private void GrowHull(List points) - { - Assert(_openSetTail >= 0); - Assert(_openSet[0].Face != INSIDE); + { + Assert(_openSetTail >= 0); + Assert(_openSet[0].Face != INSIDE); // Find farthest point and first lit face. int farthestPoint = 0; double dist = _openSet[0].Distance; - for (int i = 1; i <= _openSetTail; i++) - { - if (_openSet[i].Distance > dist) - { - farthestPoint = i; - dist = _openSet[i].Distance; - } - } + for (int i = 1; i <= _openSetTail; i++) + { + if (_openSet[i].Distance > dist) + { + farthestPoint = i; + dist = _openSet[i].Distance; + } + } - // Use lit face to find horizon and the rest of the lit - // faces. - FindHorizon( - points, - points[_openSet[farthestPoint].Point], - _openSet[farthestPoint].Face, - _faces[_openSet[farthestPoint].Face]); + // Use lit face to find horizon and the rest of the lit + // faces. + FindHorizon( + points, + points[_openSet[farthestPoint].Point], + _openSet[farthestPoint].Face, + _faces[_openSet[farthestPoint].Face]); - VerifyHorizon(); + VerifyHorizon(); - // Construct new cone from horizon - ConstructCone(points, _openSet[farthestPoint].Point); + // Construct new cone from horizon + ConstructCone(points, _openSet[farthestPoint].Point); - VerifyFaces(points); + VerifyFaces(points); - // Reassign points - ReassignPoints(points); - } + // Reassign points + ReassignPoints(points); + } /// /// Start the search for the horizon. @@ -598,193 +598,193 @@ private void GrowHull(List points) /// visited, the one you came from). /// private void FindHorizon(List points, Point3 point, int fi, Face face) - { - // TODO should I use epsilon in the PointFaceDistance comparisons? + { + // TODO should I use epsilon in the PointFaceDistance comparisons? - _litFaces.Clear(); - _horizon.Clear(); + _litFaces.Clear(); + _horizon.Clear(); - _litFaces.Add(fi); + _litFaces.Add(fi); - Assert(PointFaceDistance(point, points[face.Vertex0], face) > 0.0f); + Assert(PointFaceDistance(point, points[face.Vertex0], face) > 0.0f); - // For the rest of the recursive search calls, we first check if the - // triangle has already been visited and is part of litFaces. - // However, in this first call we can skip that because we know it - // can't possibly have been visited yet, since the only thing in - // litFaces is the current triangle. - { + // For the rest of the recursive search calls, we first check if the + // triangle has already been visited and is part of litFaces. + // However, in this first call we can skip that because we know it + // can't possibly have been visited yet, since the only thing in + // litFaces is the current triangle. + { Face oppositeFace = _faces[face.Opposite0]; double dist = PointFaceDistance( - point, - points[oppositeFace.Vertex0], - oppositeFace); - - if (dist <= 0.0f) - { - _horizon.Add(new HorizonEdge - { - Face = face.Opposite0, - Edge0 = face.Vertex1, - Edge1 = face.Vertex2, - }); - } - else - { - SearchHorizon(points, point, fi, face.Opposite0, oppositeFace); - } - } - - if (!_litFaces.Contains(face.Opposite1)) - { + point, + points[oppositeFace.Vertex0], + oppositeFace); + + if (dist <= 0.0f) + { + _horizon.Add(new HorizonEdge + { + Face = face.Opposite0, + Edge0 = face.Vertex1, + Edge1 = face.Vertex2, + }); + } + else + { + SearchHorizon(points, point, fi, face.Opposite0, oppositeFace); + } + } + + if (!_litFaces.Contains(face.Opposite1)) + { Face oppositeFace = _faces[face.Opposite1]; double dist = PointFaceDistance( - point, - points[oppositeFace.Vertex0], - oppositeFace); - - if (dist <= 0.0f) - { - _horizon.Add(new HorizonEdge - { - Face = face.Opposite1, - Edge0 = face.Vertex2, - Edge1 = face.Vertex0, - }); - } - else - { - SearchHorizon(points, point, fi, face.Opposite1, oppositeFace); - } - } - - if (!_litFaces.Contains(face.Opposite2)) - { + point, + points[oppositeFace.Vertex0], + oppositeFace); + + if (dist <= 0.0f) + { + _horizon.Add(new HorizonEdge + { + Face = face.Opposite1, + Edge0 = face.Vertex2, + Edge1 = face.Vertex0, + }); + } + else + { + SearchHorizon(points, point, fi, face.Opposite1, oppositeFace); + } + } + + if (!_litFaces.Contains(face.Opposite2)) + { Face oppositeFace = _faces[face.Opposite2]; double dist = PointFaceDistance( - point, - points[oppositeFace.Vertex0], - oppositeFace); - - if (dist <= 0.0f) - { - _horizon.Add(new HorizonEdge - { - Face = face.Opposite2, - Edge0 = face.Vertex0, - Edge1 = face.Vertex1, - }); - } - else - { - SearchHorizon(points, point, fi, face.Opposite2, oppositeFace); - } - } - } + point, + points[oppositeFace.Vertex0], + oppositeFace); + + if (dist <= 0.0f) + { + _horizon.Add(new HorizonEdge + { + Face = face.Opposite2, + Edge0 = face.Vertex0, + Edge1 = face.Vertex1, + }); + } + else + { + SearchHorizon(points, point, fi, face.Opposite2, oppositeFace); + } + } + } /// /// Recursively search to find the horizon or lit set. /// private void SearchHorizon(List points, Point3 point, int prevFaceIndex, int faceCount, Face face) - { - Assert(prevFaceIndex >= 0); - Assert(_litFaces.Contains(prevFaceIndex)); - Assert(!_litFaces.Contains(faceCount)); - Assert(_faces[faceCount].Equals(face)); - - _litFaces.Add(faceCount); - - // Use prevFaceIndex to determine what the next face to search will - // be, and what edges we need to cross to get there. It's important - // that the search proceeds in counter-clockwise order from the - // previous face. - int nextFaceIndex0; - int nextFaceIndex1; - int edge0; - int edge1; - int edge2; - - if (prevFaceIndex == face.Opposite0) - { - nextFaceIndex0 = face.Opposite1; - nextFaceIndex1 = face.Opposite2; - - edge0 = face.Vertex2; - edge1 = face.Vertex0; - edge2 = face.Vertex1; - } - else if (prevFaceIndex == face.Opposite1) - { - nextFaceIndex0 = face.Opposite2; - nextFaceIndex1 = face.Opposite0; - - edge0 = face.Vertex0; - edge1 = face.Vertex1; - edge2 = face.Vertex2; - } - else - { - Assert(prevFaceIndex == face.Opposite2); - - nextFaceIndex0 = face.Opposite0; - nextFaceIndex1 = face.Opposite1; - - edge0 = face.Vertex1; - edge1 = face.Vertex2; - edge2 = face.Vertex0; - } - - if (!_litFaces.Contains(nextFaceIndex0)) - { + { + Assert(prevFaceIndex >= 0); + Assert(_litFaces.Contains(prevFaceIndex)); + Assert(!_litFaces.Contains(faceCount)); + Assert(_faces[faceCount].Equals(face)); + + _litFaces.Add(faceCount); + + // Use prevFaceIndex to determine what the next face to search will + // be, and what edges we need to cross to get there. It's important + // that the search proceeds in counter-clockwise order from the + // previous face. + int nextFaceIndex0; + int nextFaceIndex1; + int edge0; + int edge1; + int edge2; + + if (prevFaceIndex == face.Opposite0) + { + nextFaceIndex0 = face.Opposite1; + nextFaceIndex1 = face.Opposite2; + + edge0 = face.Vertex2; + edge1 = face.Vertex0; + edge2 = face.Vertex1; + } + else if (prevFaceIndex == face.Opposite1) + { + nextFaceIndex0 = face.Opposite2; + nextFaceIndex1 = face.Opposite0; + + edge0 = face.Vertex0; + edge1 = face.Vertex1; + edge2 = face.Vertex2; + } + else + { + Assert(prevFaceIndex == face.Opposite2); + + nextFaceIndex0 = face.Opposite0; + nextFaceIndex1 = face.Opposite1; + + edge0 = face.Vertex1; + edge1 = face.Vertex2; + edge2 = face.Vertex0; + } + + if (!_litFaces.Contains(nextFaceIndex0)) + { Face oppositeFace = _faces[nextFaceIndex0]; double dist = PointFaceDistance( - point, - points[oppositeFace.Vertex0], - oppositeFace); - - if (dist <= 0.0f) - { - _horizon.Add(new HorizonEdge - { - Face = nextFaceIndex0, - Edge0 = edge0, - Edge1 = edge1, - }); - } - else - { - SearchHorizon(points, point, faceCount, nextFaceIndex0, oppositeFace); - } - } - - if (!_litFaces.Contains(nextFaceIndex1)) - { + point, + points[oppositeFace.Vertex0], + oppositeFace); + + if (dist <= 0.0f) + { + _horizon.Add(new HorizonEdge + { + Face = nextFaceIndex0, + Edge0 = edge0, + Edge1 = edge1, + }); + } + else + { + SearchHorizon(points, point, faceCount, nextFaceIndex0, oppositeFace); + } + } + + if (!_litFaces.Contains(nextFaceIndex1)) + { Face oppositeFace = _faces[nextFaceIndex1]; double dist = PointFaceDistance( - point, - points[oppositeFace.Vertex0], - oppositeFace); - - if (dist <= 0.0f) - { - _horizon.Add(new HorizonEdge - { - Face = nextFaceIndex1, - Edge0 = edge1, - Edge1 = edge2, - }); - } - else - { - SearchHorizon(points, point, faceCount, nextFaceIndex1, oppositeFace); - } - } - } + point, + points[oppositeFace.Vertex0], + oppositeFace); + + if (dist <= 0.0f) + { + _horizon.Add(new HorizonEdge + { + Face = nextFaceIndex1, + Edge0 = edge1, + Edge1 = edge2, + }); + } + else + { + SearchHorizon(points, point, faceCount, nextFaceIndex1, oppositeFace); + } + } + } /// /// Remove all lit faces and construct new faces from the horizon in a @@ -799,17 +799,17 @@ private void SearchHorizon(List points, Point3 point, int prevFaceIndex, /// the cone. /// private void ConstructCone(List points, int farthestPoint) - { - foreach (int fi in _litFaces) - { - Assert(_faces.ContainsKey(fi)); - _faces.Remove(fi); - } + { + foreach (int fi in _litFaces) + { + Assert(_faces.ContainsKey(fi)); + _faces.Remove(fi); + } int firstNewFace = _faceCount; - for (int i = 0; i < _horizon.Count; i++) - { + for (int i = 0; i < _horizon.Count; i++) + { // Vertices of the new face, the farthest point as well as the // edge on the horizon. Horizon edge is CCW, so the triangle // should be as well. @@ -825,33 +825,33 @@ private void ConstructCone(List points, int farthestPoint) int fi = _faceCount++; - _faces[fi] = new Face( - v0, v1, v2, - o0, o1, o2, - Normal(points[v0], points[v1], points[v2])); + _faces[fi] = new Face( + v0, v1, v2, + o0, o1, o2, + Normal(points[v0], points[v1], points[v2])); Face horizonFace = _faces[_horizon[i].Face]; - if (horizonFace.Vertex0 == v1) - { - Assert(v2 == horizonFace.Vertex2); - horizonFace.Opposite1 = fi; - } - else if (horizonFace.Vertex1 == v1) - { - Assert(v2 == horizonFace.Vertex0); - horizonFace.Opposite2 = fi; - } - else - { - Assert(v1 == horizonFace.Vertex2); - Assert(v2 == horizonFace.Vertex1); - horizonFace.Opposite0 = fi; - } - - _faces[_horizon[i].Face] = horizonFace; - } - } + if (horizonFace.Vertex0 == v1) + { + Assert(v2 == horizonFace.Vertex2); + horizonFace.Opposite1 = fi; + } + else if (horizonFace.Vertex1 == v1) + { + Assert(v2 == horizonFace.Vertex0); + horizonFace.Opposite2 = fi; + } + else + { + Assert(v1 == horizonFace.Vertex2); + Assert(v2 == horizonFace.Vertex1); + horizonFace.Opposite0 = fi; + } + + _faces[_horizon[i].Face] = horizonFace; + } + } /// /// Reassign points based on the new faces added by ConstructCone(). @@ -871,57 +871,57 @@ private void ConstructCone(List points, int farthestPoint) /// a list is pretty darn fast. Still, it might be worth trying /// private void ReassignPoints(List points) - { - for (int i = 0; i <= _openSetTail; i++) - { + { + for (int i = 0; i <= _openSetTail; i++) + { PointFace fp = _openSet[i]; - if (_litFaces.Contains(fp.Face)) - { + if (_litFaces.Contains(fp.Face)) + { bool assigned = false; Vector3 point = points[fp.Point]; - foreach (KeyValuePair kvp in _faces) - { + foreach (KeyValuePair kvp in _faces) + { int fi = kvp.Key; Face face = kvp.Value; double dist = PointFaceDistance( - point, - points[face.Vertex0], - face); - - if (dist > EPSILON) - { - assigned = true; - - fp.Face = fi; - fp.Distance = dist; - - _openSet[i] = fp; - break; - } - } - - if (!assigned) - { - // If point hasn't been assigned, then it's inside the - // convex hull. Swap it with openSetTail, and decrement - // openSetTail. We also have to decrement i, because - // there's now a new thing in openSet[i], so we need i - // to remain the same the next iteration of the loop. - fp.Face = INSIDE; - fp.Distance = double.NaN; - - _openSet[i] = _openSet[_openSetTail]; - _openSet[_openSetTail] = fp; - - i--; - _openSetTail--; - } - } - } - } + point, + points[face.Vertex0], + face); + + if (dist > EPSILON) + { + assigned = true; + + fp.Face = fi; + fp.Distance = dist; + + _openSet[i] = fp; + break; + } + } + + if (!assigned) + { + // If point hasn't been assigned, then it's inside the + // convex hull. Swap it with openSetTail, and decrement + // openSetTail. We also have to decrement i, because + // there's now a new thing in openSet[i], so we need i + // to remain the same the next iteration of the loop. + fp.Face = INSIDE; + fp.Distance = double.NaN; + + _openSet[i] = _openSet[_openSetTail]; + _openSet[_openSetTail] = fp; + + i--; + _openSetTail--; + } + } + } + } /// /// Final step in algorithm, export the faces of the convex hull in a @@ -931,232 +931,232 @@ private void ReassignPoints(List points) /// leaves the normal array empty. /// private void ExportMesh( - List points, - bool splitVerts, - ref List verts, - ref List tris, - ref List normals) - { - if (verts == null) - { - verts = new List(); - } - else - { - verts.Clear(); - } - - if (tris == null) - { - tris = new List(); - } - else - { - tris.Clear(); - } - - if (normals == null) - { - normals = new List(); - } - else - { - normals.Clear(); - } - - foreach (Face face in _faces.Values) - { - int vi0, vi1, vi2; - - if (splitVerts) - { - vi0 = verts.Count; verts.Add(points[face.Vertex0]); - vi1 = verts.Count; verts.Add(points[face.Vertex1]); - vi2 = verts.Count; verts.Add(points[face.Vertex2]); - - normals.Add(face.Normal); - normals.Add(face.Normal); - normals.Add(face.Normal); - } - else - { - if (!_hullVertices.TryGetValue(face.Vertex0, out vi0)) - { - vi0 = verts.Count; - _hullVertices[face.Vertex0] = vi0; - verts.Add(points[face.Vertex0]); - } - - if (!_hullVertices.TryGetValue(face.Vertex1, out vi1)) - { - vi1 = verts.Count; - _hullVertices[face.Vertex1] = vi1; - verts.Add(points[face.Vertex1]); - } - - if (!_hullVertices.TryGetValue(face.Vertex2, out vi2)) - { - vi2 = verts.Count; - _hullVertices[face.Vertex2] = vi2; - verts.Add(points[face.Vertex2]); - } - } - - tris.Add(vi0); - tris.Add(vi1); - tris.Add(vi2); - } - } - - /// - /// Signed distance from face to point (a positive number means that - /// the point is above the face) - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + List points, + bool splitVerts, + ref List verts, + ref List tris, + ref List normals) + { + if (verts == null) + { + verts = new List(); + } + else + { + verts.Clear(); + } + + if (tris == null) + { + tris = new List(); + } + else + { + tris.Clear(); + } + + if (normals == null) + { + normals = new List(); + } + else + { + normals.Clear(); + } + + foreach (Face face in _faces.Values) + { + int vi0, vi1, vi2; + + if (splitVerts) + { + vi0 = verts.Count; verts.Add(points[face.Vertex0]); + vi1 = verts.Count; verts.Add(points[face.Vertex1]); + vi2 = verts.Count; verts.Add(points[face.Vertex2]); + + normals.Add(face.Normal); + normals.Add(face.Normal); + normals.Add(face.Normal); + } + else + { + if (!_hullVertices.TryGetValue(face.Vertex0, out vi0)) + { + vi0 = verts.Count; + _hullVertices[face.Vertex0] = vi0; + verts.Add(points[face.Vertex0]); + } + + if (!_hullVertices.TryGetValue(face.Vertex1, out vi1)) + { + vi1 = verts.Count; + _hullVertices[face.Vertex1] = vi1; + verts.Add(points[face.Vertex1]); + } + + if (!_hullVertices.TryGetValue(face.Vertex2, out vi2)) + { + vi2 = verts.Count; + _hullVertices[face.Vertex2] = vi2; + verts.Add(points[face.Vertex2]); + } + } + + tris.Add(vi0); + tris.Add(vi1); + tris.Add(vi2); + } + } + + /// + /// Signed distance from face to point (a positive number means that + /// the point is above the face) + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] private double PointFaceDistance(Point3 point, Point3 pointOnFace, Face face) - { - return Vector3.DotProduct(face.Normal, point - pointOnFace); - } - - /// - /// Calculate normal for triangle - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + { + return Vector3.DotProduct(face.Normal, point - pointOnFace); + } + + /// + /// Calculate normal for triangle + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] private Vector3 Normal(Point3 v0, Point3 v1, Point3 v2) - { - return Vector3.CrossProduct(v1 - v0, v2 - v0).Unitize(); - } - - /// - /// Method used for debugging, verifies that the openSet is in a - /// sensible state. Conditionally compiled if DEBUG_QUICKHULL if - /// defined. - /// - [Conditional("DEBUG_QUICKHULL")] + { + return Vector3.CrossProduct(v1 - v0, v2 - v0).Unitize(); + } + + /// + /// Method used for debugging, verifies that the openSet is in a + /// sensible state. Conditionally compiled if DEBUG_QUICKHULL if + /// defined. + /// + [Conditional("DEBUG_QUICKHULL")] private void VerifyOpenSet(List points) - { - for (int i = 0; i < _openSet.Count; i++) - { - if (i > _openSetTail) - { - Assert(_openSet[i].Face == INSIDE); - } - else - { - Assert(_openSet[i].Face != INSIDE); - Assert(_openSet[i].Face != UNASSIGNED); - - Assert(PointFaceDistance( - points[_openSet[i].Point], - points[_faces[_openSet[i].Face].Vertex0], - _faces[_openSet[i].Face]) > 0.0f); - } - } - } - - /// - /// Method used for debugging, verifies that the horizon is in a - /// sensible state. Conditionally compiled if DEBUG_QUICKHULL if - /// defined. - /// - [Conditional("DEBUG_QUICKHULL")] + { + for (int i = 0; i < _openSet.Count; i++) + { + if (i > _openSetTail) + { + Assert(_openSet[i].Face == INSIDE); + } + else + { + Assert(_openSet[i].Face != INSIDE); + Assert(_openSet[i].Face != UNASSIGNED); + + Assert(PointFaceDistance( + points[_openSet[i].Point], + points[_faces[_openSet[i].Face].Vertex0], + _faces[_openSet[i].Face]) > 0.0f); + } + } + } + + /// + /// Method used for debugging, verifies that the horizon is in a + /// sensible state. Conditionally compiled if DEBUG_QUICKHULL if + /// defined. + /// + [Conditional("DEBUG_QUICKHULL")] private void VerifyHorizon() - { - for (int i = 0; i < _horizon.Count; i++) - { + { + for (int i = 0; i < _horizon.Count; i++) + { int prev = i == 0 ? _horizon.Count - 1 : i - 1; - Assert(_horizon[prev].Edge1 == _horizon[i].Edge0); - Assert(HasEdge(_faces[_horizon[i].Face], _horizon[i].Edge1, _horizon[i].Edge0)); - } - } - - /// - /// Method used for debugging, verifies that the faces array is in a - /// sensible state. Conditionally compiled if DEBUG_QUICKHULL if - /// defined. - /// - [Conditional("DEBUG_QUICKHULL")] + Assert(_horizon[prev].Edge1 == _horizon[i].Edge0); + Assert(HasEdge(_faces[_horizon[i].Face], _horizon[i].Edge1, _horizon[i].Edge0)); + } + } + + /// + /// Method used for debugging, verifies that the faces array is in a + /// sensible state. Conditionally compiled if DEBUG_QUICKHULL if + /// defined. + /// + [Conditional("DEBUG_QUICKHULL")] private void VerifyFaces(List points) - { - foreach (KeyValuePair kvp in _faces) - { + { + foreach (KeyValuePair kvp in _faces) + { int fi = kvp.Key; Face face = kvp.Value; - Assert(_faces.ContainsKey(face.Opposite0)); - Assert(_faces.ContainsKey(face.Opposite1)); - Assert(_faces.ContainsKey(face.Opposite2)); - - Assert(face.Opposite0 != fi); - Assert(face.Opposite1 != fi); - Assert(face.Opposite2 != fi); - - Assert(face.Vertex0 != face.Vertex1); - Assert(face.Vertex0 != face.Vertex2); - Assert(face.Vertex1 != face.Vertex2); - - Assert(HasEdge(_faces[face.Opposite0], face.Vertex2, face.Vertex1)); - Assert(HasEdge(_faces[face.Opposite1], face.Vertex0, face.Vertex2)); - Assert(HasEdge(_faces[face.Opposite2], face.Vertex1, face.Vertex0)); - - Assert((face.Normal - Normal( - points[face.Vertex0], - points[face.Vertex1], - points[face.Vertex2])).Length < EPSILON); - } - } - - /// - /// Method used for debugging, verifies that the final mesh is - /// actually a convex hull of all the points. Conditionally compiled - /// if DEBUG_QUICKHULL if defined. - /// - [Conditional("DEBUG_QUICKHULL")] + Assert(_faces.ContainsKey(face.Opposite0)); + Assert(_faces.ContainsKey(face.Opposite1)); + Assert(_faces.ContainsKey(face.Opposite2)); + + Assert(face.Opposite0 != fi); + Assert(face.Opposite1 != fi); + Assert(face.Opposite2 != fi); + + Assert(face.Vertex0 != face.Vertex1); + Assert(face.Vertex0 != face.Vertex2); + Assert(face.Vertex1 != face.Vertex2); + + Assert(HasEdge(_faces[face.Opposite0], face.Vertex2, face.Vertex1)); + Assert(HasEdge(_faces[face.Opposite1], face.Vertex0, face.Vertex2)); + Assert(HasEdge(_faces[face.Opposite2], face.Vertex1, face.Vertex0)); + + Assert((face.Normal - Normal( + points[face.Vertex0], + points[face.Vertex1], + points[face.Vertex2])).Length < EPSILON); + } + } + + /// + /// Method used for debugging, verifies that the final mesh is + /// actually a convex hull of all the points. Conditionally compiled + /// if DEBUG_QUICKHULL if defined. + /// + [Conditional("DEBUG_QUICKHULL")] private void VerifyMesh(List points, ref List verts, ref List tris) - { - Assert(tris.Count % 3 == 0); + { + Assert(tris.Count % 3 == 0); - for (int i = 0; i < points.Count; i++) - { - for (int j = 0; j < tris.Count; j += 3) - { + for (int i = 0; i < points.Count; i++) + { + for (int j = 0; j < tris.Count; j += 3) + { Vector3 t0 = verts[tris[j]]; Vector3 t1 = verts[tris[j + 1]]; Vector3 t2 = verts[tris[j + 2]]; - Assert(Vector3.DotProduct(points[i] - t0, Vector3.CrossProduct(t1 - t0, t2 - t0)) <= EPSILON); - } + Assert(Vector3.DotProduct(points[i] - t0, Vector3.CrossProduct(t1 - t0, t2 - t0)) <= EPSILON); + } - } - } + } + } /// /// Does face f have a face with vertexes e0 and e1? Used only for /// debugging. /// private bool HasEdge(Face f, int e0, int e1) - { - return (f.Vertex0 == e0 && f.Vertex1 == e1) - || (f.Vertex1 == e0 && f.Vertex2 == e1) - || (f.Vertex2 == e0 && f.Vertex0 == e1); - } - - /// - /// Assert method, conditionally compiled with DEBUG_QUICKHULL. - /// - /// I could just use Debug.Assert or the Assertions class, but I like - /// the idea of just writing Assert(something), and I also want it to - /// be conditionally compiled out with the same #define as the other - /// debug methods. - /// - [Conditional("DEBUG_QUICKHULL")] + { + return (f.Vertex0 == e0 && f.Vertex1 == e1) + || (f.Vertex1 == e0 && f.Vertex2 == e1) + || (f.Vertex2 == e0 && f.Vertex0 == e1); + } + + /// + /// Assert method, conditionally compiled with DEBUG_QUICKHULL. + /// + /// I could just use Debug.Assert or the Assertions class, but I like + /// the idea of just writing Assert(something), and I also want it to + /// be conditionally compiled out with the same #define as the other + /// debug methods. + /// + [Conditional("DEBUG_QUICKHULL")] private static void Assert(bool condition) - { - if (!condition) - { - throw new Exception("Assertion failed"); - } - } - } + { + if (!condition) + { + throw new Exception("Assertion failed"); + } + } + } } diff --git a/src/GShark/Geometry/Enum/SurfaceDirection.cs b/src/GShark/Geometry/Enum/SurfaceDirection.cs index b1486613..8945a57a 100644 --- a/src/GShark/Geometry/Enum/SurfaceDirection.cs +++ b/src/GShark/Geometry/Enum/SurfaceDirection.cs @@ -10,7 +10,7 @@ public enum SurfaceDirection /// /// The U direction of a surface. /// - U, + U, /// /// The V direction of a surface. diff --git a/src/GShark/Geometry/Interfaces/ICurve.cs b/src/GShark/Geometry/Interfaces/ICurve.cs index 109be5ce..5ef57140 100644 --- a/src/GShark/Geometry/Interfaces/ICurve.cs +++ b/src/GShark/Geometry/Interfaces/ICurve.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; -using GShark.Core; +using GShark.Core; +using System.Collections.Generic; namespace GShark.Geometry.Interfaces { diff --git a/src/GShark/Geometry/Line.cs b/src/GShark/Geometry/Line.cs index 577814de..00ec2b92 100644 --- a/src/GShark/Geometry/Line.cs +++ b/src/GShark/Geometry/Line.cs @@ -20,7 +20,7 @@ public class Line : ICurve, IEquatable, ITransformable /// End point. public Line(Point3 start, Point3 end) { - if(start == end || !start.IsValid || !end.IsValid) + if (start == end || !start.IsValid || !end.IsValid) { throw new Exception("Start or end point is not valid, or they are equal"); } @@ -39,7 +39,7 @@ public Line(Point3 start, Point3 end) /// Length of the line. public Line(Point3 start, Vector3 direction, double length) { - if(length <= GeoSharkMath.Epsilon) + if (length <= GeoSharkMath.Epsilon) { throw new Exception("Length must be bigger than zero"); } @@ -72,11 +72,11 @@ public Line(Point3 start, Vector3 direction, double length) public int Degree => 1; - public List LocationPoints => new List{Start, End}; + public List LocationPoints => new List { Start, End }; - public List ControlPoints => LinearAlgebra.PointsHomogeniser(LocationPoints, 1.0); + public List ControlPoints => Point4.PointsHomogeniser(LocationPoints, 1.0); - public KnotVector Knots => new KnotVector {0, 0, 1, 1}; + public KnotVector Knots => new KnotVector { 0, 0, 1, 1 }; public Interval Domain => new Interval(0.0, 1.0); diff --git a/src/GShark/Geometry/NurbsCurve.cs b/src/GShark/Geometry/NurbsCurve.cs index f306ef02..7653d568 100644 --- a/src/GShark/Geometry/NurbsCurve.cs +++ b/src/GShark/Geometry/NurbsCurve.cs @@ -53,10 +53,10 @@ internal NurbsCurve(int degree, KnotVector knots, List controlPoints) throw new ArgumentException("Invalid knot format! Should begin with degree + 1 repeats and end with degree + 1 repeats!"); } - Weights = LinearAlgebra.GetWeights(controlPoints); + Weights = Point4.GetWeights(controlPoints); Degree = degree; Knots = knots; - LocationPoints = LinearAlgebra.PointDehomogenizer1d(controlPoints); + LocationPoints = Point4.PointDehomogenizer1d(controlPoints); ControlPoints = controlPoints; } @@ -235,7 +235,7 @@ public NurbsCurve Reverse() /// The closest point on the curve. public Point3 ClosestPoint(Point3 point) { - return LinearAlgebra.PointDehomogenizer(Analyze.CurveClosestPoint(this, point, out _)); + return Point4.PointDehomogenizer(Analyze.CurveClosestPoint(this, point, out _)); } /// diff --git a/src/GShark/Geometry/NurbsSurface.cs b/src/GShark/Geometry/NurbsSurface.cs index 50264e02..693cf95b 100644 --- a/src/GShark/Geometry/NurbsSurface.cs +++ b/src/GShark/Geometry/NurbsSurface.cs @@ -45,8 +45,8 @@ internal NurbsSurface(int degreeU, int degreeV, KnotVector knotsU, KnotVector kn DegreeV = degreeV; KnotsU = (Math.Abs(knotsU.Domain - 1.0) > GeoSharkMath.Epsilon) ? knotsU.Normalize() : knotsU; KnotsV = (Math.Abs(knotsV.Domain - 1.0) > GeoSharkMath.Epsilon) ? knotsV.Normalize() : knotsV; - Weights = LinearAlgebra.GetWeights2d(controlPts); - LocationPoints = LinearAlgebra.PointDehomogenizer2d(controlPts); + Weights = Point4.GetWeights2d(controlPts); + LocationPoints = Point4.PointDehomogenizer2d(controlPts); ControlPoints = controlPts; DomainU = new Interval(this.KnotsU.First(), this.KnotsU.Last()); DomainV = new Interval(this.KnotsV.First(), this.KnotsV.Last()); diff --git a/src/GShark/Geometry/Plane.cs b/src/GShark/Geometry/Plane.cs index aa18b281..7b159e39 100644 --- a/src/GShark/Geometry/Plane.cs +++ b/src/GShark/Geometry/Plane.cs @@ -37,7 +37,7 @@ public Plane(Point3 origin, Vector3 direction) /// Third point representing the y direction. public Plane(Point3 pt1, Point3 pt2, Point3 pt3) { - if(Trigonometry.ArePointsCollinear(pt1, pt2, pt3)) + if (Trigonometry.ArePointsCollinear(pt1, pt2, pt3)) { throw new Exception("Plane cannot be created, the tree points must not be collinear"); } @@ -129,7 +129,7 @@ public bool IsValid var areAxesOrthogonal = Vector3.DotProduct(XAxis, YAxis) == 0 && Vector3.DotProduct(YAxis, ZAxis) == 0; if (areAxesValid && areAxesOrthogonal) return true; - + return false; } } @@ -199,7 +199,7 @@ public Plane Flip() { var xAxis = YAxis; var yAxis = XAxis; - return new Plane(Origin, xAxis, yAxis); + return new Plane(Origin, xAxis, yAxis); } /// @@ -250,7 +250,7 @@ public static Plane FitPlane(IList pts, out double deviation) double determinantMax = Math.Max(determinantX, Math.Max(determinantY, determinantZ)); - if(determinantMax <= 0.0) + if (determinantMax <= 0.0) { throw new Exception("The points don't span a plane."); } @@ -309,8 +309,8 @@ public Plane Transform(Transform transformation) { Point3 transformedOrigin = Origin.Transform(transformation); - var xDir = (Origin + XAxis).Transform(transformation) - transformedOrigin; - var yDir = (Origin + YAxis).Transform(transformation) - transformedOrigin; + var xDir = (Origin + XAxis).Transform(transformation) - transformedOrigin; + var yDir = (Origin + YAxis).Transform(transformation) - transformedOrigin; return new Plane(transformedOrigin, xDir, yDir); } diff --git a/src/GShark/Geometry/Point3.cs b/src/GShark/Geometry/Point3.cs index 572bdd89..511ffbe7 100644 --- a/src/GShark/Geometry/Point3.cs +++ b/src/GShark/Geometry/Point3.cs @@ -1,11 +1,6 @@ -using System; +using GShark.Core; +using System; using System.Collections.Generic; -using System.Linq; -using System.Runtime.Serialization; -using System.Security.Permissions; -using System.Text; -using System.Threading.Tasks; -using GShark.Core; namespace GShark.Geometry { @@ -53,7 +48,7 @@ public Point3(Point3 point) : this(point.X, point.Y, point.Z) public Point3(Point4 point) { double w = (Math.Abs(point.W - 1.0) > GeoSharkMath.Epsilon && point.W != 0.0) ? 1.0 / point.W : 1.0; - + X = point.X * w; Y = point.Y * w; Z = point.Z * w; @@ -192,7 +187,7 @@ public static Point3 Add(Vector3 vector, Point3 point) /// true if the coordinates of the two points are exactly equal; otherwise false. public static bool operator ==(Point3 a, Point3 b) { - return (a.X == b.X && a.Y == b.Y && a.Z == b.Z); + return (a.X == b.X && a.Y == b.Y && a.Z == b.Z); } /// @@ -233,7 +228,7 @@ public static Point3 Add(Vector3 vector, Point3 point) /// The resulting Vector. public static implicit operator Vector(Point3 point) { - return new Vector{ point.X, point.Y, point.Z}; + return new Vector { point.X, point.Y, point.Z }; } /// diff --git a/src/GShark/Geometry/Point4.cs b/src/GShark/Geometry/Point4.cs index eb1270f8..1c874545 100644 --- a/src/GShark/Geometry/Point4.cs +++ b/src/GShark/Geometry/Point4.cs @@ -1,5 +1,7 @@ using GShark.Core; using System; +using System.Collections.Generic; +using System.Linq; namespace GShark.Geometry { @@ -308,6 +310,188 @@ public static Point4 WeightedSubtraction(Point4 point1, Point4 point2) return new Vector { point4.X, point4.Y, point4.Z, point4.W }; } + /// + /// Transforms a collection of points into their homogeneous equivalents.
+ /// http://deltaorange.com/2012/03/08/the-truth-behind-homogenous-coordinates/ + ///
+ /// Control points, a set of size (points count x points dimension). + /// Control point weights, the same size as the set of control points (points count x 1). + /// A set of control points where each point is (wi*pi, wi)
+ /// where wi the ith control point weight and pi is the ith control point, hence the dimension of the point is dim + 1.
+ public static List PointsHomogeniser(List controlPoints, List weights) + { + if (controlPoints.Count < weights.Count) + { + throw new ArgumentOutOfRangeException(nameof(weights), + "The weights set is bigger than the control points, it must be the same dimension"); + } + + if (controlPoints.Count > weights.Count) + { + int diff = controlPoints.Count - weights.Count; + List dataFilled = Sets.RepeatData(1.0, diff); + weights.AddRange(dataFilled); + } + + List controlPtsHomogenized = new List(); + + for (int i = 0; i < controlPoints.Count; i++) + { + Point4 tempPt = new Point4 + { + X = controlPoints[i].X * weights[i], + Y = controlPoints[i].Y * weights[i], + Z = controlPoints[i].Z * weights[i], + W = weights[i] + }; + + + controlPtsHomogenized.Add(tempPt); + } + + return controlPtsHomogenized; + } + + /// + /// Transforms a collection of points into their homogeneous equivalents, by a given weight value.
+ /// http://deltaorange.com/2012/03/08/the-truth-behind-homogenous-coordinates/ + ///
+ /// Control points, a set of size (points count x points dimension). + /// Weight value for each point. + /// A set of control points where each point is (wi*pi, wi)
+ /// where wi the ith control point weight and pi is the ith control point, hence the dimension of the point is dim + 1.
+ public static List PointsHomogeniser(List controlPoints, double weight) + { + List controlPtsHomogenized = new List(); + + foreach (var pt in controlPoints) + { + Point4 tempPt = new Point4 + { + X = pt.X * weight, + Y = pt.Y * weight, + Z = pt.Z * weight, + W = weight + }; + + controlPtsHomogenized.Add(tempPt); + } + + return controlPtsHomogenized; + } + + /// + /// Transforms a two-dimension collection of points into their homogeneous equivalents.
+ /// http://deltaorange.com/2012/03/08/the-truth-behind-homogenous-coordinates/ + ///
+ /// Control points, a two-dimensional set of size (points count x points dimension). + /// Control point weights, the same size as the set of control points (points count x 1). + /// A two-dimensional set of control points where each point is (wi*pi, wi)
+ /// where wi the ith control point weight and pi is the ith control point, hence the dimension of the point is dim + 1.
+ public static List> PointsHomogeniser2d(List> controlPoints, List> weights = null) + { + int rows = controlPoints.Count; + List> controlPtsHomogenized = new List>(); + List> usedWeights = weights; + if (weights == null || weights.Count == 0) + { + usedWeights = new List>(); + for (int i = 0; i < rows; i++) + { + usedWeights.Add(Sets.RepeatData(1.0, controlPoints[i].Count)); + } + } + if (controlPoints.Count < usedWeights.Count) + { + throw new ArgumentOutOfRangeException(nameof(weights), "The weights set is bigger than the control points, it must be the same dimension"); + } + + for (int i = 0; i < rows; i++) + { + controlPtsHomogenized.Add(PointsHomogeniser(controlPoints[i], usedWeights[i])); + } + + return controlPtsHomogenized; + } + + /// + /// Obtains the weight from a collection of points in homogeneous space, assuming all are the same dimension. + /// + /// Points represented by an array (wi*pi, wi) with length (dim+1). + /// A set of values, represented by a set pi with length (dim). + public static List GetWeights(List homogenizedPoints) + { + return homogenizedPoints.Select(pt => pt.W).ToList(); + } + + /// + /// Obtains the weight from a two-dimensional collection of points in homogeneous space, assuming all are the same dimension. + /// + /// Two-dimensional set of points represented by an array (wi*pi, wi) with length (dim+1) + /// Two-dimensional set of values, each represented by an array pi with length (dim) + public static List> GetWeights2d(List> homogenizedPoints) + { + return homogenizedPoints.Select(pts => GetWeights(pts).ToList()).ToList(); + } + + /// + /// Gets a dehomogenized point from a homogenized curve point. + /// + /// A point represented by an array (wi*pi, wi) with length (dim+1). + /// A dehomogenized point. + public static Point3 PointDehomogenizer(Point4 homogenizedCurvePoint) + { + Point3 point = new Point3 + { + X = homogenizedCurvePoint.X / homogenizedCurvePoint.W, + Y = homogenizedCurvePoint.Y / homogenizedCurvePoint.W, + Z = homogenizedCurvePoint.Z / homogenizedCurvePoint.W + }; + + return point; + } + + /// + /// Gets a set of dehomogenized points. + /// + /// A collection of points represented by an array (wi*pi, wi) with length (dim+1). + /// Set of dehomogenized points. + public static List PointDehomogenizer1d(List homogenizedPoints) + { + return homogenizedPoints.Select(PointDehomogenizer).ToList(); + } + + /// + /// Gets a two-dimensional set of dehomogenized points. + /// + /// Two-dimensional set of points represented by an array (wi*pi, wi) with length (dim+1) + /// Two-dimensional set of dehomogenized points. + public static List> PointDehomogenizer2d(List> homogenizedPoints) + { + return homogenizedPoints.Select(PointDehomogenizer1d).ToList(); + } + + /// + /// Obtains the point from homogeneous point without dehomogenization, assuming all are the same length. + /// + /// Sets of points represented by an array (wi*pi, wi) with length (dim+1). + /// Set of rational points. + public static List RationalPoints(List homogenizedPoints) + { + + return homogenizedPoints.Select(pt => new Point3(pt.X, pt.Y, pt.Z)).ToList(); + } + + /// + /// Obtains the point from a two-dimensional set of homogeneous points without dehomogenization, assuming all are the same length. + /// + /// Two-dimensional set of points represented by an array (wi*pi, wi) with length (dim+1) + /// Two-dimensional set of rational points. + public static List> Rational2d(List> homogenizedPoints) + { + return homogenizedPoints.Select(hpts => RationalPoints(hpts)).ToList(); + } + /// /// Determines whether the specified System.Object is Point4d and has same coordinates as the present point. /// diff --git a/src/GShark/Geometry/Polygon.cs b/src/GShark/Geometry/Polygon.cs index b4c76338..84ba6dca 100644 --- a/src/GShark/Geometry/Polygon.cs +++ b/src/GShark/Geometry/Polygon.cs @@ -154,7 +154,7 @@ public static Polygon RegularPolygon(Plane plane, double radius, int numberOfSeg throw new Exception("Polygon radius cannot be less or equal zero."); } Point3[] pts = new Point3[numberOfSegments + 1]; - double t = 2.0 * Math.PI / (double) numberOfSegments; + double t = 2.0 * Math.PI / (double)numberOfSegments; for (int i = 0; i < numberOfSegments; i++) { var ty = Math.Sin(t * i) * radius; diff --git a/src/GShark/Geometry/Polyline.cs b/src/GShark/Geometry/Polyline.cs index a44b5ee5..eda532d8 100644 --- a/src/GShark/Geometry/Polyline.cs +++ b/src/GShark/Geometry/Polyline.cs @@ -299,7 +299,7 @@ protected void ToNurbsCurve() knots.Add(lengthSum - 1); Knots = knots; - ControlPoints = LinearAlgebra.PointsHomogeniser(this, weights); + ControlPoints = Point4.PointsHomogeniser(this, weights); } /// diff --git a/src/GShark/Geometry/Vector.cs b/src/GShark/Geometry/Vector.cs index 91ab1e95..5fe4401b 100644 --- a/src/GShark/Geometry/Vector.cs +++ b/src/GShark/Geometry/Vector.cs @@ -290,7 +290,7 @@ public bool Equals(Vector other) { if (!(Math.Abs(this[i] - other[i]) <= GeoSharkMath.Epsilon)) return false; } - + return true; } diff --git a/src/GShark/Geometry/Vector3.cs b/src/GShark/Geometry/Vector3.cs index f782bb90..a1ee7034 100644 --- a/src/GShark/Geometry/Vector3.cs +++ b/src/GShark/Geometry/Vector3.cs @@ -41,7 +41,7 @@ public Vector3(Vector3 vector) : this(vector.X, vector.Y, vector.Z) /// /// Gets the value of the vector with components 0,0,0. /// - public static Vector3 Zero => new Vector3(0,0,0); + public static Vector3 Zero => new Vector3(0, 0, 0); /// /// Gets the value of the vector with components 1,0,0. @@ -172,7 +172,7 @@ public Vector3(Vector3 vector) : this(vector.X, vector.Y, vector.Z) /// The resulting Vector3. public static implicit operator Vector(Vector3 vector3d) { - return new Vector{vector3d.X, vector3d.Y, vector3d.Z}; + return new Vector { vector3d.X, vector3d.Y, vector3d.Z }; } /// @@ -216,7 +216,7 @@ public static double VectorAngle(Vector3 a, Vector3 b) //compute dot product double dot = DotProduct(a.Unitize(), b.Unitize()); - + if (dot > 1.0) { dot = 1.0; @@ -242,17 +242,17 @@ public static double VectorAngle(Vector3 a, Vector3 b) public static double VectorAngleOnPlane(Vector3 a, Vector3 b, Plane plane, out double reflexAngle) { // Project vectors onto plane. - var pA = plane.Origin + a; - var pB = plane.Origin + b; + var pA = plane.Origin + a; + var pB = plane.Origin + b; + + pA = plane.ClosestPoint(pA, out _); + pB = plane.ClosestPoint(pB, out _); - pA = plane.ClosestPoint(pA, out _); - pB = plane.ClosestPoint(pB, out _); + a = pA - plane.Origin; + b = pB - plane.Origin; + a = a.Unitize(); + b = b.Unitize(); - a = pA - plane.Origin; - b = pB - plane.Origin; - a = a.Unitize(); - b = b.Unitize(); - // Abort on invalid cases. if (a == Unset || b == Unset) @@ -262,14 +262,14 @@ public static double VectorAngleOnPlane(Vector3 a, Vector3 b, Plane plane, out d } double dot = a * b; - // Limit dot product to valid range. - if (dot >= 1.0) - { dot = 1.0; } - else if (dot < -1.0) - { dot = -1.0; } - + // Limit dot product to valid range. + if (dot >= 1.0) + { dot = 1.0; } + else if (dot < -1.0) + { dot = -1.0; } + double angle = Math.Acos(dot); - // Special case (anti)parallel vectors. + // Special case (anti)parallel vectors. if (Math.Abs(angle) < 1e-64) { reflexAngle = 0; @@ -284,7 +284,7 @@ public static double VectorAngleOnPlane(Vector3 a, Vector3 b, Plane plane, out d if (angle > Math.PI) { - reflexAngle = angle ; + reflexAngle = angle; return 2 * Math.PI - angle; } @@ -734,75 +734,75 @@ public bool IsPerpendicularTo(Vector3 other, double angleTolerance = GeoSharkMat /// The other vector. /// The perpendicular vector. public static Vector3 PerpendicularTo(Vector3 vector) + { + double[] vectorComponents = { vector.X, vector.Y, vector.Z }; + double[] tempVector = new double[3]; + int i, j, k; + double a, b; + if (Math.Abs(vectorComponents[1]) > Math.Abs(vectorComponents[0])) { - double[] vectorComponents = {vector.X, vector.Y, vector.Z}; - double[] tempVector = new double[3]; - int i, j, k; - double a, b; - if (Math.Abs(vectorComponents[1]) > Math.Abs(vectorComponents[0])) - { - if (Math.Abs(vectorComponents[2]) > Math.Abs(vectorComponents[1])) - { - // |v.z| > |v.y| > |v.x| - i = 2; - j = 1; - k = 0; - a = vectorComponents[2]; - b = -vectorComponents[1]; - } - else if (Math.Abs(vectorComponents[2]) > Math.Abs(vectorComponents[0])) - { - // |v.y| >= |v.z| >= |v.x| - i = 1; - j = 2; - k = 0; - a = vectorComponents[1]; - b = -vectorComponents[2]; - } - else - { - // |v.y| > |v.x| > |v.z| - i = 1; - j = 0; - k = 2; - a = vectorComponents[1]; - b = -vectorComponents[0]; - } - } - else if (Math.Abs(vectorComponents[2]) > Math.Abs(vectorComponents[0])) + if (Math.Abs(vectorComponents[2]) > Math.Abs(vectorComponents[1])) { - // |v.z| > |v.x| >= |v.y| + // |v.z| > |v.y| > |v.x| i = 2; - j = 0; - k = 1; + j = 1; + k = 0; a = vectorComponents[2]; - b = -vectorComponents[0]; + b = -vectorComponents[1]; } - else if (Math.Abs(vectorComponents[2]) > Math.Abs(vectorComponents[1])) + else if (Math.Abs(vectorComponents[2]) > Math.Abs(vectorComponents[0])) { - // |v.x| >= |v.z| > |v.y| - i = 0; + // |v.y| >= |v.z| >= |v.x| + i = 1; j = 2; - k = 1; - a = vectorComponents[0]; + k = 0; + a = vectorComponents[1]; b = -vectorComponents[2]; } else { - // |v.x| >= |v.y| >= |v.z| - i = 0; - j = 1; + // |v.y| > |v.x| > |v.z| + i = 1; + j = 0; k = 2; - a = vectorComponents[0]; - b = -vectorComponents[1]; + a = vectorComponents[1]; + b = -vectorComponents[0]; } + } + else if (Math.Abs(vectorComponents[2]) > Math.Abs(vectorComponents[0])) + { + // |v.z| > |v.x| >= |v.y| + i = 2; + j = 0; + k = 1; + a = vectorComponents[2]; + b = -vectorComponents[0]; + } + else if (Math.Abs(vectorComponents[2]) > Math.Abs(vectorComponents[1])) + { + // |v.x| >= |v.z| > |v.y| + i = 0; + j = 2; + k = 1; + a = vectorComponents[0]; + b = -vectorComponents[2]; + } + else + { + // |v.x| >= |v.y| >= |v.z| + i = 0; + j = 1; + k = 2; + a = vectorComponents[0]; + b = -vectorComponents[1]; + } - tempVector[i] = b; - tempVector[j] = a; - tempVector[k] = 0.0; + tempVector[i] = b; + tempVector[j] = a; + tempVector[k] = 0.0; - return new Vector3(tempVector[0], tempVector[1], tempVector[2]); - } + return new Vector3(tempVector[0], tempVector[1], tempVector[2]); + } /// /// Computes the perpendicular of a vector given three points.
diff --git a/src/GShark/Operation/Divide.cs b/src/GShark/Operation/Divide.cs index a1818cdb..13640f65 100644 --- a/src/GShark/Operation/Divide.cs +++ b/src/GShark/Operation/Divide.cs @@ -86,34 +86,34 @@ internal static NurbsSurface[] SplitSurface(NurbsSurface surface, double paramet switch (direction) { case SplitDirection.U: - { - surfaceResult = new NurbsSurface[] { + surfaceResult = new NurbsSurface[] + { new NurbsSurface(degree, surface.DegreeV, knotLeft, surface.KnotsV.Copy(), Sets.Reverse2DMatrixData(surfPtsLeft)), new NurbsSurface(degree, surface.DegreeV, knotRight, surface.KnotsV.Copy(), Sets.Reverse2DMatrixData(surfPtsRight)) - }; - break; - } + }; + break; + } case SplitDirection.V: - { - surfaceResult = new NurbsSurface[] { + surfaceResult = new NurbsSurface[] + { new NurbsSurface(surface.DegreeU, degree, surface.KnotsU.Copy(), knotLeft, surfPtsLeft), new NurbsSurface(surface.DegreeU, degree, surface.KnotsU.Copy(), knotRight, surfPtsRight) - }; - break; - } + }; + break; + } case SplitDirection.Both: - { - NurbsSurface srf1 = new NurbsSurface(degree, surface.DegreeV, knotLeft, surface.KnotsV.Copy(), Sets.Reverse2DMatrixData(surfPtsLeft)); - NurbsSurface srf2 = new NurbsSurface(degree, surface.DegreeV, knotRight, surface.KnotsV.Copy(), Sets.Reverse2DMatrixData(surfPtsRight)); + { + NurbsSurface srf1 = new NurbsSurface(degree, surface.DegreeV, knotLeft, surface.KnotsV.Copy(), Sets.Reverse2DMatrixData(surfPtsLeft)); + NurbsSurface srf2 = new NurbsSurface(degree, surface.DegreeV, knotRight, surface.KnotsV.Copy(), Sets.Reverse2DMatrixData(surfPtsRight)); - NurbsSurface[] split1 = SplitSurface(srf1, parameter, SplitDirection.V); - NurbsSurface[] split2 = SplitSurface(srf2, parameter, SplitDirection.V); + NurbsSurface[] split1 = SplitSurface(srf1, parameter, SplitDirection.V); + NurbsSurface[] split2 = SplitSurface(srf2, parameter, SplitDirection.V); - surfaceResult = split2.Concat(split1).ToArray(); - break; - } + surfaceResult = split2.Concat(split1).ToArray(); + break; + } } return surfaceResult; diff --git a/src/GShark/Operation/Evaluation.cs b/src/GShark/Operation/Evaluation.cs index f16230ce..c4e30e4c 100644 --- a/src/GShark/Operation/Evaluation.cs +++ b/src/GShark/Operation/Evaluation.cs @@ -375,9 +375,9 @@ public static List RationalCurveDerivatives(ICurve curve, double parame // Where A(t) is the vector - valued function whose coordinates are the first three coordinates // of an homogenized pts. // Correspond in the book to Aders. - List rationalDerivativePoints = LinearAlgebra.RationalPoints(derivatives); + List rationalDerivativePoints = Point4.RationalPoints(derivatives); // Correspond in the book to wDers. - List weightDers = LinearAlgebra.GetWeights(derivatives); + List weightDers = Point4.GetWeights(derivatives); List CK = new List(); for (int k = 0; k < numberOfDerivatives + 1; k++) @@ -592,7 +592,7 @@ public static List CurveDerivatives(ICurve curve, double parameter, int { for (int l = 0; l < numDerivs - k + 1; l++) { - Vector3 t = derivatives.Item1[k,l]; + Vector3 t = derivatives.Item1[k, l]; for (int j = 1; j < l + 1; j++) { t -= SKL[k, l - j] * (LinearAlgebra.GetBinomial(l, j) * derivatives.Item2[0, j]); @@ -604,7 +604,7 @@ public static List CurveDerivatives(ICurve curve, double parameter, int Vector3 t2 = Vector3.Zero; for (int j = 1; j < l + 1; j++) { - t2 += SKL[k - i,l - j] * (LinearAlgebra.GetBinomial(l, j) * derivatives.Item2[i, j]); + t2 += SKL[k - i, l - j] * (LinearAlgebra.GetBinomial(l, j) * derivatives.Item2[i, j]); } t -= t2 * LinearAlgebra.GetBinomial(k, i); diff --git a/src/GShark/Operation/Fitting.cs b/src/GShark/Operation/Fitting.cs index bcf6b98a..613c12d7 100644 --- a/src/GShark/Operation/Fitting.cs +++ b/src/GShark/Operation/Fitting.cs @@ -3,7 +3,6 @@ using GShark.Geometry; using System; using System.Collections.Generic; -using System.Drawing; using System.Linq; namespace GShark.Operation @@ -266,14 +265,14 @@ private static List SolveCtrlPtsWithTangents(KnotVector knots, List pt[i])); // Equations 9.12 b.Add(endTangent[i] * mult1); b.Add(pts[pts.Count - 1][i]); - + Vector solution = Matrix.Solve(matrixLu, permutation, b); ptsSolved.Add(solution); } diff --git a/src/GShark/Operation/Offset.cs b/src/GShark/Operation/Offset.cs index 63ec4179..71a32880 100644 --- a/src/GShark/Operation/Offset.cs +++ b/src/GShark/Operation/Offset.cs @@ -100,7 +100,7 @@ public static Polyline Polyline(Polyline poly, double distance, Plane pln) continue; } - Intersection: + Intersection: bool ccx = Intersect.LineLine(offsetSegments[(i == iteration - 1 && poly.IsClosed) ? iteration - 2 : k - 1], offsetSegments[k], out Point3 pt, out _, out _, out _); if (!ccx) continue; offsetPts[k] = pt; diff --git a/src/GShark/Operation/Tessellation.cs b/src/GShark/Operation/Tessellation.cs index 44f09c0a..2e022889 100644 --- a/src/GShark/Operation/Tessellation.cs +++ b/src/GShark/Operation/Tessellation.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Threading; namespace GShark.Operation { @@ -85,9 +84,9 @@ public static (List tValues, List pts) CurveAdaptiveSampleRange( double t = 0.5 + 0.2 * random.NextDouble(); double mid = start + (end - start) * t; - Point3 pt1 = LinearAlgebra.PointDehomogenizer(Evaluation.CurvePointAt(curve, start)); - Point3 pt2 = LinearAlgebra.PointDehomogenizer(Evaluation.CurvePointAt(curve, mid)); - Point3 pt3 = LinearAlgebra.PointDehomogenizer(Evaluation.CurvePointAt(curve, end)); + Point3 pt1 = Point4.PointDehomogenizer(Evaluation.CurvePointAt(curve, start)); + Point3 pt2 = Point4.PointDehomogenizer(Evaluation.CurvePointAt(curve, mid)); + Point3 pt3 = Point4.PointDehomogenizer(Evaluation.CurvePointAt(curve, end)); Vector3 diff = pt1 - pt3; Vector3 diff2 = pt1 - pt2; diff --git a/src/GShark/Operation/Utilities/Extrema.cs b/src/GShark/Operation/Utilities/Extrema.cs index 4b35721b..c2acdd04 100644 --- a/src/GShark/Operation/Utilities/Extrema.cs +++ b/src/GShark/Operation/Utilities/Extrema.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Runtime.InteropServices.ComTypes; namespace GShark.Operation.Utilities { diff --git a/src/GShark/Optimization/CurvePlaneIntersectionObjectives.cs b/src/GShark/Optimization/CurvePlaneIntersectionObjectives.cs index cd70886c..ea44712f 100644 --- a/src/GShark/Optimization/CurvePlaneIntersectionObjectives.cs +++ b/src/GShark/Optimization/CurvePlaneIntersectionObjectives.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using GShark.Geometry; +using GShark.Geometry; using GShark.Geometry.Interfaces; using GShark.Operation; @@ -45,7 +44,7 @@ public Vector Gradient(Vector v) double value0 = 2 * (f / df); - return new Vector{value0, value0}; + return new Vector { value0, value0 }; } } } diff --git a/src/GShark/Optimization/Minimizer.cs b/src/GShark/Optimization/Minimizer.cs index ad86e715..fc266b7c 100644 --- a/src/GShark/Optimization/Minimizer.cs +++ b/src/GShark/Optimization/Minimizer.cs @@ -1,7 +1,7 @@ using GShark.Core; +using GShark.Geometry; using System; using System.Linq; -using GShark.Geometry; namespace GShark.Optimization {