Beispiel #1
0
        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);
        }
Beispiel #2
0
        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();
        }
Beispiel #3
0
        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);
        }
Beispiel #4
0
        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();
        }
Beispiel #5
0
        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();
        }
Beispiel #6
0
        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
        }
Beispiel #7
0
        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);
        }
Beispiel #8
0
        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();
        }
Beispiel #9
0
        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();
        }
Beispiel #10
0
        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);
        }
Beispiel #11
0
        /// <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);
        }
Beispiel #12
0
        /// <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);
        }
Beispiel #13
0
        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();
        }
Beispiel #14
0
        /// <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);
        }
Beispiel #15
0
 /// <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))));
 }
Beispiel #16
0
 public void It_Checks_If_A_Double_Is_Valid(double val, bool expectedResult)
 {
     GSharkMath.IsValidDouble(val).Should().Be(expectedResult);
 }
Beispiel #17
0
 public void It_Returns_The_Degree_From_Radians(double radians, double degreeExpected)
 {
     System.Math.Round(GSharkMath.ToDegrees(radians), 0).Should().Be(degreeExpected);
 }
Beispiel #18
0
        /// <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));
        }
Beispiel #19
0
        /// <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));
        }
Beispiel #20
0
 /// <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)})");
 }
Beispiel #21
0
 public void It_Returns_The_Radians_From_Degree(double degree, double radiansExpected)
 {
     System.Math.Round(GSharkMath.ToRadians(degree), 6).Should().Be(radiansExpected);
 }