// Make sure the indexers are starting next to each other
        static private void IntersectsHelperPrepareIndexers(ref TimeIntervalCollection tic1, ref TimeIntervalCollection tic2)
        {
            Debug.Assert(!tic1.IsEmptyOfRealPoints);  // We shouldn't reach here if either TIC is empty
            Debug.Assert(!tic2.IsEmptyOfRealPoints);

            tic1.MoveFirst();  // Point _current to the first node in both TICs
            tic2.MoveFirst();

            // First bring tic1._current and tic2._current within an interval of each other
            if (tic1.CurrentNodeTime < tic2.CurrentNodeTime)
            {
                // Keep advancing tic1._current as far as possible while keeping _nodeTime[tic1._current] < _nodeTime[tic2._current]
                while (!tic1.CurrentIsAtLastNode && (tic1.NextNodeTime <= tic2.CurrentNodeTime))
                {
                    tic1.MoveNext();
                }
            }
            else if (tic2.CurrentNodeTime < tic1.CurrentNodeTime)
            {
                // Keep advancing tic2._current as far as possible while keeping _nodeTime[tic1._current] > _nodeTime[tic2._current]
                while (!tic2.CurrentIsAtLastNode && (tic2.NextNodeTime <= tic1.CurrentNodeTime))
                {
                    tic2.MoveNext();
                }
            }
        }
        /// <summary>
        /// Performs the NORMALIZE operation, as described in the comments to the general projection function.
        /// Clip begin and end times, normalize by beginTime, scale by speedRatio.
        /// </summary>
        /// <param name="projection">The normalized collection to create.</param>
        /// <param name="beginTime">Begin time of the active period for clipping.</param>
        /// <param name="endTime">End time of the active period for clipping.</param>
        /// <param name="speedRatio">The ratio by which to scale begin and end time.</param>
        /// <param name="includeFillPeriod">Whether a non-zero fill period exists.</param>
        private void ProjectionNormalize(ref TimeIntervalCollection projection,
                                         TimeSpan beginTime, Nullable<TimeSpan> endTime, bool includeFillPeriod, double speedRatio)
        {
            Debug.Assert(!IsEmptyOfRealPoints);
            Debug.Assert(projection.IsEmpty);
            
            projection.EnsureAllocatedCapacity(this._nodeTime.Length);

            this.MoveFirst();
            projection.MoveFirst();

            // Get to the non-clipped zone; we must overlap the active zone, so we should terminate at some point.
            while (!CurrentIsAtLastNode && NextNodeTime <= beginTime)
            {
                MoveNext();
            }

            if (CurrentNodeTime < beginTime)  // This means we have an interval clipped by beginTime
            {
                if (CurrentNodeIsInterval)
                {
                    projection._count++;
                    projection.CurrentNodeTime = TimeSpan.Zero;
                    projection.CurrentNodeIsPoint = true;
                    projection.CurrentNodeIsInterval = true;
                    projection.MoveNext();
                }
                this.MoveNext();
            }

            while(_current < _count && (!endTime.HasValue || CurrentNodeTime < endTime))  // Copy the main set of segments, transforming them
            {
                double timeOffset = (double)((this.CurrentNodeTime - beginTime).Ticks);
                
                projection._count++;
                projection.CurrentNodeTime = TimeSpan.FromTicks((long)(speedRatio * timeOffset));
                projection.CurrentNodeIsPoint = this.CurrentNodeIsPoint;
                projection.CurrentNodeIsInterval = this.CurrentNodeIsInterval;

                projection.MoveNext();
                this.MoveNext();
            }

            Debug.Assert(_current > 0);  // The only way _current could stay at zero is if the collection begins at (or past) the end of active period
            if (_current < _count  // We have an interval reaching beyond the active zone, clip that interval
             && (_nodeIsInterval[_current - 1]
              || (CurrentNodeTime == endTime.Value && CurrentNodeIsPoint && includeFillPeriod)))
            {
                Debug.Assert(endTime.HasValue && CurrentNodeTime >= endTime.Value);

                double timeOffset = (double)((endTime.Value - beginTime).Ticks);

                projection._count++;
                projection.CurrentNodeTime = TimeSpan.FromTicks((long)(speedRatio * timeOffset));
                projection.CurrentNodeIsPoint = includeFillPeriod && (CurrentNodeTime > endTime.Value || CurrentNodeIsPoint);
                projection.CurrentNodeIsInterval = false;
            }
        }