This commit is contained in:
niko
2026-06-04 11:42:34 +02:00
parent f39ba70a9f
commit e720b98cd1
7488 changed files with 2493818 additions and 0 deletions
+17
View File
@@ -0,0 +1,17 @@
using System;
namespace KdTree
{
// Token: 0x02000007 RID: 7
public enum AddDuplicateBehavior
{
// Token: 0x04000006 RID: 6
Skip,
// Token: 0x04000007 RID: 7
Error,
// Token: 0x04000008 RID: 8
Update,
// Token: 0x04000009 RID: 9
Collect
}
}
+14
View File
@@ -0,0 +1,14 @@
using System;
namespace KdTree
{
// Token: 0x02000008 RID: 8
public class DuplicateNodeError : Exception
{
// Token: 0x06000023 RID: 35 RVA: 0x000021C8 File Offset: 0x000003C8
public DuplicateNodeError()
: base("Cannot Add Node With Duplicate Coordinates")
{
}
}
}
+92
View File
@@ -0,0 +1,92 @@
using System;
namespace KdTree
{
// Token: 0x02000003 RID: 3
public struct HyperRect<T>
{
// Token: 0x17000001 RID: 1
// (get) Token: 0x06000001 RID: 1 RVA: 0x00002050 File Offset: 0x00000250
// (set) Token: 0x06000002 RID: 2 RVA: 0x00002058 File Offset: 0x00000258
public T[] MinPoint
{
get
{
return this.minPoint;
}
set
{
this.minPoint = new T[value.Length];
value.CopyTo(this.minPoint, 0);
}
}
// Token: 0x17000002 RID: 2
// (get) Token: 0x06000003 RID: 3 RVA: 0x00002075 File Offset: 0x00000275
// (set) Token: 0x06000004 RID: 4 RVA: 0x0000207D File Offset: 0x0000027D
public T[] MaxPoint
{
get
{
return this.maxPoint;
}
set
{
this.maxPoint = new T[value.Length];
value.CopyTo(this.maxPoint, 0);
}
}
// Token: 0x06000005 RID: 5 RVA: 0x0000209C File Offset: 0x0000029C
public static HyperRect<T> Infinite(int dimensions, ITypeMath<T> math)
{
HyperRect<T> hyperRect = default(HyperRect<T>);
hyperRect.MinPoint = new T[dimensions];
hyperRect.MaxPoint = new T[dimensions];
for (int i = 0; i < dimensions; i++)
{
hyperRect.MinPoint[i] = math.NegativeInfinity;
hyperRect.MaxPoint[i] = math.PositiveInfinity;
}
return hyperRect;
}
// Token: 0x06000006 RID: 6 RVA: 0x00002100 File Offset: 0x00000300
public T[] GetClosestPoint(T[] toPoint, ITypeMath<T> math)
{
T[] array = new T[toPoint.Length];
for (int i = 0; i < toPoint.Length; i++)
{
if (math.Compare(this.minPoint[i], toPoint[i]) > 0)
{
array[i] = this.minPoint[i];
}
else if (math.Compare(this.maxPoint[i], toPoint[i]) < 0)
{
array[i] = this.maxPoint[i];
}
else
{
array[i] = toPoint[i];
}
}
return array;
}
// Token: 0x06000007 RID: 7 RVA: 0x00002198 File Offset: 0x00000398
public HyperRect<T> Clone()
{
return new HyperRect<T>
{
MinPoint = this.MinPoint,
MaxPoint = this.MaxPoint
};
}
// Token: 0x04000003 RID: 3
private T[] minPoint;
// Token: 0x04000004 RID: 4
private T[] maxPoint;
}
}
+41
View File
@@ -0,0 +1,41 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace KdTree
{
// Token: 0x02000006 RID: 6
public interface IKdTree<TKey, TValue> : IEnumerable<KdTreeNode<TKey, TValue>>, IEnumerable
{
// Token: 0x06000019 RID: 25
bool Add(TKey[] point, TValue value);
// Token: 0x0600001A RID: 26
bool TryFindValueAt(TKey[] point, out TValue value);
// Token: 0x0600001B RID: 27
TValue FindValueAt(TKey[] point);
// Token: 0x0600001C RID: 28
bool TryFindValue(TValue value, out TKey[] point);
// Token: 0x0600001D RID: 29
TKey[] FindValue(TValue value);
// Token: 0x0600001E RID: 30
KdTreeNode<TKey, TValue>[] RadialSearch(TKey[] center, TKey radius, int count);
// Token: 0x0600001F RID: 31
void RemoveAt(TKey[] point);
// Token: 0x06000020 RID: 32
void Clear();
// Token: 0x06000021 RID: 33
KdTreeNode<TKey, TValue>[] GetNearestNeighbours(TKey[] point, int count = 2147483647);
// Token: 0x17000009 RID: 9
// (get) Token: 0x06000022 RID: 34
int Count { get; }
}
}
+25
View File
@@ -0,0 +1,25 @@
using System;
namespace KdTree
{
// Token: 0x0200000B RID: 11
public interface INearestNeighbourList<TItem, TDistance>
{
// Token: 0x06000047 RID: 71
bool Add(TItem item, TDistance distance);
// Token: 0x06000048 RID: 72
TItem GetFurtherest();
// Token: 0x06000049 RID: 73
TItem RemoveFurtherest();
// Token: 0x1700000E RID: 14
// (get) Token: 0x0600004A RID: 74
int MaxCapacity { get; }
// Token: 0x1700000F RID: 15
// (get) Token: 0x0600004B RID: 75
int Count { get; }
}
}
+18
View File
@@ -0,0 +1,18 @@
using System;
namespace KdTree
{
// Token: 0x02000004 RID: 4
public interface IPriorityQueue<TItem, TPriority>
{
// Token: 0x06000008 RID: 8
void Enqueue(TItem item, TPriority priority);
// Token: 0x06000009 RID: 9
TItem Dequeue();
// Token: 0x17000003 RID: 3
// (get) Token: 0x0600000A RID: 10
int Count { get; }
}
}
+55
View File
@@ -0,0 +1,55 @@
using System;
namespace KdTree
{
// Token: 0x02000005 RID: 5
public interface ITypeMath<T>
{
// Token: 0x0600000B RID: 11
int Compare(T a, T b);
// Token: 0x17000004 RID: 4
// (get) Token: 0x0600000C RID: 12
T MinValue { get; }
// Token: 0x17000005 RID: 5
// (get) Token: 0x0600000D RID: 13
T MaxValue { get; }
// Token: 0x0600000E RID: 14
T Min(T a, T b);
// Token: 0x0600000F RID: 15
T Max(T a, T b);
// Token: 0x06000010 RID: 16
bool AreEqual(T a, T b);
// Token: 0x06000011 RID: 17
bool AreEqual(T[] a, T[] b);
// Token: 0x06000012 RID: 18
T Add(T a, T b);
// Token: 0x06000013 RID: 19
T Subtract(T a, T b);
// Token: 0x06000014 RID: 20
T Multiply(T a, T b);
// Token: 0x17000006 RID: 6
// (get) Token: 0x06000015 RID: 21
T Zero { get; }
// Token: 0x17000007 RID: 7
// (get) Token: 0x06000016 RID: 22
T NegativeInfinity { get; }
// Token: 0x17000008 RID: 8
// (get) Token: 0x06000017 RID: 23
T PositiveInfinity { get; }
// Token: 0x06000018 RID: 24
T DistanceSquaredBetweenPoints(T[] a, T[] b);
}
}
+11
View File
@@ -0,0 +1,11 @@
using System;
// Token: 0x02000002 RID: 2
internal struct ItemPriority<TItem, TPriority>
{
// Token: 0x04000001 RID: 1
public TItem Item;
// Token: 0x04000002 RID: 2
public TPriority Priority;
}
+552
View File
@@ -0,0 +1,552 @@
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<TKey, TValue> : IKdTree<TKey, TValue>, IEnumerable<KdTreeNode<TKey, TValue>>, IEnumerable
{
// Token: 0x06000024 RID: 36 RVA: 0x000021D5 File Offset: 0x000003D5
public KdTree(int dimensions, ITypeMath<TKey> typeMath)
{
this.dimensions = dimensions;
this.typeMath = typeMath;
this.Count = 0;
}
// Token: 0x06000025 RID: 37 RVA: 0x000021F2 File Offset: 0x000003F2
public KdTree(int dimensions, ITypeMath<TKey> 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<TKey, TValue> kdTreeNode = new KdTreeNode<TKey, TValue>(point, value);
if (this.root == null)
{
this.root = new KdTreeNode<TKey, TValue>(point, value);
}
else
{
int num = -1;
KdTreeNode<TKey, TValue> 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<TKey, TValue> removedNode)
{
if (removedNode.IsLeaf)
{
return;
}
Queue<KdTreeNode<TKey, TValue>> queue = new Queue<KdTreeNode<TKey, TValue>>();
Queue<KdTreeNode<TKey, TValue>> queue2 = new Queue<KdTreeNode<TKey, TValue>>();
if (removedNode.LeftChild != null)
{
queue2.Enqueue(removedNode.LeftChild);
}
if (removedNode.RightChild != null)
{
queue2.Enqueue(removedNode.RightChild);
}
while (queue2.Count > 0)
{
KdTreeNode<TKey, TValue> 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<TKey, TValue> 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<TKey, TValue> 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<TKey, TValue> 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<TKey, TValue>[] 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<TKey, TValue>[0];
}
new KdTreeNode<TKey, TValue>[count];
NearestNeighbourList<KdTreeNode<TKey, TValue>, TKey> nearestNeighbourList = new NearestNeighbourList<KdTreeNode<TKey, TValue>, TKey>(count, this.typeMath);
HyperRect<TKey> hyperRect = HyperRect<TKey>.Infinite(this.dimensions, this.typeMath);
this.AddNearestNeighbours(this.root, point, hyperRect, 0, nearestNeighbourList, this.typeMath.MaxValue);
count = nearestNeighbourList.Count;
KdTreeNode<TKey, TValue>[] array = new KdTreeNode<TKey, TValue>[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<TKey, TValue> node, TKey[] target, HyperRect<TKey> rect, int depth, NearestNeighbourList<KdTreeNode<TKey, TValue>, TKey> nearestNeighbours, TKey maxSearchRadiusSquared)
{
if (node == null)
{
return;
}
int num = depth % this.dimensions;
HyperRect<TKey> hyperRect = rect.Clone();
hyperRect.MaxPoint[num] = node.Point[num];
HyperRect<TKey> hyperRect2 = rect.Clone();
hyperRect2.MinPoint[num] = node.Point[num];
int num2 = this.typeMath.Compare(target[num], node.Point[num]);
HyperRect<TKey> hyperRect3 = ((num2 <= 0) ? hyperRect : hyperRect2);
HyperRect<TKey> hyperRect4 = ((num2 <= 0) ? hyperRect2 : hyperRect);
KdTreeNode<TKey, TValue> kdTreeNode = ((num2 <= 0) ? node.LeftChild : node.RightChild);
KdTreeNode<TKey, TValue> 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<TKey, TValue>[] RadialSearch(TKey[] center, TKey radius, int count)
{
NearestNeighbourList<KdTreeNode<TKey, TValue>, TKey> nearestNeighbourList = new NearestNeighbourList<KdTreeNode<TKey, TValue>, TKey>(count, this.typeMath);
this.AddNearestNeighbours(this.root, center, HyperRect<TKey>.Infinite(this.dimensions, this.typeMath), 0, nearestNeighbourList, this.typeMath.Multiply(radius, radius));
count = nearestNeighbourList.Count;
KdTreeNode<TKey, TValue>[] array = new KdTreeNode<TKey, TValue>[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<TKey, TValue> 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<KdTreeNode<TKey, TValue>> queue = new Queue<KdTreeNode<TKey, TValue>>();
queue.Enqueue(this.root);
while (queue.Count > 0)
{
KdTreeNode<TKey, TValue> kdTreeNode = queue.Dequeue();
if (kdTreeNode.Value.Equals(value))
{
point = kdTreeNode.Point;
return true;
}
for (int i = -1; i <= 1; i += 2)
{
KdTreeNode<TKey, TValue> 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<TKey, TValue> 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<TKey, TValue> node, List<KdTreeNode<TKey, TValue>> 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<TKey, TValue>[] nodes, int byDimension, int fromIndex, int toIndex)
{
for (int i = fromIndex + 1; i <= toIndex; i++)
{
int num = i;
for (;;)
{
KdTreeNode<TKey, TValue> kdTreeNode = nodes[num - 1];
KdTreeNode<TKey, TValue> 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<TKey, TValue>[] 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<KdTreeNode<TKey, TValue>> list = new List<KdTreeNode<TKey, TValue>>();
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<TKey, TValue> 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<TKey, TValue> LoadFromFile(string filename)
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
KdTree<TKey, TValue> kdTree;
using (FileStream fileStream = File.Open(filename, FileMode.Open))
{
kdTree = (KdTree<TKey, TValue>)binaryFormatter.Deserialize(fileStream);
}
return kdTree;
}
// Token: 0x0600003E RID: 62 RVA: 0x00002B9C File Offset: 0x00000D9C
public IEnumerator<KdTreeNode<TKey, TValue>> GetEnumerator()
{
Stack<KdTreeNode<TKey, TValue>> left = new Stack<KdTreeNode<TKey, TValue>>();
Stack<KdTreeNode<TKey, TValue>> right = new Stack<KdTreeNode<TKey, TValue>>();
Action<KdTreeNode<TKey, TValue>> addLeft = delegate(KdTreeNode<TKey, TValue> node)
{
if (node.LeftChild != null)
{
left.Push(node.LeftChild);
}
};
Action<KdTreeNode<TKey, TValue>> addRight = delegate(KdTreeNode<TKey, TValue> 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<TKey, TValue>>())
{
KdTreeNode<TKey, TValue> kdTreeNode = left.Pop();
addLeft(kdTreeNode);
addRight(kdTreeNode);
yield return kdTreeNode;
}
else
{
if (!right.Any<KdTreeNode<TKey, TValue>>())
{
break;
}
KdTreeNode<TKey, TValue> 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<TKey> typeMath;
// Token: 0x0400000C RID: 12
private KdTreeNode<TKey, TValue> root;
}
}
+72
View File
@@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{99604A24-13D0-4C83-A3AA-9A315339FA4A}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>KdTree</RootNamespace>
<AssemblyName>KdTreeLib</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<NoStdLib>true</NoStdLib>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<NoStdLib>true</NoStdLib>
</PropertyGroup>
<ItemGroup />
<ItemGroup>
<AppDesigner Include="Properties\" />
</ItemGroup>
<ItemGroup>
<Compile Include="AddDuplicateBehavior.cs" />
<Compile Include="DuplicateNodeError.cs" />
<Compile Include="HyperRect.cs" />
<Compile Include="IKdTree.cs" />
<Compile Include="INearestNeighbourList.cs" />
<Compile Include="IPriorityQueue.cs" />
<Compile Include="ItemPriority.cs" />
<Compile Include="ITypeMath.cs" />
<Compile Include="KdTree.cs" />
<Compile Include="KdTreeNode.cs" />
<Compile Include="Math\DoubleMath.cs" />
<Compile Include="Math\FloatMath.cs" />
<Compile Include="Math\TypeMath.cs" />
<Compile Include="NearestNeighbourList.cs" />
<Compile Include="PriorityQueue.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\mscorlib\mscorlib.csproj">
<Project>{99604a24-13d0-4c83-a3aa-9a315339fa4c}</Project>
<Name>mscorlib</Name>
</ProjectReference>
<ProjectReference Include="..\System.Core\System.Core.csproj">
<Project>{99604a24-13d0-4c83-a3aa-9a315339fa55}</Project>
<Name>System.Core</Name>
</ProjectReference>
<ProjectReference Include="..\System\System.csproj">
<Project>{99604a24-13d0-4c83-a3aa-9a315339fa56}</Project>
<Name>System</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
+100
View File
@@ -0,0 +1,100 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace KdTree
{
// Token: 0x0200000A RID: 10
[Serializable]
public class KdTreeNode<TKey, TValue>
{
// Token: 0x06000040 RID: 64 RVA: 0x00002BB3 File Offset: 0x00000DB3
public KdTreeNode()
{
}
// Token: 0x06000041 RID: 65 RVA: 0x00002BBB File Offset: 0x00000DBB
public KdTreeNode(TKey[] point, TValue value)
{
this.Point = point;
this.Value = value;
}
// Token: 0x1700000C RID: 12
internal KdTreeNode<TKey, TValue> this[int compare]
{
get
{
if (compare <= 0)
{
return this.LeftChild;
}
return this.RightChild;
}
set
{
if (compare <= 0)
{
this.LeftChild = value;
return;
}
this.RightChild = value;
}
}
// Token: 0x1700000D RID: 13
// (get) Token: 0x06000044 RID: 68 RVA: 0x00002BF9 File Offset: 0x00000DF9
public bool IsLeaf
{
get
{
return this.LeftChild == null && this.RightChild == null;
}
}
// Token: 0x06000045 RID: 69 RVA: 0x00002C0E File Offset: 0x00000E0E
public void AddDuplicate(TValue value)
{
if (this.Duplicates == null)
{
this.Duplicates = new List<TValue> { value };
return;
}
this.Duplicates.Add(value);
}
// Token: 0x06000046 RID: 70 RVA: 0x00002C38 File Offset: 0x00000E38
public override string ToString()
{
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < this.Point.Length; i++)
{
stringBuilder.Append(this.Point[i].ToString());
}
if (this.Value == null)
{
stringBuilder.Append("null");
}
else
{
stringBuilder.Append(this.Value.ToString());
}
return stringBuilder.ToString();
}
// Token: 0x0400000F RID: 15
public TKey[] Point;
// Token: 0x04000010 RID: 16
public TValue Value;
// Token: 0x04000011 RID: 17
public List<TValue> Duplicates;
// Token: 0x04000012 RID: 18
internal KdTreeNode<TKey, TValue> LeftChild;
// Token: 0x04000013 RID: 19
internal KdTreeNode<TKey, TValue> RightChild;
}
}
+103
View File
@@ -0,0 +1,103 @@
using System;
namespace KdTree.Math
{
// Token: 0x0200000E RID: 14
[Serializable]
public class DoubleMath : TypeMath<double>
{
// Token: 0x0600005C RID: 92 RVA: 0x00002FE0 File Offset: 0x000011E0
public override int Compare(double a, double b)
{
return a.CompareTo(b);
}
// Token: 0x0600005D RID: 93 RVA: 0x00002FEA File Offset: 0x000011EA
public override bool AreEqual(double a, double b)
{
return a == b;
}
// Token: 0x17000014 RID: 20
// (get) Token: 0x0600005E RID: 94 RVA: 0x00002FF0 File Offset: 0x000011F0
public override double MinValue
{
get
{
return double.MinValue;
}
}
// Token: 0x17000015 RID: 21
// (get) Token: 0x0600005F RID: 95 RVA: 0x00002FFB File Offset: 0x000011FB
public override double MaxValue
{
get
{
return double.MaxValue;
}
}
// Token: 0x17000016 RID: 22
// (get) Token: 0x06000060 RID: 96 RVA: 0x00003006 File Offset: 0x00001206
public override double Zero
{
get
{
return 0.0;
}
}
// Token: 0x17000017 RID: 23
// (get) Token: 0x06000061 RID: 97 RVA: 0x00003011 File Offset: 0x00001211
public override double NegativeInfinity
{
get
{
return double.NegativeInfinity;
}
}
// Token: 0x17000018 RID: 24
// (get) Token: 0x06000062 RID: 98 RVA: 0x0000301C File Offset: 0x0000121C
public override double PositiveInfinity
{
get
{
return double.PositiveInfinity;
}
}
// Token: 0x06000063 RID: 99 RVA: 0x00003027 File Offset: 0x00001227
public override double Add(double a, double b)
{
return a + b;
}
// Token: 0x06000064 RID: 100 RVA: 0x0000302C File Offset: 0x0000122C
public override double Subtract(double a, double b)
{
return a - b;
}
// Token: 0x06000065 RID: 101 RVA: 0x00003031 File Offset: 0x00001231
public override double Multiply(double a, double b)
{
return a * b;
}
// Token: 0x06000066 RID: 102 RVA: 0x00003038 File Offset: 0x00001238
public override double DistanceSquaredBetweenPoints(double[] a, double[] b)
{
double num = this.Zero;
int num2 = a.Length;
for (int i = 0; i < num2; i++)
{
double num3 = this.Subtract(a[i], b[i]);
double num4 = this.Multiply(num3, num3);
num = this.Add(num, num4);
}
return num;
}
}
}
+103
View File
@@ -0,0 +1,103 @@
using System;
namespace KdTree.Math
{
// Token: 0x0200000F RID: 15
[Serializable]
public class FloatMath : TypeMath<float>
{
// Token: 0x06000068 RID: 104 RVA: 0x00003086 File Offset: 0x00001286
public override int Compare(float a, float b)
{
return a.CompareTo(b);
}
// Token: 0x06000069 RID: 105 RVA: 0x00002FEA File Offset: 0x000011EA
public override bool AreEqual(float a, float b)
{
return a == b;
}
// Token: 0x17000019 RID: 25
// (get) Token: 0x0600006A RID: 106 RVA: 0x00003090 File Offset: 0x00001290
public override float MinValue
{
get
{
return float.MinValue;
}
}
// Token: 0x1700001A RID: 26
// (get) Token: 0x0600006B RID: 107 RVA: 0x00003097 File Offset: 0x00001297
public override float MaxValue
{
get
{
return float.MaxValue;
}
}
// Token: 0x1700001B RID: 27
// (get) Token: 0x0600006C RID: 108 RVA: 0x0000309E File Offset: 0x0000129E
public override float Zero
{
get
{
return 0f;
}
}
// Token: 0x1700001C RID: 28
// (get) Token: 0x0600006D RID: 109 RVA: 0x000030A5 File Offset: 0x000012A5
public override float NegativeInfinity
{
get
{
return float.NegativeInfinity;
}
}
// Token: 0x1700001D RID: 29
// (get) Token: 0x0600006E RID: 110 RVA: 0x000030AC File Offset: 0x000012AC
public override float PositiveInfinity
{
get
{
return float.PositiveInfinity;
}
}
// Token: 0x0600006F RID: 111 RVA: 0x00003027 File Offset: 0x00001227
public override float Add(float a, float b)
{
return a + b;
}
// Token: 0x06000070 RID: 112 RVA: 0x0000302C File Offset: 0x0000122C
public override float Subtract(float a, float b)
{
return a - b;
}
// Token: 0x06000071 RID: 113 RVA: 0x00003031 File Offset: 0x00001231
public override float Multiply(float a, float b)
{
return a * b;
}
// Token: 0x06000072 RID: 114 RVA: 0x000030B4 File Offset: 0x000012B4
public override float DistanceSquaredBetweenPoints(float[] a, float[] b)
{
float num = this.Zero;
int num2 = a.Length;
for (int i = 0; i < num2; i++)
{
float num3 = this.Subtract(a[i], b[i]);
float num4 = this.Multiply(num3, num3);
num = this.Add(num, num4);
}
return num;
}
}
}
+84
View File
@@ -0,0 +1,84 @@
using System;
namespace KdTree.Math
{
// Token: 0x02000010 RID: 16
[Serializable]
public abstract class TypeMath<T> : ITypeMath<T>
{
// Token: 0x06000074 RID: 116
public abstract int Compare(T a, T b);
// Token: 0x06000075 RID: 117
public abstract bool AreEqual(T a, T b);
// Token: 0x06000076 RID: 118 RVA: 0x00003104 File Offset: 0x00001304
public virtual bool AreEqual(T[] a, T[] b)
{
if (a.Length != b.Length)
{
return false;
}
for (int i = 0; i < a.Length; i++)
{
if (!this.AreEqual(a[i], b[i]))
{
return false;
}
}
return true;
}
// Token: 0x1700001E RID: 30
// (get) Token: 0x06000077 RID: 119
public abstract T MinValue { get; }
// Token: 0x1700001F RID: 31
// (get) Token: 0x06000078 RID: 120
public abstract T MaxValue { get; }
// Token: 0x06000079 RID: 121 RVA: 0x00003142 File Offset: 0x00001342
public T Min(T a, T b)
{
if (this.Compare(a, b) < 0)
{
return a;
}
return b;
}
// Token: 0x0600007A RID: 122 RVA: 0x00003152 File Offset: 0x00001352
public T Max(T a, T b)
{
if (this.Compare(a, b) > 0)
{
return a;
}
return b;
}
// Token: 0x17000020 RID: 32
// (get) Token: 0x0600007B RID: 123
public abstract T Zero { get; }
// Token: 0x17000021 RID: 33
// (get) Token: 0x0600007C RID: 124
public abstract T NegativeInfinity { get; }
// Token: 0x17000022 RID: 34
// (get) Token: 0x0600007D RID: 125
public abstract T PositiveInfinity { get; }
// Token: 0x0600007E RID: 126
public abstract T Add(T a, T b);
// Token: 0x0600007F RID: 127
public abstract T Subtract(T a, T b);
// Token: 0x06000080 RID: 128
public abstract T Multiply(T a, T b);
// Token: 0x06000081 RID: 129
public abstract T DistanceSquaredBetweenPoints(T[] a, T[] b);
}
}
+98
View File
@@ -0,0 +1,98 @@
using System;
namespace KdTree
{
// Token: 0x0200000C RID: 12
public class NearestNeighbourList<TItem, TDistance> : INearestNeighbourList<TItem, TDistance>
{
// Token: 0x0600004C RID: 76 RVA: 0x00002CB7 File Offset: 0x00000EB7
public NearestNeighbourList(int maxCapacity, ITypeMath<TDistance> distanceMath)
{
this.maxCapacity = maxCapacity;
this.distanceMath = distanceMath;
this.queue = new PriorityQueue<TItem, TDistance>(maxCapacity, distanceMath);
}
// Token: 0x17000010 RID: 16
// (get) Token: 0x0600004D RID: 77 RVA: 0x00002CDA File Offset: 0x00000EDA
public int MaxCapacity
{
get
{
return this.maxCapacity;
}
}
// Token: 0x17000011 RID: 17
// (get) Token: 0x0600004E RID: 78 RVA: 0x00002CE2 File Offset: 0x00000EE2
public int Count
{
get
{
return this.queue.Count;
}
}
// Token: 0x0600004F RID: 79 RVA: 0x00002CF0 File Offset: 0x00000EF0
public bool Add(TItem item, TDistance distance)
{
if (this.queue.Count < this.maxCapacity)
{
this.queue.Enqueue(item, distance);
return true;
}
if (this.distanceMath.Compare(distance, this.queue.GetHighestPriority()) < 0)
{
this.queue.Dequeue();
this.queue.Enqueue(item, distance);
return true;
}
return false;
}
// Token: 0x06000050 RID: 80 RVA: 0x00002D55 File Offset: 0x00000F55
public TItem GetFurtherest()
{
if (this.Count == 0)
{
throw new Exception("List is empty");
}
return this.queue.GetHighest();
}
// Token: 0x06000051 RID: 81 RVA: 0x00002D75 File Offset: 0x00000F75
public TDistance GetFurtherestDistance()
{
if (this.Count == 0)
{
throw new Exception("List is empty");
}
return this.queue.GetHighestPriority();
}
// Token: 0x06000052 RID: 82 RVA: 0x00002D95 File Offset: 0x00000F95
public TItem RemoveFurtherest()
{
return this.queue.Dequeue();
}
// Token: 0x17000012 RID: 18
// (get) Token: 0x06000053 RID: 83 RVA: 0x00002DA2 File Offset: 0x00000FA2
public bool IsCapacityReached
{
get
{
return this.Count == this.MaxCapacity;
}
}
// Token: 0x04000014 RID: 20
private PriorityQueue<TItem, TDistance> queue;
// Token: 0x04000015 RID: 21
private ITypeMath<TDistance> distanceMath;
// Token: 0x04000016 RID: 22
private int maxCapacity;
}
}
+124
View File
@@ -0,0 +1,124 @@
using System;
namespace KdTree
{
// Token: 0x0200000D RID: 13
public class PriorityQueue<TItem, TPriority> : IPriorityQueue<TItem, TPriority>
{
// Token: 0x06000054 RID: 84 RVA: 0x00002DB2 File Offset: 0x00000FB2
public PriorityQueue(int capacity, ITypeMath<TPriority> priorityMath)
{
if (capacity <= 0)
{
throw new ArgumentException("Capacity must be greater than zero");
}
this.capacity = capacity;
this.queue = new ItemPriority<TItem, TPriority>[capacity];
this.priorityMath = priorityMath;
}
// Token: 0x17000013 RID: 19
// (get) Token: 0x06000055 RID: 85 RVA: 0x00002DE3 File Offset: 0x00000FE3
public int Count
{
get
{
return this.count;
}
}
// Token: 0x06000056 RID: 86 RVA: 0x00002DEC File Offset: 0x00000FEC
private void ExpandCapacity()
{
this.capacity *= 2;
ItemPriority<TItem, TPriority>[] array = new ItemPriority<TItem, TPriority>[this.capacity];
Array.Copy(this.queue, array, this.queue.Length);
this.queue = array;
}
// Token: 0x06000057 RID: 87 RVA: 0x00002E30 File Offset: 0x00001030
public void Enqueue(TItem item, TPriority priority)
{
int num = this.count + 1;
this.count = num;
if (num > this.capacity)
{
this.ExpandCapacity();
}
int num2 = this.count - 1;
this.queue[num2] = new ItemPriority<TItem, TPriority>
{
Item = item,
Priority = priority
};
this.ReorderItem(num2, -1);
}
// Token: 0x06000058 RID: 88 RVA: 0x00002E94 File Offset: 0x00001094
public TItem Dequeue()
{
TItem item = this.queue[0].Item;
this.queue[0].Item = default(TItem);
this.queue[0].Priority = this.priorityMath.MinValue;
this.ReorderItem(0, 1);
this.count--;
return item;
}
// Token: 0x06000059 RID: 89 RVA: 0x00002EFC File Offset: 0x000010FC
private void ReorderItem(int index, int direction)
{
if (direction != -1 && direction != 1)
{
throw new ArgumentException("Invalid Direction");
}
ItemPriority<TItem, TPriority> itemPriority = this.queue[index];
int num = index + direction;
while (num >= 0 && num < this.count)
{
ItemPriority<TItem, TPriority> itemPriority2 = this.queue[num];
int num2 = this.priorityMath.Compare(itemPriority.Priority, itemPriority2.Priority);
if ((direction != -1 || num2 <= 0) && (direction != 1 || num2 >= 0))
{
break;
}
this.queue[index] = itemPriority2;
this.queue[num] = itemPriority;
index += direction;
num += direction;
}
}
// Token: 0x0600005A RID: 90 RVA: 0x00002F94 File Offset: 0x00001194
public TItem GetHighest()
{
if (this.count == 0)
{
throw new Exception("Queue is empty");
}
return this.queue[0].Item;
}
// Token: 0x0600005B RID: 91 RVA: 0x00002FBA File Offset: 0x000011BA
public TPriority GetHighestPriority()
{
if (this.count == 0)
{
throw new Exception("Queue is empty");
}
return this.queue[0].Priority;
}
// Token: 0x04000017 RID: 23
private ITypeMath<TPriority> priorityMath;
// Token: 0x04000018 RID: 24
private ItemPriority<TItem, TPriority>[] queue;
// Token: 0x04000019 RID: 25
private int capacity;
// Token: 0x0400001A RID: 26
private int count;
}
}
+17
View File
@@ -0,0 +1,17 @@
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
[assembly: AssemblyVersion("1.3.0.0")]
[assembly: AssemblyTitle("KdTreeLib")]
[assembly: AssemblyDescription("Generic multi-dimensional binary search tree")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("codeandcats@gmail.com")]
[assembly: AssemblyProduct("KdTreeLib")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("40b103e3-41e5-4a82-b9ba-384af1391862")]
[assembly: AssemblyFileVersion("1.3.0.0")]