private static Animation CreateAnimationOfOperations(Interval renderInterval, Interval targetInterval, params Operation[] operations) { var keyNodes = new Dictionary<int, Tuple<NestingDepthTreeNode, Interval, NestingDepthTreeNode>>(); var activeOperation = default(Operation); var dt = 1.0; var ani = new Animation(); ani.Add(new TextDesc("Using a Tree to Track Referenced Intervals", new Point(250, 5), new Point(0, 0), fontSize:20)); ani.Add(new TextDesc("Referenced" + Environment.NewLine + "Intervals", new Point(10, 80))); ani.Add(new TextDesc("Tree", new Point(10, 220))); ani.Add(new TextDesc("Nesting" + Environment.NewLine + "Depth", new Point(10, 350))); ani.Add(new LineSegmentDesc(new Point(0, 30).Sweep(new Vector(10000, 0)), Brushes.Black, 1)); ani.Add(new LineSegmentDesc(new Point(0, 100).Sweep(new Vector(10000, 0)), Brushes.Black, 1)); ani.Add(new LineSegmentDesc(new Point(0, 300).Sweep(new Vector(10000, 0)), Brushes.Black, 1)); ani.Add(new LineSegmentDesc(new Point(75, 0).Sweep(new Vector(0, 10000)), Brushes.Black, 1)); var i = 0.0; var dealloced = new HashSet<int>(); for (var i2 = 0; i2 < renderInterval.Length; i2++) { if (i2 + renderInterval.Offset < targetInterval.Offset || i2 + renderInterval.Offset >= targetInterval.Offset + targetInterval.Length) { dealloced.Add(i2 + renderInterval.Offset); } } var x = 100; var y = 90; Func<double, Animation> addFrame = focus => { var roots = keyNodes.Select(e => NestingDepthTreeNode.RootOf(e.Value.Item1)).Distinct().ToArray(); var a = new Animation(); var s = 10; if (!double.IsNaN(focus) && !double.IsInfinity(focus)) { var dx = focus - renderInterval.Offset; a.Add(new LineSegmentDesc(new LineSegment(new Point(x + dx*s, 0), new Point(x + dx*s, 10000)), activeOperation.Interval.HasValue ? Brushes.Green : Brushes.Red, 1, 1.0)); } foreach (var r in roots) a.Add(RenderTree(renderInterval, r, dealloced)); ani.LimitedNewTime(i.Seconds(), (i + dt).Seconds()).Add(a); i += dt; var bb = 0; foreach (var e in keyNodes) { Brush brush; if (e.Key == activeOperation.Key && !double.IsInfinity(focus)) { brush = activeOperation.Interval.HasValue ? Brushes.Green : Brushes.Red; } else { brush = Brushes.Yellow; } var inv = e.Value.Item2; var dx = inv.Offset - renderInterval.Offset; a.Add(new RectDesc(new Rect(x + dx * s, y - (bb+1) * s*1.1, s*inv.Length, s), fill: brush, stroke: Brushes.Black, strokeThickness: 1)); bb += 1; } return a; }; foreach (var e in operations) { activeOperation = e; var affectedRoot = e.Interval.HasValue ? keyNodes.Select(n => NestingDepthTreeNode.RootOf(n.Value.Item1)).FirstOrDefault(n => NestingDepthTreeNode.GetInterval(n).Overlaps(e.Interval.Value)) : NestingDepthTreeNode.RootOf(keyNodes[e.Key].Item1); if (e.Interval.HasValue) { keyNodes.Add(e.Key, Tuple.Create((NestingDepthTreeNode)null, e.Interval.Value, (NestingDepthTreeNode)null)); addFrame(double.NaN); addFrame(e.Interval.Value.Offset); var a1 = NestingDepthTreeNode.Include(affectedRoot, e.Interval.Value.Offset, +1, +1); a1.AdjustedNode._fakeRefCount += 2; keyNodes[e.Key] = Tuple.Create(a1.AdjustedNode, e.Interval.Value, (NestingDepthTreeNode)null); addFrame(e.Interval.Value.Offset); addFrame(e.Interval.Value.Offset + e.Interval.Value.Length); var a2 = NestingDepthTreeNode.Include(a1.NewRoot, e.Interval.Value.Offset + e.Interval.Value.Length, -1, +1); a2.AdjustedNode._fakeRefCount += 2; keyNodes[e.Key] = Tuple.Create(a1.AdjustedNode, e.Interval.Value, a2.AdjustedNode); addFrame(e.Interval.Value.Offset + e.Interval.Value.Length); addFrame(double.PositiveInfinity); } else { var xs = keyNodes[e.Key]; var r = NestingDepthTreeNode.RootOf(xs.Item1); r = NestingDepthTreeNode.Include(r, xs.Item2.Offset + xs.Item2.Length, +1, 0).NewRoot; r = NestingDepthTreeNode.Include(r, xs.Item2.Offset, -1, 0).NewRoot; var hh = new HashSet<int>(); foreach (var ex in NestingDepthTreeNode.FindHolesIn(NestingDepthTreeNode.GetInterval(r), r)) { for (var ii = ex.Offset; ii < ex.Offset + ex.Length; ii++) { hh.Add(ii); } } r = NestingDepthTreeNode.Include(r, xs.Item2.Offset + xs.Item2.Length, -1, 0).NewRoot; r = NestingDepthTreeNode.Include(r, xs.Item2.Offset, +1, 0).NewRoot; xs.Item3._fakeRefCount -= 1; xs.Item3._fakeRefCount -= 1; xs.Item1._fakeRefCount -= 1; addFrame(xs.Item2.Offset + xs.Item2.Length); var r1 = NestingDepthTreeNode.Include(r, xs.Item2.Offset + xs.Item2.Length, +1, -1); addFrame(xs.Item2.Offset + xs.Item2.Length); xs.Item1._fakeRefCount -= 1; addFrame(xs.Item2.Offset); var r2 = NestingDepthTreeNode.Include(r1.NewRoot, xs.Item2.Offset, -1, -1); keyNodes.Remove(e.Key); addFrame(double.NaN); foreach (var xxx in hh) { dealloced.Add(xxx); } NestingDepthTreeNode.PartitionAroundHoles(r2.NewRoot); addFrame(double.NaN); } } var xx = new Animation(); xx.Periodic(i.Seconds()).Add(ani); return xx; }