Ejemplo n.º 1
0
        /// <summary>
        /// Gets the tangent for the start of the cure.
        /// </summary>
        public VECTOR GetLeftTangent(int last)
        {
#if OPTIMIZED_GETLEFTTANGENT
            using var _ = GetLeftTangentMarker.Auto();
            unsafe
            {
                using (_pts.ViewAsNativeArray(out var pts))
                    using (_arclen.ViewAsNativeArray(out var arclen))
                    {
                        OptimizedHelpers.GetLeftTangent(last, (VECTOR *)pts.GetUnsafePtr(), pts.Length, (FLOAT *)arclen.GetUnsafePtr(), arclen.Length, out var tanL);
                        return(tanL);
                    }
            }
#else
            using var _ = GetLeftTangentMarker.Auto();
            List <VECTOR> pts         = _pts;
            List <FLOAT>  arclen      = _arclen;
            FLOAT         totalLen    = arclen[arclen.Count - 1];
            VECTOR        p0          = pts[0];
            VECTOR        tanL        = VectorHelper.Normalize(pts[1] - p0);
            VECTOR        total       = tanL;
            FLOAT         weightTotal = 1;
            last = Math.Min(END_TANGENT_N_PTS, last - 1);
            for (int i = 2; i <= last; i++)
            {
                FLOAT  ti     = 1 - (arclen[i] / totalLen);
                FLOAT  weight = ti * ti * ti;
                VECTOR v      = VectorHelper.Normalize(pts[i] - p0);
                total       += v * weight;
                weightTotal += weight;
            }
            // if the vectors add up to zero (ie going opposite directions), there's no way to normalize them
            if (VectorHelper.Length(total) > EPSILON)
            {
                tanL = VectorHelper.Normalize(total / weightTotal);
            }
            return(tanL);
#endif
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Gets the tangent for the the end of the curve.
        /// </summary>
        public VECTOR GetRightTangent(int first)
        {
#if OPTIMIZED_GETRIGHTTANGENT
            using var _ = GetRightTangentMarker.Auto();
            unsafe
            {
                using (_pts.ViewAsNativeArray(out var pts))
                    using (_arclen.ViewAsNativeArray(out var arclen))
                    {
                        OptimizedHelpers.GetRightTangent(first, (VECTOR *)pts.GetUnsafePtr(), pts.Length, (FLOAT *)arclen.GetUnsafePtr(), arclen.Length, out var tanR);
                        return(tanR);
                    }
            }
#else
            using var _ = GetRightTangentMarker.Auto();
            List <VECTOR> pts         = _pts;
            List <FLOAT>  arclen      = _arclen;
            FLOAT         totalLen    = arclen[arclen.Count - 1];
            VECTOR        p3          = pts[pts.Count - 1];
            VECTOR        tanR        = VectorHelper.Normalize(pts[pts.Count - 2] - p3);
            VECTOR        total       = tanR;
            FLOAT         weightTotal = 1;
            first = Math.Max(pts.Count - (END_TANGENT_N_PTS + 1), first + 1);
            for (int i = pts.Count - 3; i >= first; i--)
            {
                FLOAT  t      = arclen[i] / totalLen;
                FLOAT  weight = t * t * t;
                VECTOR v      = VectorHelper.Normalize(pts[i] - p3);
                total       += v * weight;
                weightTotal += weight;
            }
            if (VectorHelper.Length(total) > EPSILON)
            {
                tanR = VectorHelper.Normalize(total / weightTotal);
            }
            return(tanR);
#endif
        }
Ejemplo n.º 3
0
        public static unsafe void GetRightTangent(int first, Vector2 *pts, int ptsCount, float *arclen, int arclenCount, out Vector2 retval)
        {
            var totalLen    = arclen[arclenCount - 1];
            var p3          = pts[ptsCount - 1];
            var tanR        = VectorHelper.Normalize(pts[ptsCount - 2] - p3);
            var total       = tanR;
            var weightTotal = 1.0f;

            first = Math.Max(ptsCount - (CurveFitBase.END_TANGENT_N_PTS + 1), first + 1);
            for (int i = ptsCount - 3; i >= first; i--)
            {
                var t      = arclen[i] / totalLen;
                var weight = t * t * t;
                var v      = VectorHelper.Normalize(pts[i] - p3);
                total       += v * weight;
                weightTotal += weight;
            }
            if (VectorHelper.Length(total) > CurveFitBase.EPSILON)
            {
                tanR = VectorHelper.Normalize(total / weightTotal);
            }
            retval = tanR;
        }
Ejemplo n.º 4
0
        public static unsafe void GetLeftTangent(int last, Vector2 *pts, int ptsCount, float *arclen, int arclenCount, out Vector2 retval)
        {
            float   totalLen    = arclen[arclenCount - 1];
            Vector2 p0          = pts[0];
            Vector2 tanL        = VectorHelper.Normalize(pts[1] - p0);
            Vector2 total       = tanL;
            float   weightTotal = 1;

            last = Math.Min(CurveFitBase.END_TANGENT_N_PTS, last - 1);
            for (int i = 2; i <= last; i++)
            {
                float   ti     = 1 - (arclen[i] / totalLen);
                float   weight = ti * ti * ti;
                Vector2 v      = VectorHelper.Normalize(pts[i] - p0);
                total       += v * weight;
                weightTotal += weight;
            }
            // if the vectors add up to zero (ie going opposite directions), there's no way to normalize them
            if (VectorHelper.Length(total) > CurveFitBase.EPSILON)
            {
                tanL = VectorHelper.Normalize(total / weightTotal);
            }
            retval = tanL;
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Gets the tangent at a given point in the curve.
        /// </summary>
        protected VECTOR GetCenterTangent(int first, int last, int split)
        {
            using var _ = GetCenterTangentMarker.Auto();
            List <VECTOR> pts    = _pts;
            List <FLOAT>  arclen = _arclen;

            // because we want to maintain C1 continuity on the spline, the tangents on either side must be inverses of one another
            Debug.Assert(first < split && split < last);
            FLOAT  splitLen = arclen[split];
            VECTOR pSplit   = pts[split];

            // left side
            FLOAT  firstLen    = arclen[first];
            FLOAT  partLen     = splitLen - firstLen;
            VECTOR total       = default(VECTOR);
            FLOAT  weightTotal = 0;

            for (int i = Math.Max(first, split - MID_TANGENT_N_PTS); i < split; i++)
            {
                FLOAT  t      = (arclen[i] - firstLen) / partLen;
                FLOAT  weight = t * t * t;
                VECTOR v      = VectorHelper.Normalize(pts[i] - pSplit);
                total       += v * weight;
                weightTotal += weight;
            }
            VECTOR tanL = VectorHelper.Length(total) > EPSILON && weightTotal > EPSILON?
                          VectorHelper.Normalize(total / weightTotal) :
                              VectorHelper.Normalize(pts[split - 1] - pSplit);

            // right side
            partLen = arclen[last] - splitLen;
            int rMax = Math.Min(last, split + MID_TANGENT_N_PTS);

            total       = default(VECTOR);
            weightTotal = 0;
            for (int i = split + 1; i <= rMax; i++)
            {
                FLOAT  ti     = 1 - ((arclen[i] - splitLen) / partLen);
                FLOAT  weight = ti * ti * ti;
                VECTOR v      = VectorHelper.Normalize(pSplit - pts[i]);
                total       += v * weight;
                weightTotal += weight;
            }
            VECTOR tanR = VectorHelper.Length(total) > EPSILON && weightTotal > EPSILON?
                          VectorHelper.Normalize(total / weightTotal) :
                              VectorHelper.Normalize(pSplit - pts[split + 1]);

            // The reason we separate this into two halves is because we want the right and left tangents to be weighted
            // equally no matter the weights of the individual parts of them, so that one of the curves doesn't get screwed
            // for the pleasure of the other half
            total = tanL + tanR;

            // Since the points are never coincident, the vector between any two of them will be normalizable, however this can happen in some really
            // odd cases when the points are going directly opposite directions (therefore the tangent is undefined)
            if (VectorHelper.LengthSquared(total) < EPSILON)
            {
                // try one last time using only the three points at the center, otherwise just use one of the sides
                tanL  = VectorHelper.Normalize(pts[split - 1] - pSplit);
                tanR  = VectorHelper.Normalize(pSplit - pts[split + 1]);
                total = tanL + tanR;
                return(VectorHelper.LengthSquared(total) < EPSILON ? tanL : VectorHelper.Normalize(total / 2));
            }
            else
            {
                return(VectorHelper.Normalize(total / 2));
            }
        }