diff options
| author | Andrew Lee <alee14498@protonmail.com> | 2020-04-19 17:19:32 -0400 |
|---|---|---|
| committer | Andrew Lee <alee14498@protonmail.com> | 2020-04-19 17:19:32 -0400 |
| commit | c55fba8ab2a1c9d3df65eda4a5a1e957f4aa1f78 (patch) | |
| tree | ee4d51c7c1d633e11f46453ef1edd3c77c4ef9f7 /Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/IntervalTree.cs | |
| download | Project-Sandbox-c55fba8ab2a1c9d3df65eda4a5a1e957f4aa1f78.tar.gz Project-Sandbox-c55fba8ab2a1c9d3df65eda4a5a1e957f4aa1f78.tar.bz2 Project-Sandbox-c55fba8ab2a1c9d3df65eda4a5a1e957f4aa1f78.zip | |
Inital commit
Diffstat (limited to 'Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/IntervalTree.cs')
| -rw-r--r-- | Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/IntervalTree.cs | 271 |
1 files changed, 271 insertions, 0 deletions
diff --git a/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/IntervalTree.cs b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/IntervalTree.cs new file mode 100644 index 0000000..691f477 --- /dev/null +++ b/Library/PackageCache/com.unity.timeline@1.2.13/Runtime/Evaluation/IntervalTree.cs @@ -0,0 +1,271 @@ +using System; +using System.Collections.Generic; + +namespace UnityEngine.Timeline +{ + interface IInterval + { + Int64 intervalStart { get; } + Int64 intervalEnd { get; } + } + + struct IntervalTreeNode // interval node, + { + public Int64 center; // midpoint for this node + public int first; // index of first element of this node in m_Entries + public int last; // index of the last element of this node in m_Entries + public int left; // index in m_Nodes of the left subnode + public int right; // index in m_Nodes of the right subnode + } + + class IntervalTree<T> where T : IInterval + { + internal struct Entry + { + public Int64 intervalStart; + public Int64 intervalEnd; + public T item; + } + + const int kMinNodeSize = 10; // the minimum number of entries to have subnodes + const int kInvalidNode = -1; + const Int64 kCenterUnknown = Int64.MaxValue; // center hasn't been calculated. indicates no children + + readonly List<Entry> m_Entries = new List<Entry>(); + readonly List<IntervalTreeNode> m_Nodes = new List<IntervalTreeNode>(); + + /// <summary> + /// Whether the tree will be rebuilt on the next query + /// </summary> + public bool dirty { get; internal set; } + + /// <summary> + /// Add an IInterval to the tree + /// </summary> + public void Add(T item) + { + if (item == null) + return; + + m_Entries.Add( + new Entry() + { + intervalStart = item.intervalStart, + intervalEnd = item.intervalEnd, + item = item + } + ); + dirty = true; + } + + /// <summary> + /// Query the tree at a particular time + /// </summary> + /// <param name="value"></param> + /// <param name="results"></param> + public void IntersectsWith(Int64 value, List<T> results) + { + if (m_Entries.Count == 0) + return; + + if (dirty) + { + Rebuild(); + dirty = false; + } + + if (m_Nodes.Count > 0) + Query(m_Nodes[0], value, results); + } + + /// <summary> + /// Query the tree at a particular range of time + /// </summary> + /// <param name="start"></param> + /// <param name="end"></param> + /// <param name="results"></param> + public void IntersectsWithRange(Int64 start, Int64 end, List<T> results) + { + if (start > end) + return; + + if (m_Entries.Count == 0) + return; + + if (dirty) + { + Rebuild(); + dirty = false; + } + + if (m_Nodes.Count > 0) + QueryRange(m_Nodes[0], start, end, results); + } + + /// <summary> + /// Updates the intervals from their source. Use this to detect if the data in the tree + /// has changed. + /// </summary> + public void UpdateIntervals() + { + bool isDirty = false; + for (int i = 0; i < m_Entries.Count; i++) + { + var n = m_Entries[i]; + var s = n.item.intervalStart; + var e = n.item.intervalEnd; + + isDirty |= n.intervalStart != s; + isDirty |= n.intervalEnd != e; + + m_Entries[i] = new Entry() + { + intervalStart = s, + intervalEnd = e, + item = n.item + }; + } + + dirty |= isDirty; + } + + private void Query(IntervalTreeNode intervalTreeNode, Int64 value, List<T> results) + { + for (int i = intervalTreeNode.first; i <= intervalTreeNode.last; i++) + { + var entry = m_Entries[i]; + if (value >= entry.intervalStart && value < entry.intervalEnd) + { + results.Add(entry.item); + } + } + + if (intervalTreeNode.center == kCenterUnknown) + return; + if (intervalTreeNode.left != kInvalidNode && value < intervalTreeNode.center) + Query(m_Nodes[intervalTreeNode.left], value, results); + if (intervalTreeNode.right != kInvalidNode && value > intervalTreeNode.center) + Query(m_Nodes[intervalTreeNode.right], value, results); + } + + private void QueryRange(IntervalTreeNode intervalTreeNode, Int64 start, Int64 end, List<T> results) + { + for (int i = intervalTreeNode.first; i <= intervalTreeNode.last; i++) + { + var entry = m_Entries[i]; + if (end >= entry.intervalStart && start < entry.intervalEnd) + { + results.Add(entry.item); + } + } + + if (intervalTreeNode.center == kCenterUnknown) + return; + if (intervalTreeNode.left != kInvalidNode && start < intervalTreeNode.center) + QueryRange(m_Nodes[intervalTreeNode.left], start, end, results); + if (intervalTreeNode.right != kInvalidNode && end > intervalTreeNode.center) + QueryRange(m_Nodes[intervalTreeNode.right], start, end, results); + } + + private void Rebuild() + { + m_Nodes.Clear(); + m_Nodes.Capacity = m_Entries.Capacity; + Rebuild(0, m_Entries.Count - 1); + } + + private int Rebuild(int start, int end) + { + IntervalTreeNode intervalTreeNode = new IntervalTreeNode(); + + // minimum size, don't subdivide + int count = end - start + 1; + if (count < kMinNodeSize) + { + intervalTreeNode = new IntervalTreeNode() {center = kCenterUnknown, first = start, last = end, left = kInvalidNode, right = kInvalidNode}; + m_Nodes.Add(intervalTreeNode); + return m_Nodes.Count - 1; + } + + var min = Int64.MaxValue; + var max = Int64.MinValue; + + for (int i = start; i <= end; i++) + { + var o = m_Entries[i]; + min = Math.Min(min, o.intervalStart); + max = Math.Max(max, o.intervalEnd); + } + + var center = (max + min) / 2; + intervalTreeNode.center = center; + + // first pass, put every thing left of center, left + int x = start; + int y = end; + while (true) + { + while (x <= end && m_Entries[x].intervalEnd < center) + x++; + + while (y >= start && m_Entries[y].intervalEnd >= center) + y--; + + if (x > y) + break; + + var nodeX = m_Entries[x]; + var nodeY = m_Entries[y]; + + m_Entries[y] = nodeX; + m_Entries[x] = nodeY; + } + + intervalTreeNode.first = x; + + // second pass, put every start passed the center right + y = end; + while (true) + { + while (x <= end && m_Entries[x].intervalStart <= center) + x++; + + while (y >= start && m_Entries[y].intervalStart > center) + y--; + + if (x > y) + break; + + var nodeX = m_Entries[x]; + var nodeY = m_Entries[y]; + + m_Entries[y] = nodeX; + m_Entries[x] = nodeY; + } + + intervalTreeNode.last = y; + + // reserve a place + m_Nodes.Add(new IntervalTreeNode()); + int index = m_Nodes.Count - 1; + + intervalTreeNode.left = kInvalidNode; + intervalTreeNode.right = kInvalidNode; + + if (start < intervalTreeNode.first) + intervalTreeNode.left = Rebuild(start, intervalTreeNode.first - 1); + + if (end > intervalTreeNode.last) + intervalTreeNode.right = Rebuild(intervalTreeNode.last + 1, end); + + m_Nodes[index] = intervalTreeNode; + return index; + } + + public void Clear() + { + m_Entries.Clear(); + m_Nodes.Clear(); + } + } +} |
