public void It_Returns_A_Vector_Rotated_By_An_Angle() { // Arrange Vector3 vector = new Vector3(-7, 10, -5); double rotationAngle1 = GSharkMath.ToRadians(-0.0000125); Vector3 expectedResult1 = new Vector3(-7.0, 10.0, -5.0); double rotationAngle2 = GSharkMath.ToRadians(0.0); Vector3 expectedResult2 = new Vector3(-7.0, 10.0, -5.0); double rotationAngle3 = GSharkMath.ToRadians(12.5); Vector3 expectedResult3 = new Vector3(-7.454672, 10.649531, -2.239498); double rotationAngle4 = GSharkMath.ToRadians(450); Vector3 expectedResult4 = new Vector3(-2.867312, 4.09616, 12.206556); Vector3 axis = new Vector3(10, 7, 0); // Act Vector3 result1 = vector.Rotate(axis, rotationAngle1); Vector3 result2 = vector.Rotate(axis, rotationAngle2); Vector3 result3 = vector.Rotate(axis, rotationAngle3); Vector3 result4 = vector.Rotate(axis, rotationAngle4); // Assert result1.EpsilonEquals(expectedResult1, 1e-6).Should().Be(true); result2.EpsilonEquals(expectedResult2, 1e-6).Should().Be(true); result3.EpsilonEquals(expectedResult3, 1e-6).Should().Be(true); result4.EpsilonEquals(expectedResult4, 1e-6).Should().Be(true); }
public void It_Returns_A_Binomial_Coefficient(int n, int k, double resultValue) { // Act double valToCheck = GSharkMath.GetBinomial(n, k); // Assert (System.Math.Abs(valToCheck - resultValue) < GSharkMath.Epsilon).Should().BeTrue(); }
public void Initializes_An_Arc_By_Three_Points() { // Arrange Arc arc = _exampleArc3D; // Assert arc.Length.Should().BeApproximately(71.333203, GSharkMath.MaxTolerance); arc.Radius.Should().BeApproximately(16.47719, GSharkMath.MaxTolerance); GSharkMath.ToDegrees(arc.Angle).Should().BeApproximately(248.045414, GSharkMath.MaxTolerance); }
public void It_Returns_A_Rotated_Plane() { // Arrange Plane plane = BasePlaneByPoints; // Act Plane rotatedPlane = plane.Rotate(GSharkMath.ToRadians(30)); // Assert rotatedPlane.XAxis.EpsilonEquals(new Vector3(-0.965926, -0.258819, 0), GSharkMath.MaxTolerance).Should().BeTrue(); rotatedPlane.YAxis.EpsilonEquals(new Vector3(-0.258819, 0.965926, 0), GSharkMath.MaxTolerance).Should().BeTrue(); rotatedPlane.ZAxis.EpsilonEquals(new Vector3(0, 0, -1), GSharkMath.MaxTolerance).Should().BeTrue(); }
public void It_Returns_The_Point_On_The_Circle_At_The_Give_Length(double length, double[] pts) { // Arrange Point3 expectedPt = new Point3(pts[0], pts[1], pts[2]); // Act double normalizeLength = GSharkMath.RemapValue(length, new Interval(0.0, _circle2D.Length), new Interval(0.0, 1.0)); Point3 pt = _circle2D.PointAtLength(length); Point3 ptNormalizedLength = _circle2D.PointAtNormalizedLength(normalizeLength); // Assert pt.EpsilonEquals(expectedPt, GSharkMath.MaxTolerance).Should().BeTrue(); pt.EpsilonEquals(ptNormalizedLength, GSharkMath.MaxTolerance).Should().BeTrue(); }
public ArcTests(ITestOutputHelper testOutput) { _testOutput = testOutput; #region example // Initializes an arc by plane, radius and angle. double angle = GSharkMath.ToRadians(40); _exampleArc2D = new Arc(Plane.PlaneXY, 15, angle); // Initializes an arc by 3 points. Point3 pt1 = new Point3(74.264416, 36.39316, -1.884313); Point3 pt2 = new Point3(97.679126, 13.940616, 3.812853); Point3 pt3 = new Point3(100.92443, 30.599893, -0.585116); _exampleArc3D = new Arc(pt1, pt2, pt3); #endregion }
public void It_Creates_An_Aligned_BoundingBox() { // Arrange Plane orientedPlane = Plane.PlaneXY.Rotate(GSharkMath.ToRadians(30)); 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); // Assert _testOutput.WriteLine(bBox.ToString()); bBox.Should().NotBeNull(); bBox.Min.DistanceTo(expectedMin).Should().BeLessThan(GSharkMath.MaxTolerance); bBox.Max.DistanceTo(expectedMax).Should().BeLessThan(GSharkMath.MaxTolerance); }
public void It_Returns_The_BoundingBox_Of_The_Arc() { // Arrange double angle = GSharkMath.ToRadians(40); Arc arc2D = new Arc(Plane.PlaneXY, 15, angle); Arc arc3D = _exampleArc3D; // Act BoundingBox bBox2D = arc2D.BoundingBox(); BoundingBox bBox3D = arc3D.BoundingBox(); // 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(); }
public void It_Returns_A_Arc_Based_On_A_Start_And_An_End_Point_And_A_Direction() { // Arrange Point3 startPt = new Point3(5, 5, 5); Point3 endPt = new Point3(10, 15, 10); Vector3 dir = new Vector3(3, 3, 0); double radiusExpected = 12.247449; double angleExpected = GSharkMath.ToRadians(60); Point3 centerExpected = new Point3(0, 10, 15); // Act Arc arc = Arc.ByStartEndDirection(startPt, endPt, dir); // Assert arc.Angle.Should().BeApproximately(angleExpected, 1e-6); arc.Radius.Should().BeApproximately(radiusExpected, 1e-6); arc.Plane.Origin.EpsilonEquals(centerExpected, 1e-6).Should().BeTrue(); }
public void It_Returns_A_Rotated_Transformed_Matrix() { // Arrange var center = new Point3(5, 5, 0); double angleInRadians = GSharkMath.ToRadians(30); // Act Transform transform = Transform.Rotation(angleInRadians, center); // Getting the angles. Dictionary <string, double> angles = Transform.GetYawPitchRoll(transform); // Getting the direction. var axis = Transform.GetRotationAxis(transform); // Assert GSharkMath.ToDegrees(angles["Yaw"]).Should().BeApproximately(30, GSharkMath.Epsilon); axis.Should().BeEquivalentTo(Vector3.ZAxis); }
/// <summary> /// Computes the derivatives at the given U and V parameters on a NURBS surface.<br/> /// <para>Returns a two dimensional array containing the derivative vectors.<br/> /// Increasing U partial derivatives are increasing row-wise.Increasing V partial derivatives are increasing column-wise.<br/> /// Therefore, the[0,0] position is a point on the surface, [n,0] is the nth V partial derivative, the[n,n] position is twist vector or mixed partial derivative UV.</para> /// <em>Corresponds to algorithm 4.4 from The NURBS Book by Piegl and Tiller.</em> /// </summary> /// <param name="surface">The surface.</param> /// <param name="u">The u parameter at which to evaluate the derivatives.</param> /// <param name="v">The v parameter at which to evaluate the derivatives.</param> /// <param name="numDerivs">Number of derivatives to evaluate, set as default to 1.</param> /// <returns>The derivatives.</returns> internal static Vector3[,] RationalDerivatives(NurbsSurface surface, double u, double v, int numDerivs = 1) { if (u < 0.0 || u > 1.0) { throw new ArgumentException("The U parameter is not into the domain 0.0 to 1.0."); } if (v < 0.0 || v > 1.0) { throw new ArgumentException("The V parameter is not into the domain 0.0 to 1.0."); } var derivatives = Derivatives(surface, u, v, numDerivs); Vector3[,] SKL = new Vector3[numDerivs + 1, numDerivs + 1]; for (int k = 0; k < numDerivs + 1; k++) { for (int l = 0; l < numDerivs - k + 1; l++) { Vector3 t = derivatives.Item1[k, l]; for (int j = 1; j < l + 1; j++) { t -= SKL[k, l - j] * (GSharkMath.GetBinomial(l, j) * derivatives.Item2[0, j]); } for (int i = 1; i < k + 1; i++) { t -= SKL[k - i, l] * (GSharkMath.GetBinomial(k, i) * derivatives.Item2[i, 0]); Vector3 t2 = Vector3.Zero; for (int j = 1; j < l + 1; j++) { t2 += SKL[k - i, l - j] * (GSharkMath.GetBinomial(l, j) * derivatives.Item2[i, j]); } t -= t2 * GSharkMath.GetBinomial(k, i); } SKL[k, l] = t / derivatives.Item2[0, 0]; } } return(SKL); }
/// <summary> /// Evaluates a point at the specif length. /// </summary> /// <param name="length">The length where to evaluate the point.</param> /// <returns>The point at the length.</returns> public override Point3 PointAtLength(double length) { if (length <= 0.0) { return(StartPoint); } if (length >= Length) { return(EndPoint); } double theta = GSharkMath.ToRadians((length * 360) / (Math.PI * 2 * Radius)); Vector3 xDir = Plane.XAxis * Math.Cos(theta) * Radius; Vector3 yDir = Plane.YAxis * Math.Sin(theta) * Radius; return(Plane.Origin + xDir + yDir); }
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); Plane plane = new Plane(pt1, pt2, pt3); Transform translation = Transform.Translation(new Point3(10, 15, 0)); Transform rotation = Transform.Rotation(GSharkMath.ToRadians(30), new Point3(0, 0, 0)); var expectedOrigin = new Point3(17.320508, 42.320508, 0); var expectedZAxis = new Vector3(0, 0, -1); // Act Transform combinedTransformations = translation.Combine(rotation); Plane transformedPlane = plane.Transform(combinedTransformations); // Assert transformedPlane.Origin.EpsilonEquals(expectedOrigin, GSharkMath.MaxTolerance).Should().BeTrue(); transformedPlane.ZAxis.EpsilonEquals(expectedZAxis, GSharkMath.MaxTolerance).Should().BeTrue(); }
/// <summary> /// Determines the derivatives of a curve at a given parameter.<br/> /// <em>Corresponds to algorithm 4.2 from The NURBS Book by Piegl and Tiller.</em> /// </summary> /// <param name="curve">The curve object.</param> /// <param name="parameter">Parameter on the curve at which the point is to be evaluated</param> /// <param name="numberOfDerivatives">The number of derivatives required.</param> /// <returns>The derivatives.</returns> public static List <Vector3> RationalDerivatives(NurbsBase curve, double parameter, int numberOfDerivatives = 1) { List <Point4> derivatives = CurveDerivatives(curve, parameter, numberOfDerivatives); // Array of derivative of A(t). // 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 <Point3> rationalDerivativePoints = Point4.RationalPoints(derivatives); // Correspond in the book to wDers. List <double> weightDers = Point4.GetWeights(derivatives); List <Vector3> CK = new List <Vector3>(); for (int k = 0; k < numberOfDerivatives + 1; k++) { Point3 rationalDerivativePoint = rationalDerivativePoints[k]; for (int i = 1; i < k + 1; i++) { double valToMultiply = GSharkMath.GetBinomial(k, i) * weightDers[i]; var pt = CK[k - i]; for (int j = 0; j < rationalDerivativePoint.Size; j++) { rationalDerivativePoint[j] = rationalDerivativePoint[j] - valToMultiply * pt[j]; } } for (int j = 0; j < rationalDerivativePoint.Size; j++) { rationalDerivativePoint[j] = rationalDerivativePoint[j] * (1 / weightDers[0]); } CK.Add(rationalDerivativePoint); } // Return C(t) derivatives. return(CK); }
/// <summary> /// Constructs the string representation of the vector. /// </summary> /// <returns>The vector in string format.</returns> public override string ToString() { return(string.Join(",", this.Select(e => GSharkMath.Truncate(e)))); }
public void It_Checks_If_A_Double_Is_Valid(double val, bool expectedResult) { GSharkMath.IsValidDouble(val).Should().Be(expectedResult); }
public void It_Returns_The_Degree_From_Radians(double radians, double degreeExpected) { System.Math.Round(GSharkMath.ToDegrees(radians), 0).Should().Be(degreeExpected); }
/// <summary> /// Evaluates a point at the normalized length. /// </summary> /// <param name="normalizedLength">The length factor is normalized between 0.0 and 1.0.</param> /// <returns>The point at the length.</returns> public override Point3 PointAtNormalizedLength(double normalizedLength) { double length = GSharkMath.RemapValue(normalizedLength, new Interval(0.0, 1.0), new Interval(0.0, Length)); return(PointAtLength(length)); }
/// <summary> /// Elevates the degree of a curve. /// <em>Implementation of Algorithm A5.9 of The NURBS Book by Piegl and Tiller.</em> /// </summary> /// <param name="curve">The object curve to elevate.</param> /// <param name="finalDegree">The expected final degree. If the supplied degree is less or equal the curve is returned unmodified.</param> /// <returns>The curve after degree elevation.</returns> internal static NurbsBase ElevateDegree(NurbsBase curve, int finalDegree) { if (finalDegree <= curve.Degree) { return(curve); } int n = curve.Knots.Count - curve.Degree - 2; int p = curve.Degree; KnotVector U = curve.Knots; List <Point4> Pw = curve.ControlPoints; int t = finalDegree - curve.Degree; // Degree elevate a curve t times. // local arrays. double[,] bezalfs = new double[p + t + 1, p + 1]; Point4[] bpts = new Point4[p + 1]; Point4[] ebpts = new Point4[p + t + 1]; Point4[] nextbpts = new Point4[p - 1]; double[] alphas = new double[p - 1]; int m = n + p + 1; int ph = finalDegree; int ph2 = (int)Math.Floor((double)(ph / 2)); // Output values; List <Point4> Qw = new List <Point4>(); KnotVector Uh = new KnotVector(); // Compute Bezier degree elevation coefficients. bezalfs[0, 0] = bezalfs[ph, p] = 1.0; for (int i = 1; i <= ph2; i++) { double inv = 1.0 / GSharkMath.GetBinomial(ph, i); int mpi = Math.Min(p, i); for (int j = Math.Max(0, i - t); j <= mpi; j++) { bezalfs[i, j] = inv * GSharkMath.GetBinomial(p, j) * GSharkMath.GetBinomial(t, i - j); } } for (int i = ph2 + 1; i <= ph - 1; i++) { int mpi = Math.Min(p, i); for (int j = Math.Max(0, i - t); j <= mpi; j++) { bezalfs[i, j] = bezalfs[ph - i, p - j]; } } int mh = ph; int kind = ph + 1; int r = -1; int a = p; int b = p + 1; int cind = 1; double ua = U[0]; Qw.Add(Pw[0]); for (int i = 0; i <= ph; i++) { Uh.Add(ua); } // Initialize first Bezier segment. for (int i = 0; i <= p; i++) { bpts[i] = Pw[i]; } // Big loop thru knot vector. while (b < m) { int i = b; while (b < m && Math.Abs(U[b] - U[b + 1]) < GSharkMath.Epsilon) { b += 1; } int mul = b - i + 1; mh = mh + mul + t; double ub = U[b]; int oldr = r; r = p - mul; // Insert knot U[b] r times. // Checks for integer arithmetic. int lbz = (oldr > 0) ? (int)Math.Floor((double)((2 + oldr) / 2)) : 1; int rbz = (r > 0) ? (int)Math.Floor((double)(ph - (r + 1) / 2)) : ph; if (r > 0) { // Inserts knot to get Bezier segment. double numer = ub - ua; for (int k = p; k > mul; k--) { alphas[k - mul - 1] = (numer / (U[a + k] - ua)); } for (int j = 1; j <= r; j++) { int save = r - j; int s = mul + j; for (int k = p; k >= s; k--) { bpts[k] = Point4.Interpolate(bpts[k], bpts[k - 1], alphas[k - s]); } nextbpts[save] = bpts[p]; } } // End of insert knot. // Degree elevate Bezier. for (int j = lbz; j <= ph; j++) { ebpts[j] = Point4.Zero; int mpi = Math.Min(p, j); for (int k = Math.Max(0, j - t); k <= mpi; k++) { ebpts[j] += bpts[k] * bezalfs[j, k]; } } if (oldr > 1) { // Must remove knot u=U[a] oldr times. int first = kind - 2; int last = kind; double den = ub - ua; double bet = (ub - Uh[kind - 1]) / den; for (int tr = 1; tr < oldr; tr++) { // Knot removal loop. int ii = first; int jj = last; int kj = jj - kind + 1; while (jj - ii > tr) { // Loop and compute the new control points for one removal step. if (ii < cind) { double alf = (ub - Uh[ii]) / (ua - Uh[ii]); Qw.Add(Point4.Interpolate(Qw[ii], Qw[ii - 1], alf)); } if (jj >= lbz) { if (jj - tr <= kind - ph + oldr) { double gam = (ub - Uh[jj - tr]) / den; ebpts[kj] = Point4.Interpolate(ebpts[kj], ebpts[kj + 1], gam); } else { ebpts[kj] = Point4.Interpolate(ebpts[kj], ebpts[kj + 1], bet); } } ii += 1; jj -= 1; kj -= 1; } first -= 1; last += 1; } } // End of removing knot, n = U[a]. if (a != p) { // Load the knot ua. for (int j = 0; j < ph - oldr; j++) { Uh.Add(ua); } } for (int j = lbz; j <= rbz; j++) { // Load control points into Qw. Qw.Add(ebpts[j]); } if (b < m) { // Set up for the next pass thru loop. for (int j = 0; j < r; j++) { bpts[j] = nextbpts[j]; } for (int j = r; j <= p; j++) { bpts[j] = Pw[b - p + j]; } a = b; b += 1; ua = ub; } else { // End knot. for (int j = 0; j <= ph; j++) { Uh.Add(ub); } } } return(new NurbsCurve(finalDegree, Uh, Qw)); }
/// <summary> /// Gets the text representation of an arc. /// </summary> /// <returns>Text value.</returns> public override string ToString() { return($"Arc(R:{Radius} - A:{GSharkMath.ToDegrees(Angle)})"); }
public void It_Returns_The_Radians_From_Degree(double degree, double radiansExpected) { System.Math.Round(GSharkMath.ToRadians(degree), 6).Should().Be(radiansExpected); }