// 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; } }