using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Timeline; namespace UnityEditor.Timeline { interface IBounds { Rect boundingRect { get; } } class SpacePartitioner { internal class CachedList { public static readonly List Instance = new List(1000); } struct Entry : IInterval { public object item { get; set; } public long intervalStart { get; set; } public long intervalEnd { get; set; } public Rect bounds { get; set; } private const float kPrecision = 100.0f; private const float kMaxFloat = (float)long.MaxValue; private const float kMinFloat = (float)long.MinValue; static public Int64 FromFloat(float f) { if (Single.IsPositiveInfinity(f)) return long.MaxValue; if (Single.IsNegativeInfinity(f)) return long.MinValue; f = Mathf.Clamp(f, kMinFloat, kMaxFloat); // prevent overflow of floats f = Mathf.Clamp(f * kPrecision, kMinFloat, kMaxFloat); // clamp to 'long' range return (long)(f); } } const EventType k_GuiEventLock = EventType.Repaint; IntervalTree m_Tree = new IntervalTree(); List m_CacheList = new List(); public void Clear() { m_Tree.Clear(); } public void AddBounds(IBounds bounds) { AddBounds(bounds, bounds.boundingRect); } public void AddBounds(object item, Rect rect) { if (item == null) throw new ArgumentNullException("item"); m_Tree.Add(new Entry() { intervalStart = Entry.FromFloat(rect.yMin), intervalEnd = Entry.FromFloat(rect.yMax), bounds = rect, item = item } ); } /// /// Get items of type T at a given position /// /// /// /// /// /// Uses a (1,1) sized box /// Use .ToList() or .ToArray() when not enumerating the result immediately /// /// public IEnumerable GetItemsAtPosition(Vector2 position) { return GetItemsInArea(new Rect(position.x, position.y, 1, 1)); } /// /// /// /// /// /// /// public IEnumerable GetItemsInArea(Rect area) { m_CacheList.Clear(); m_Tree.IntersectsWithRange(long.MinValue, long.MaxValue, m_CacheList); var list = CachedList.Instance; list.Clear(); foreach (var i in m_CacheList) { if (i.item is T && i.bounds.Overlaps(area)) list.Add((T)i.item); } return list; } public void DebugDraw(Color fillColor, Color outlineColor) { m_CacheList.Clear(); m_Tree.IntersectsWithRange(long.MinValue, long.MaxValue, m_CacheList); HandleUtility.ApplyWireMaterial(); foreach (var item in m_CacheList) { Handles.DrawSolidRectangleWithOutline(item.bounds, fillColor, outlineColor); } } } }