private double NormalizeTime(double t)
        {
            // This operation takes log(n) time, where n is the constant NumberOfSamples.
            if (t <= 0.0)
            {
                return(t);
            }
            if (t >= 1.0)
            {
                return(t);
            }

            // Find the sample that contains our time.
            int index = _samples.BinarySearchStruct((item) => {
                if (item.StartTime > t)
                {
                    return(-1);
                }
                if (item.EndTime <= t)
                {
                    return(1);
                }
                return(0);
            });

            SegmentSample sample   = _samples[index];
            double        segmentT = (t - sample.StartTime) / (sample.EndTime - sample.StartTime);

            // Each segment is spaced at 1/NumberOfSegments intervals along our curve.
            return((index + segmentT) / (double)NumberOfSamples);
        }
        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;
            }
        }
        private double DenormalizeTime(double t)
        {
            // This operation takes log(n) time, where n is the constant NumberOfSamples.
            if (t <= 0.0)
            {
                return(t);
            }
            if (t >= 1.0)
            {
                return(t);
            }

            double total    = t * NumberOfSamples;
            int    index    = Mathf.FloorToInt((float)total);
            double segmentT = total - index;

            SegmentSample sample = _samples[index];

            return((segmentT * (sample.EndTime - sample.StartTime)) + sample.StartTime);
        }