Exemple #1
0
        /// <summary>
        /// Calculates the tangent coefficents of a segment. This is used in tangent and acceleration calculations.
        /// </summary>
        /// <returns>The tangent coefficients.</returns>
        /// <param name="segment">The segment to calculate the coefficients of.</param>
        public static CubicBezierTangentCoefficients CalculateTangentCoefficients(this CubicBezierSegment segment)
        {
            var coeffs = new CubicBezierTangentCoefficients();

            coeffs.Coeff1 = -3f * segment.StartPoint + 9f * segment.StartControlPoint - 9 * segment.EndControlPoint + 3f * segment.EndPoint;
            coeffs.Coeff2 = 6f * segment.StartPoint - 12f * segment.StartControlPoint + 6 * segment.EndControlPoint;
            coeffs.Coeff3 = -3f * segment.StartPoint + 3f * segment.StartControlPoint;

            return(coeffs);
        }
Exemple #2
0
        /// <summary>
        /// Gets a normal for a given segment. Note that there are an infinite number of possible normals, this method just
        /// produces a locally consistent normal.
        /// </summary>
        /// <returns>A normal at a given point.</returns>
        /// <param name="segment">The segment to calculate the tangent of.</param>
        /// <param name="segment">The precalculated coefficients of the curve.</param>
        /// <param name="t">
        /// The time along the curve, where t=0 is the start point, and t=1 is the end point. Note that t can be extrapolated
        /// beyond these bounds.
        /// </param>
        /// <param name="up">
        /// The direction the normal should try to match.
        /// </param>
        public static Vector3 GetNormal(this CubicBezierSegment segment, CubicBezierTangentCoefficients coeffs, double t, Vector3 up)
        {
            Vector3 baseNormal = segment.GetNormal(coeffs, t);
            Vector3 tangent    = coeffs.GetTangent(t);

            Vector3 upNormal = Vector3.Cross(Vector3.Cross(tangent, up), tangent).normalized;

            if (Vector3.Angle(tangent, up) == 0f)
            {
                return(baseNormal);
            }

            float angle = Mathf.Min(Mathf.Abs(Vector3.Angle(tangent, up)), Mathf.Abs(Vector3.Angle(tangent, -up)));
            float lerp  = Mathf.Clamp01((angle + 5) / 45f);

            return(AngleLerp(baseNormal, upNormal, lerp));
        }
        /// <summary>
        /// Finds the points of inflection of the curve.
        /// </summary>
        /// <returns>The points of inflection times.</returns>
        /// <param name="segment">Segment.</param>
        public static double[] GetPointsOfInflectionTimes(this CubicBezierTangentCoefficients coeffs)
        {
            // Solve the x,y and z axis separately.
            IEnumerable <double> xRoots = GetCubicExtremities(
                coeffs.Coeff1.x, coeffs.Coeff2.x, coeffs.Coeff3.x);
            IEnumerable <double> yRoots = GetCubicExtremities(
                coeffs.Coeff1.y, coeffs.Coeff2.y, coeffs.Coeff3.y);
            IEnumerable <double> zRoots = GetCubicExtremities(
                coeffs.Coeff1.z, coeffs.Coeff2.z, coeffs.Coeff3.z);

            // Join them together, and resort.
            return(xRoots
                   .Union(yRoots)
                   .Union(zRoots)
                   .Where(t => 0.0 <= t && t <= 1.0)      // In Range of bezier.
                   .OrderBy(root => root)
                   .ToArray());
        }
        /// <summary>
        /// Gets the tangent at a point along the curve.
        /// </summary>
        /// <returns>The tangent at the given time.</returns>
        /// <param name="coeffs">The precalculated coefficients of the curve.</param>
        /// <param name="t">
        /// The time along the curve, where t=0 is the start point, and t=1 is the end point. Note that t can be extrapolated
        /// beyond these bounds.
        /// </param>
        public static Vector3 GetTangent(this CubicBezierTangentCoefficients coeffs, double t)
        {
            Vector3 velocity = (float)(t * t) * coeffs.Coeff1 + ((float)t) * coeffs.Coeff2 + coeffs.Coeff3;

            // If the velocity is 0, we look at the acceleration of the path to determine which direction the path is about
            // to travel to.
            if (velocity.magnitude < float.Epsilon)
            {
                Vector3 acceleration = coeffs.GetAcceleration(t);
                // If acceleration is 0, the entire path is probably a single point.
                if (acceleration.magnitude < float.Epsilon)
                {
                    if (coeffs.Coeff1.magnitude < float.Epsilon)
                    {
                        return(Vector3.forward);
                    }
                    return(coeffs.Coeff1.normalized);
                }
                return(acceleration.normalized);
            }
            return(velocity.normalized);
        }
Exemple #5
0
        /// <summary>
        /// Gets a normal for a given segment. Note that there are an infinite number of possible normals, this method just
        /// produces a locally consistent normal.
        /// </summary>
        /// <returns>A normal at a given point.</returns>
        /// <param name="segment">The segment to calculate the tangent of.</param>
        /// <param name="segment">The precalculated coefficients of the curve.</param>
        /// <param name="t">
        /// The time along the curve, where t=0 is the start point, and t=1 is the end point. Note that t can be extrapolated
        /// beyond these bounds.
        /// </param>
        public static Vector3 GetNormal(this CubicBezierSegment segment, CubicBezierTangentCoefficients coeffs, double t)
        {
            Vector3 currentTangent = coeffs.GetTangent(t);

            Vector3 normal;

            if (currentTangent == Vector3.zero)
            {
                Vector3 acceleration = coeffs.GetAcceleration(t);
                currentTangent = acceleration;
            }

            // The tangent doesn't change, (such in the case of a straight line).
            // We pick a vector which shouldn't be parallel to the tangent, and
            // use the cross product with the tangent to find a normal.
            normal   = currentTangent;
            normal.x = -currentTangent.y;
            normal.y = -currentTangent.z;
            normal.z = currentTangent.x;

            normal = Vector3.Cross(currentTangent, normal).normalized;
            return(normal);
        }
 /// <summary>
 /// Get the acceleration at a point along the curve.
 /// </summary>
 /// <returns>The acceleration at a given time.</returns>
 /// <param name="coeffs">The precalculated coefficients of the curve.</param>
 /// <param name="t">
 /// The time along the curve, where t=0 is the start point, and t=1 is the end point. Note that t can be extrapolated
 /// beyond these bounds.
 /// </param>
 public static Vector3 GetAcceleration(this CubicBezierTangentCoefficients coeffs, double t)
 {
     return(((float)t) * coeffs.Coeff1 * 2 + coeffs.Coeff2);
 }
 /// <summary>
 /// Gets the velocity at a point of the curve.
 /// </summary>
 /// <returns>The tangent at the given time.</returns>
 /// <param name="coeffs">The precalculated coefficients of the curve.</param>
 /// <param name="t">
 /// The time along the curve, where t=0 is the start point, and t=1 is the end point. Note that t can be extrapolated
 /// beyond these bounds.
 /// </param>
 public static Vector3 GetVelocity(this CubicBezierTangentCoefficients coeffs, double t)
 {
     return((float)(t * t) * coeffs.Coeff1 + ((float)t) * coeffs.Coeff2 + coeffs.Coeff3);
 }