private void CalculateSamples()
        {
            var workingSegment = new CubicBezierSegment();

            workingSegment.StartPoint        = _segment.StartPoint;
            workingSegment.StartControlPoint = _segment.StartControlPoint;
            workingSegment.EndControlPoint   = _segment.EndControlPoint;
            workingSegment.EndPoint          = _segment.EndPoint;

            _length = 0.0f;

            // First, break the working segment down into a discrete number of segments. We only care about the approximate
            // length of these segments, not the curve segments themselves.
            CubicBezierSegment leftSegment = new CubicBezierSegment(), rightSegment = new CubicBezierSegment();

            for (int i = 0; i < NumberOfSamples; ++i)
            {
                // Subdivide another part off the curve. We take 1/64 of the curve on the first loop, and keep the
                // remaining 63/64 of the curve. On the next loop, we want 1/63 of the curve and so on, to keep the
                // segment size consistent.
                double splitT = 1 / (double)(NumberOfSamples - i);
                workingSegment.Subdivide(leftSegment, rightSegment, splitT);

                float nodeLength = leftSegment.CalculateLength();
                _length += nodeLength;
                SegmentSample sample = new SegmentSample();
                sample.Length    = nodeLength;
                sample.StartTime = 0.0f;
                sample.EndTime   = 1.0f;
                _samples.Add(sample);

                // Copy the right curve segment into the working curve segment.
                workingSegment.StartPoint        = rightSegment.StartPoint;
                workingSegment.StartControlPoint = rightSegment.StartControlPoint;
                workingSegment.EndControlPoint   = rightSegment.EndControlPoint;
                workingSegment.EndPoint          = rightSegment.EndPoint;
            }

            // Knowing what the length of the curve segments are, and a total approximate length, we can calculate the
            // the start/end times of each segment. These will be the values we use for our runtime lookup.
            float runningLength = _samples[0].Length;

            for (int i = 1; i < _samples.Count; ++i)
            {
                float t = (float)runningLength / _length;

                SegmentSample sample = _samples[i];
                sample.StartTime = t;
                _samples[i]      = sample;

                SegmentSample oldSample = _samples[i - 1];
                oldSample.EndTime = t;
                _samples[i - 1]   = oldSample;

                runningLength += sample.Length;
            }
        }
Beispiel #2
0
        /// <summary>
        /// Calculates the length of a CubicBezierSegment. Note that because this uses a numerical method to get the length,
        /// it won't be completely accurate.
        /// </summary>
        /// <returns>The length of the bezier segment.</returns>
        /// <param name="segment">The segment to calculate the length of.</param>
        public static float CalculateLength(this CubicBezierSegment segment)
        {
            // Subdividing the segment into 4 pieces, then getting an approximate length on those 4 pieces, gives
            // a fairly accurate length (< 1% error), and is very quick.
            CubicBezierSegment l = new CubicBezierSegment(), r = new CubicBezierSegment(),
                               ll = new CubicBezierSegment(), lr = new CubicBezierSegment(), rl = new CubicBezierSegment(),
                               rr = new CubicBezierSegment();

            segment.Subdivide(l, r, 0.5);
            l.Subdivide(ll, lr, 0.5);
            r.Subdivide(rl, rr, 0.5);
            return(ll.CalculateApproximateLength() + lr.CalculateApproximateLength() + rl.CalculateApproximateLength() +
                   rr.CalculateApproximateLength());
        }