using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.Serialization.Formatters.Binary; using System.Text; namespace KdTree { // Token: 0x02000009 RID: 9 [Serializable] public class KdTree : IKdTree, IEnumerable>, IEnumerable { // Token: 0x06000024 RID: 36 RVA: 0x000021D5 File Offset: 0x000003D5 public KdTree(int dimensions, ITypeMath typeMath) { this.dimensions = dimensions; this.typeMath = typeMath; this.Count = 0; } // Token: 0x06000025 RID: 37 RVA: 0x000021F2 File Offset: 0x000003F2 public KdTree(int dimensions, ITypeMath typeMath, AddDuplicateBehavior addDuplicateBehavior) : this(dimensions, typeMath) { this.AddDuplicateBehavior = addDuplicateBehavior; } // Token: 0x1700000A RID: 10 // (get) Token: 0x06000026 RID: 38 RVA: 0x00002203 File Offset: 0x00000403 // (set) Token: 0x06000027 RID: 39 RVA: 0x0000220B File Offset: 0x0000040B public AddDuplicateBehavior AddDuplicateBehavior { get; private set; } // Token: 0x06000028 RID: 40 RVA: 0x00002214 File Offset: 0x00000414 public bool Add(TKey[] point, TValue value) { KdTreeNode kdTreeNode = new KdTreeNode(point, value); if (this.root == null) { this.root = new KdTreeNode(point, value); } else { int num = -1; KdTreeNode kdTreeNode2 = this.root; int num2; for (;;) { num = (num + 1) % this.dimensions; if (this.typeMath.AreEqual(point, kdTreeNode2.Point)) { switch (this.AddDuplicateBehavior) { case AddDuplicateBehavior.Skip: return false; case AddDuplicateBehavior.Error: goto IL_6D; case AddDuplicateBehavior.Update: kdTreeNode2.Value = value; goto IL_90; case AddDuplicateBehavior.Collect: goto IL_7C; } break; } IL_90: num2 = this.typeMath.Compare(point[num], kdTreeNode2.Point[num]); if (kdTreeNode2[num2] == null) { goto Block_4; } kdTreeNode2 = kdTreeNode2[num2]; } throw new Exception("Unexpected AddDuplicateBehavior"); IL_6D: throw new DuplicateNodeError(); IL_7C: kdTreeNode2.AddDuplicate(value); return false; Block_4: kdTreeNode2[num2] = kdTreeNode; } int count = this.Count; this.Count = count + 1; return true; } // Token: 0x06000029 RID: 41 RVA: 0x00002304 File Offset: 0x00000504 private void ReadChildNodes(KdTreeNode removedNode) { if (removedNode.IsLeaf) { return; } Queue> queue = new Queue>(); Queue> queue2 = new Queue>(); if (removedNode.LeftChild != null) { queue2.Enqueue(removedNode.LeftChild); } if (removedNode.RightChild != null) { queue2.Enqueue(removedNode.RightChild); } while (queue2.Count > 0) { KdTreeNode kdTreeNode = queue2.Dequeue(); queue.Enqueue(kdTreeNode); for (int i = -1; i <= 1; i += 2) { if (kdTreeNode[i] != null) { queue2.Enqueue(kdTreeNode[i]); kdTreeNode[i] = null; } } } while (queue.Count > 0) { KdTreeNode kdTreeNode2 = queue.Dequeue(); int count = this.Count; this.Count = count - 1; this.Add(kdTreeNode2.Point, kdTreeNode2.Value); } } // Token: 0x0600002A RID: 42 RVA: 0x000023CC File Offset: 0x000005CC public void RemoveAt(TKey[] point) { if (this.root == null) { return; } KdTreeNode kdTreeNode; if (this.typeMath.AreEqual(point, this.root.Point)) { kdTreeNode = this.root; this.root = null; int num = this.Count; this.Count = num - 1; this.ReadChildNodes(kdTreeNode); return; } kdTreeNode = this.root; int num2 = -1; for (;;) { num2 = (num2 + 1) % this.dimensions; int num3 = this.typeMath.Compare(point[num2], kdTreeNode.Point[num2]); if (kdTreeNode[num3] == null) { break; } if (this.typeMath.AreEqual(point, kdTreeNode[num3].Point)) { KdTreeNode kdTreeNode2 = kdTreeNode[num3]; kdTreeNode[num3] = null; int num = this.Count; this.Count = num - 1; this.ReadChildNodes(kdTreeNode2); } else { kdTreeNode = kdTreeNode[num3]; } if (kdTreeNode == null) { return; } } } // Token: 0x0600002B RID: 43 RVA: 0x000024B4 File Offset: 0x000006B4 public KdTreeNode[] GetNearestNeighbours(TKey[] point, int count) { if (count > this.Count) { count = this.Count; } if (count < 0) { throw new ArgumentException("Number of neighbors cannot be negative"); } if (count == 0) { return new KdTreeNode[0]; } new KdTreeNode[count]; NearestNeighbourList, TKey> nearestNeighbourList = new NearestNeighbourList, TKey>(count, this.typeMath); HyperRect hyperRect = HyperRect.Infinite(this.dimensions, this.typeMath); this.AddNearestNeighbours(this.root, point, hyperRect, 0, nearestNeighbourList, this.typeMath.MaxValue); count = nearestNeighbourList.Count; KdTreeNode[] array = new KdTreeNode[count]; for (int i = 0; i < count; i++) { array[count - i - 1] = nearestNeighbourList.RemoveFurtherest(); } return array; } // Token: 0x0600002C RID: 44 RVA: 0x00002558 File Offset: 0x00000758 private void AddNearestNeighbours(KdTreeNode node, TKey[] target, HyperRect rect, int depth, NearestNeighbourList, TKey> nearestNeighbours, TKey maxSearchRadiusSquared) { if (node == null) { return; } int num = depth % this.dimensions; HyperRect hyperRect = rect.Clone(); hyperRect.MaxPoint[num] = node.Point[num]; HyperRect hyperRect2 = rect.Clone(); hyperRect2.MinPoint[num] = node.Point[num]; int num2 = this.typeMath.Compare(target[num], node.Point[num]); HyperRect hyperRect3 = ((num2 <= 0) ? hyperRect : hyperRect2); HyperRect hyperRect4 = ((num2 <= 0) ? hyperRect2 : hyperRect); KdTreeNode kdTreeNode = ((num2 <= 0) ? node.LeftChild : node.RightChild); KdTreeNode kdTreeNode2 = ((num2 <= 0) ? node.RightChild : node.LeftChild); if (kdTreeNode != null) { this.AddNearestNeighbours(kdTreeNode, target, hyperRect3, depth + 1, nearestNeighbours, maxSearchRadiusSquared); } TKey[] closestPoint = hyperRect4.GetClosestPoint(target, this.typeMath); TKey tkey = this.typeMath.DistanceSquaredBetweenPoints(closestPoint, target); if (this.typeMath.Compare(tkey, maxSearchRadiusSquared) <= 0) { if (nearestNeighbours.IsCapacityReached) { if (this.typeMath.Compare(tkey, nearestNeighbours.GetFurtherestDistance()) < 0) { this.AddNearestNeighbours(kdTreeNode2, target, hyperRect4, depth + 1, nearestNeighbours, maxSearchRadiusSquared); } } else { this.AddNearestNeighbours(kdTreeNode2, target, hyperRect4, depth + 1, nearestNeighbours, maxSearchRadiusSquared); } } tkey = this.typeMath.DistanceSquaredBetweenPoints(node.Point, target); if (this.typeMath.Compare(tkey, maxSearchRadiusSquared) <= 0) { nearestNeighbours.Add(node, tkey); } } // Token: 0x0600002D RID: 45 RVA: 0x000026D0 File Offset: 0x000008D0 public KdTreeNode[] RadialSearch(TKey[] center, TKey radius, int count) { NearestNeighbourList, TKey> nearestNeighbourList = new NearestNeighbourList, TKey>(count, this.typeMath); this.AddNearestNeighbours(this.root, center, HyperRect.Infinite(this.dimensions, this.typeMath), 0, nearestNeighbourList, this.typeMath.Multiply(radius, radius)); count = nearestNeighbourList.Count; KdTreeNode[] array = new KdTreeNode[count]; for (int i = 0; i < count; i++) { array[count - i - 1] = nearestNeighbourList.RemoveFurtherest(); } return array; } // Token: 0x1700000B RID: 11 // (get) Token: 0x0600002E RID: 46 RVA: 0x00002740 File Offset: 0x00000940 // (set) Token: 0x0600002F RID: 47 RVA: 0x00002748 File Offset: 0x00000948 public int Count { get; private set; } // Token: 0x06000030 RID: 48 RVA: 0x00002754 File Offset: 0x00000954 public bool TryFindValueAt(TKey[] point, out TValue value) { KdTreeNode kdTreeNode = this.root; int num = -1; while (kdTreeNode != null) { if (this.typeMath.AreEqual(point, kdTreeNode.Point)) { value = kdTreeNode.Value; return true; } num = (num + 1) % this.dimensions; int num2 = this.typeMath.Compare(point[num], kdTreeNode.Point[num]); kdTreeNode = kdTreeNode[num2]; } value = default(TValue); return false; } // Token: 0x06000031 RID: 49 RVA: 0x000027CC File Offset: 0x000009CC public TValue FindValueAt(TKey[] point) { TValue tvalue; if (this.TryFindValueAt(point, out tvalue)) { return tvalue; } return default(TValue); } // Token: 0x06000032 RID: 50 RVA: 0x000027F0 File Offset: 0x000009F0 public bool TryFindValue(TValue value, out TKey[] point) { if (this.root == null) { point = null; return false; } Queue> queue = new Queue>(); queue.Enqueue(this.root); while (queue.Count > 0) { KdTreeNode kdTreeNode = queue.Dequeue(); if (kdTreeNode.Value.Equals(value)) { point = kdTreeNode.Point; return true; } for (int i = -1; i <= 1; i += 2) { KdTreeNode kdTreeNode2 = kdTreeNode[i]; if (kdTreeNode2 != null) { queue.Enqueue(kdTreeNode2); } } } point = null; return false; } // Token: 0x06000033 RID: 51 RVA: 0x00002874 File Offset: 0x00000A74 public TKey[] FindValue(TValue value) { TKey[] array; if (this.TryFindValue(value, out array)) { return array; } return null; } // Token: 0x06000034 RID: 52 RVA: 0x00002890 File Offset: 0x00000A90 private void AddNodeToStringBuilder(KdTreeNode node, StringBuilder sb, int depth) { sb.AppendLine(node.ToString()); for (int i = -1; i <= 1; i += 2) { for (int j = 0; j <= depth; j++) { sb.Append("\t"); } sb.Append((i == -1) ? "L " : "R "); if (node[i] == null) { sb.AppendLine(""); } else { this.AddNodeToStringBuilder(node[i], sb, depth + 1); } } } // Token: 0x06000035 RID: 53 RVA: 0x00002910 File Offset: 0x00000B10 public override string ToString() { if (this.root == null) { return ""; } StringBuilder stringBuilder = new StringBuilder(); this.AddNodeToStringBuilder(this.root, stringBuilder, 0); return stringBuilder.ToString(); } // Token: 0x06000036 RID: 54 RVA: 0x00002948 File Offset: 0x00000B48 private void AddNodesToList(KdTreeNode node, List> nodes) { if (node == null) { return; } nodes.Add(node); for (int i = -1; i <= 1; i += 2) { if (node[i] != null) { this.AddNodesToList(node[i], nodes); node[i] = null; } } } // Token: 0x06000037 RID: 55 RVA: 0x0000298C File Offset: 0x00000B8C private void SortNodesArray(KdTreeNode[] nodes, int byDimension, int fromIndex, int toIndex) { for (int i = fromIndex + 1; i <= toIndex; i++) { int num = i; for (;;) { KdTreeNode kdTreeNode = nodes[num - 1]; KdTreeNode kdTreeNode2 = nodes[num]; if (this.typeMath.Compare(kdTreeNode2.Point[byDimension], kdTreeNode.Point[byDimension]) >= 0) { break; } nodes[num - 1] = kdTreeNode2; nodes[num] = kdTreeNode; } } } // Token: 0x06000038 RID: 56 RVA: 0x000029E8 File Offset: 0x00000BE8 private void AddNodesBalanced(KdTreeNode[] nodes, int byDimension, int fromIndex, int toIndex) { if (fromIndex == toIndex) { this.Add(nodes[fromIndex].Point, nodes[fromIndex].Value); nodes[fromIndex] = null; return; } this.SortNodesArray(nodes, byDimension, fromIndex, toIndex); int num = fromIndex + (int)Math.Round((double)((float)(toIndex + 1 - fromIndex) / 2f)) - 1; this.Add(nodes[num].Point, nodes[num].Value); nodes[num] = null; int num2 = (byDimension + 1) % this.dimensions; if (fromIndex < num) { this.AddNodesBalanced(nodes, num2, fromIndex, num - 1); } if (toIndex > num) { this.AddNodesBalanced(nodes, num2, num + 1, toIndex); } } // Token: 0x06000039 RID: 57 RVA: 0x00002A84 File Offset: 0x00000C84 public void Balance() { List> list = new List>(); this.AddNodesToList(this.root, list); this.Clear(); this.AddNodesBalanced(list.ToArray(), 0, 0, list.Count - 1); } // Token: 0x0600003A RID: 58 RVA: 0x00002AC0 File Offset: 0x00000CC0 private void RemoveChildNodes(KdTreeNode node) { for (int i = -1; i <= 1; i += 2) { if (node[i] != null) { this.RemoveChildNodes(node[i]); node[i] = null; } } } // Token: 0x0600003B RID: 59 RVA: 0x00002AF7 File Offset: 0x00000CF7 public void Clear() { if (this.root != null) { this.RemoveChildNodes(this.root); } } // Token: 0x0600003C RID: 60 RVA: 0x00002B10 File Offset: 0x00000D10 public void SaveToFile(string filename) { BinaryFormatter binaryFormatter = new BinaryFormatter(); using (FileStream fileStream = File.Create(filename)) { binaryFormatter.Serialize(fileStream, this); fileStream.Flush(); } } // Token: 0x0600003D RID: 61 RVA: 0x00002B54 File Offset: 0x00000D54 public static KdTree LoadFromFile(string filename) { BinaryFormatter binaryFormatter = new BinaryFormatter(); KdTree kdTree; using (FileStream fileStream = File.Open(filename, FileMode.Open)) { kdTree = (KdTree)binaryFormatter.Deserialize(fileStream); } return kdTree; } // Token: 0x0600003E RID: 62 RVA: 0x00002B9C File Offset: 0x00000D9C public IEnumerator> GetEnumerator() { Stack> left = new Stack>(); Stack> right = new Stack>(); Action> addLeft = delegate(KdTreeNode node) { if (node.LeftChild != null) { left.Push(node.LeftChild); } }; Action> addRight = delegate(KdTreeNode node) { if (node.RightChild != null) { right.Push(node.RightChild); } }; if (this.root != null) { yield return this.root; addLeft(this.root); addRight(this.root); for (;;) { if (left.Any>()) { KdTreeNode kdTreeNode = left.Pop(); addLeft(kdTreeNode); addRight(kdTreeNode); yield return kdTreeNode; } else { if (!right.Any>()) { break; } KdTreeNode kdTreeNode2 = right.Pop(); addLeft(kdTreeNode2); addRight(kdTreeNode2); yield return kdTreeNode2; } } } yield break; } // Token: 0x0600003F RID: 63 RVA: 0x00002BAB File Offset: 0x00000DAB IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } // Token: 0x0400000A RID: 10 private int dimensions; // Token: 0x0400000B RID: 11 private ITypeMath typeMath; // Token: 0x0400000C RID: 12 private KdTreeNode root; } }