scripts
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
|
||||
namespace KDTree
|
||||
{
|
||||
// Token: 0x02000002 RID: 2
|
||||
public interface DistanceFunctions
|
||||
{
|
||||
// Token: 0x06000001 RID: 1
|
||||
double Distance(double[] p1, double[] p2);
|
||||
|
||||
// Token: 0x06000002 RID: 2
|
||||
double DistanceToRectangle(double[] point, double[] min, double[] max);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,362 @@
|
||||
using System;
|
||||
|
||||
namespace KDTree
|
||||
{
|
||||
// Token: 0x02000004 RID: 4
|
||||
public class IntervalHeap<T>
|
||||
{
|
||||
// Token: 0x06000006 RID: 6 RVA: 0x0000211D File Offset: 0x0000031D
|
||||
public IntervalHeap()
|
||||
: this(64)
|
||||
{
|
||||
}
|
||||
|
||||
// Token: 0x06000007 RID: 7 RVA: 0x0000212A File Offset: 0x0000032A
|
||||
public IntervalHeap(int capacity)
|
||||
{
|
||||
this.tData = new T[capacity];
|
||||
this.tKeys = new double[capacity];
|
||||
this.Capacity = capacity;
|
||||
this.Size = 0;
|
||||
}
|
||||
|
||||
// Token: 0x17000001 RID: 1
|
||||
// (get) Token: 0x06000008 RID: 8 RVA: 0x00002160 File Offset: 0x00000360
|
||||
// (set) Token: 0x06000009 RID: 9 RVA: 0x00002177 File Offset: 0x00000377
|
||||
public int Size { get; private set; }
|
||||
|
||||
// Token: 0x17000002 RID: 2
|
||||
// (get) Token: 0x0600000A RID: 10 RVA: 0x00002180 File Offset: 0x00000380
|
||||
// (set) Token: 0x0600000B RID: 11 RVA: 0x00002197 File Offset: 0x00000397
|
||||
public int Capacity { get; private set; }
|
||||
|
||||
// Token: 0x17000003 RID: 3
|
||||
// (get) Token: 0x0600000C RID: 12 RVA: 0x000021A0 File Offset: 0x000003A0
|
||||
public T Min
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.Size == 0)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
return this.tData[0];
|
||||
}
|
||||
}
|
||||
|
||||
// Token: 0x17000004 RID: 4
|
||||
// (get) Token: 0x0600000D RID: 13 RVA: 0x000021D4 File Offset: 0x000003D4
|
||||
public T Max
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.Size == 0)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
T t;
|
||||
if (this.Size == 1)
|
||||
{
|
||||
t = this.tData[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
t = this.tData[1];
|
||||
}
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
// Token: 0x17000005 RID: 5
|
||||
// (get) Token: 0x0600000E RID: 14 RVA: 0x0000222C File Offset: 0x0000042C
|
||||
public double MinKey
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.Size == 0)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
return this.tKeys[0];
|
||||
}
|
||||
}
|
||||
|
||||
// Token: 0x17000006 RID: 6
|
||||
// (get) Token: 0x0600000F RID: 15 RVA: 0x0000225C File Offset: 0x0000045C
|
||||
public double MaxKey
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.Size == 0)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
double num;
|
||||
if (this.Size == 1)
|
||||
{
|
||||
num = this.tKeys[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
num = this.tKeys[1];
|
||||
}
|
||||
return num;
|
||||
}
|
||||
}
|
||||
|
||||
// Token: 0x06000010 RID: 16 RVA: 0x000022AC File Offset: 0x000004AC
|
||||
public void Insert(double key, T value)
|
||||
{
|
||||
if (this.Size >= this.Capacity)
|
||||
{
|
||||
this.Capacity *= 2;
|
||||
T[] array = new T[this.Capacity];
|
||||
Array.Copy(this.tData, array, this.tData.Length);
|
||||
this.tData = array;
|
||||
double[] array2 = new double[this.Capacity];
|
||||
Array.Copy(this.tKeys, array2, this.tKeys.Length);
|
||||
this.tKeys = array2;
|
||||
}
|
||||
this.Size++;
|
||||
this.tData[this.Size - 1] = value;
|
||||
this.tKeys[this.Size - 1] = key;
|
||||
this.SiftInsertedValueUp();
|
||||
}
|
||||
|
||||
// Token: 0x06000011 RID: 17 RVA: 0x00002368 File Offset: 0x00000568
|
||||
public void RemoveMin()
|
||||
{
|
||||
if (this.Size == 0)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
this.Size--;
|
||||
this.tData[0] = this.tData[this.Size];
|
||||
this.tKeys[0] = this.tKeys[this.Size];
|
||||
this.tData[this.Size] = default(T);
|
||||
this.SiftDownMin(0);
|
||||
}
|
||||
|
||||
// Token: 0x06000012 RID: 18 RVA: 0x000023F0 File Offset: 0x000005F0
|
||||
public void ReplaceMin(double key, T value)
|
||||
{
|
||||
if (this.Size == 0)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
this.tData[0] = value;
|
||||
this.tKeys[0] = key;
|
||||
if (this.Size > 1)
|
||||
{
|
||||
if (this.tKeys[1] < key)
|
||||
{
|
||||
this.Swap(0, 1);
|
||||
}
|
||||
this.SiftDownMin(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Token: 0x06000013 RID: 19 RVA: 0x00002460 File Offset: 0x00000660
|
||||
public void RemoveMax()
|
||||
{
|
||||
if (this.Size == 0)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
if (this.Size == 1)
|
||||
{
|
||||
this.RemoveMin();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Size--;
|
||||
this.tData[1] = this.tData[this.Size];
|
||||
this.tKeys[1] = this.tKeys[this.Size];
|
||||
this.tData[this.Size] = default(T);
|
||||
this.SiftDownMax(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Token: 0x06000014 RID: 20 RVA: 0x00002504 File Offset: 0x00000704
|
||||
public void ReplaceMax(double key, T value)
|
||||
{
|
||||
if (this.Size == 0)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
if (this.Size == 1)
|
||||
{
|
||||
this.ReplaceMin(key, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.tData[1] = value;
|
||||
this.tKeys[1] = key;
|
||||
if (key < this.tKeys[0])
|
||||
{
|
||||
this.Swap(0, 1);
|
||||
}
|
||||
this.SiftDownMax(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Token: 0x06000015 RID: 21 RVA: 0x00002580 File Offset: 0x00000780
|
||||
private int Swap(int x, int y)
|
||||
{
|
||||
T t = this.tData[y];
|
||||
double num = this.tKeys[y];
|
||||
this.tData[y] = this.tData[x];
|
||||
this.tKeys[y] = this.tKeys[x];
|
||||
this.tData[x] = t;
|
||||
this.tKeys[x] = num;
|
||||
return y;
|
||||
}
|
||||
|
||||
// Token: 0x06000016 RID: 22 RVA: 0x000025E8 File Offset: 0x000007E8
|
||||
private void SiftInsertedValueUp()
|
||||
{
|
||||
int num = this.Size - 1;
|
||||
if (num != 0)
|
||||
{
|
||||
if (num == 1)
|
||||
{
|
||||
if (this.tKeys[num] < this.tKeys[num - 1])
|
||||
{
|
||||
this.Swap(num, num - 1);
|
||||
}
|
||||
}
|
||||
else if (num % 2 == 1)
|
||||
{
|
||||
int num2 = (num / 2 - 1) | 1;
|
||||
if (this.tKeys[num] < this.tKeys[num - 1])
|
||||
{
|
||||
num = this.Swap(num, num - 1);
|
||||
if (this.tKeys[num] < this.tKeys[num2 - 1])
|
||||
{
|
||||
num = this.Swap(num, num2 - 1);
|
||||
this.SiftUpMin(num);
|
||||
}
|
||||
}
|
||||
else if (this.tKeys[num] > this.tKeys[num2])
|
||||
{
|
||||
num = this.Swap(num, num2);
|
||||
this.SiftUpMax(num);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int num2 = (num / 2 - 1) | 1;
|
||||
if (this.tKeys[num] > this.tKeys[num2])
|
||||
{
|
||||
num = this.Swap(num, num2);
|
||||
this.SiftUpMax(num);
|
||||
}
|
||||
else if (this.tKeys[num] < this.tKeys[num2 - 1])
|
||||
{
|
||||
num = this.Swap(num, num2 - 1);
|
||||
this.SiftUpMin(num);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Token: 0x06000017 RID: 23 RVA: 0x00002758 File Offset: 0x00000958
|
||||
private void SiftUpMin(int iChild)
|
||||
{
|
||||
int num = (iChild / 2 - 1) & -2;
|
||||
while (num >= 0 && this.tKeys[iChild] < this.tKeys[num])
|
||||
{
|
||||
this.Swap(iChild, num);
|
||||
iChild = num;
|
||||
num = (iChild / 2 - 1) & -2;
|
||||
}
|
||||
}
|
||||
|
||||
// Token: 0x06000018 RID: 24 RVA: 0x000027A8 File Offset: 0x000009A8
|
||||
private void SiftUpMax(int iChild)
|
||||
{
|
||||
int num = (iChild / 2 - 1) | 1;
|
||||
while (num >= 0 && this.tKeys[iChild] > this.tKeys[num])
|
||||
{
|
||||
this.Swap(iChild, num);
|
||||
iChild = num;
|
||||
num = (iChild / 2 - 1) | 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Token: 0x06000019 RID: 25 RVA: 0x000027F4 File Offset: 0x000009F4
|
||||
private void SiftDownMin(int iParent)
|
||||
{
|
||||
for (int i = iParent * 2 + 2; i < this.Size; i = iParent * 2 + 2)
|
||||
{
|
||||
if (i + 2 < this.Size && this.tKeys[i + 2] < this.tKeys[i])
|
||||
{
|
||||
i += 2;
|
||||
}
|
||||
if (this.tKeys[i] >= this.tKeys[iParent])
|
||||
{
|
||||
break;
|
||||
}
|
||||
this.Swap(iParent, i);
|
||||
if (i + 1 < this.Size && this.tKeys[i + 1] < this.tKeys[i])
|
||||
{
|
||||
this.Swap(i, i + 1);
|
||||
}
|
||||
iParent = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Token: 0x0600001A RID: 26 RVA: 0x000028B8 File Offset: 0x00000AB8
|
||||
private void SiftDownMax(int iParent)
|
||||
{
|
||||
for (int i = iParent * 2 + 1; i <= this.Size; i = iParent * 2 + 1)
|
||||
{
|
||||
if (i == this.Size)
|
||||
{
|
||||
if (this.tKeys[i - 1] > this.tKeys[iParent])
|
||||
{
|
||||
this.Swap(iParent, i - 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (i + 2 == this.Size)
|
||||
{
|
||||
if (this.tKeys[i + 1] > this.tKeys[i])
|
||||
{
|
||||
if (this.tKeys[i + 1] > this.tKeys[iParent])
|
||||
{
|
||||
this.Swap(iParent, i + 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (i + 2 < this.Size)
|
||||
{
|
||||
if (this.tKeys[i + 2] > this.tKeys[i])
|
||||
{
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
if (this.tKeys[i] <= this.tKeys[iParent])
|
||||
{
|
||||
break;
|
||||
}
|
||||
this.Swap(iParent, i);
|
||||
if (this.tKeys[i - 1] > this.tKeys[i])
|
||||
{
|
||||
this.Swap(i, i - 1);
|
||||
}
|
||||
iParent = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Token: 0x04000001 RID: 1
|
||||
private const int DEFAULT_SIZE = 64;
|
||||
|
||||
// Token: 0x04000002 RID: 2
|
||||
private T[] tData;
|
||||
|
||||
// Token: 0x04000003 RID: 3
|
||||
private double[] tKeys;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
using System;
|
||||
|
||||
namespace KDTree
|
||||
{
|
||||
// Token: 0x02000005 RID: 5
|
||||
public class KDNode<T>
|
||||
{
|
||||
// Token: 0x0600001B RID: 27 RVA: 0x00002A10 File Offset: 0x00000C10
|
||||
protected KDNode(int iDimensions, int iBucketCapacity)
|
||||
{
|
||||
this.iDimensions = iDimensions;
|
||||
this.iBucketCapacity = iBucketCapacity;
|
||||
this.Size = 0;
|
||||
this.bSinglePoint = true;
|
||||
this.tPoints = new double[iBucketCapacity + 1][];
|
||||
this.tData = new T[iBucketCapacity + 1];
|
||||
}
|
||||
|
||||
// Token: 0x17000007 RID: 7
|
||||
// (get) Token: 0x0600001C RID: 28 RVA: 0x00002A60 File Offset: 0x00000C60
|
||||
// (set) Token: 0x0600001D RID: 29 RVA: 0x00002A77 File Offset: 0x00000C77
|
||||
public int Size { get; private set; }
|
||||
|
||||
// Token: 0x17000008 RID: 8
|
||||
// (get) Token: 0x0600001E RID: 30 RVA: 0x00002A80 File Offset: 0x00000C80
|
||||
public bool IsLeaf
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.tPoints != null;
|
||||
}
|
||||
}
|
||||
|
||||
// Token: 0x0600001F RID: 31 RVA: 0x00002AA0 File Offset: 0x00000CA0
|
||||
public void AddPoint(double[] tPoint, T kValue)
|
||||
{
|
||||
KDNode<T> kdnode = this;
|
||||
while (!kdnode.IsLeaf)
|
||||
{
|
||||
kdnode.ExtendBounds(tPoint);
|
||||
kdnode.Size++;
|
||||
if (tPoint[kdnode.iSplitDimension] > kdnode.fSplitValue)
|
||||
{
|
||||
kdnode = kdnode.pRight;
|
||||
}
|
||||
else
|
||||
{
|
||||
kdnode = kdnode.pLeft;
|
||||
}
|
||||
}
|
||||
kdnode.AddLeafPoint(tPoint, kValue);
|
||||
}
|
||||
|
||||
// Token: 0x06000020 RID: 32 RVA: 0x00002B0C File Offset: 0x00000D0C
|
||||
private void AddLeafPoint(double[] tPoint, T kValue)
|
||||
{
|
||||
this.tPoints[this.Size] = tPoint;
|
||||
this.tData[this.Size] = kValue;
|
||||
this.ExtendBounds(tPoint);
|
||||
this.Size++;
|
||||
if (this.Size == this.tPoints.Length - 1)
|
||||
{
|
||||
if (this.CalculateSplit())
|
||||
{
|
||||
this.SplitLeafNode();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.IncreaseLeafCapacity();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Token: 0x06000021 RID: 33 RVA: 0x00002B90 File Offset: 0x00000D90
|
||||
private bool CheckBounds(double[] tPoint)
|
||||
{
|
||||
int i = 0;
|
||||
while (i < this.iDimensions)
|
||||
{
|
||||
bool flag;
|
||||
if (tPoint[i] > this.tMaxBound[i])
|
||||
{
|
||||
flag = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tPoint[i] >= this.tMinBound[i])
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
flag = false;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Token: 0x06000022 RID: 34 RVA: 0x00002BEC File Offset: 0x00000DEC
|
||||
private void ExtendBounds(double[] tPoint)
|
||||
{
|
||||
if (this.tMinBound == null)
|
||||
{
|
||||
this.tMinBound = new double[this.iDimensions];
|
||||
this.tMaxBound = new double[this.iDimensions];
|
||||
Array.Copy(tPoint, this.tMinBound, this.iDimensions);
|
||||
Array.Copy(tPoint, this.tMaxBound, this.iDimensions);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < this.iDimensions; i++)
|
||||
{
|
||||
if (double.IsNaN(tPoint[i]))
|
||||
{
|
||||
if (!double.IsNaN(this.tMinBound[i]) || !double.IsNaN(this.tMaxBound[i]))
|
||||
{
|
||||
this.bSinglePoint = false;
|
||||
}
|
||||
this.tMinBound[i] = double.NaN;
|
||||
this.tMaxBound[i] = double.NaN;
|
||||
}
|
||||
else if (this.tMinBound[i] > tPoint[i])
|
||||
{
|
||||
this.tMinBound[i] = tPoint[i];
|
||||
this.bSinglePoint = false;
|
||||
}
|
||||
else if (this.tMaxBound[i] < tPoint[i])
|
||||
{
|
||||
this.tMaxBound[i] = tPoint[i];
|
||||
this.bSinglePoint = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Token: 0x06000023 RID: 35 RVA: 0x00002D27 File Offset: 0x00000F27
|
||||
private void IncreaseLeafCapacity()
|
||||
{
|
||||
Array.Resize<double[]>(ref this.tPoints, this.tPoints.Length * 2);
|
||||
Array.Resize<T>(ref this.tData, this.tData.Length * 2);
|
||||
}
|
||||
|
||||
// Token: 0x06000024 RID: 36 RVA: 0x00002D58 File Offset: 0x00000F58
|
||||
private bool CalculateSplit()
|
||||
{
|
||||
bool flag;
|
||||
if (this.bSinglePoint)
|
||||
{
|
||||
flag = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
double num = 0.0;
|
||||
for (int i = 0; i < this.iDimensions; i++)
|
||||
{
|
||||
double num2 = this.tMaxBound[i] - this.tMinBound[i];
|
||||
if (double.IsNaN(num2))
|
||||
{
|
||||
num2 = 0.0;
|
||||
}
|
||||
if (num2 > num)
|
||||
{
|
||||
this.iSplitDimension = i;
|
||||
num = num2;
|
||||
}
|
||||
}
|
||||
if (num == 0.0)
|
||||
{
|
||||
flag = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.fSplitValue = (this.tMinBound[this.iSplitDimension] + this.tMaxBound[this.iSplitDimension]) * 0.5;
|
||||
if (this.fSplitValue == double.PositiveInfinity)
|
||||
{
|
||||
this.fSplitValue = double.MaxValue;
|
||||
}
|
||||
else if (this.fSplitValue == double.NegativeInfinity)
|
||||
{
|
||||
this.fSplitValue = double.MinValue;
|
||||
}
|
||||
if (this.fSplitValue == this.tMaxBound[this.iSplitDimension])
|
||||
{
|
||||
this.fSplitValue = this.tMinBound[this.iSplitDimension];
|
||||
}
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
// Token: 0x06000025 RID: 37 RVA: 0x00002EB4 File Offset: 0x000010B4
|
||||
private void SplitLeafNode()
|
||||
{
|
||||
this.pRight = new KDNode<T>(this.iDimensions, this.iBucketCapacity);
|
||||
this.pLeft = new KDNode<T>(this.iDimensions, this.iBucketCapacity);
|
||||
for (int i = 0; i < this.Size; i++)
|
||||
{
|
||||
double[] array = this.tPoints[i];
|
||||
T t = this.tData[i];
|
||||
if (array[this.iSplitDimension] > this.fSplitValue)
|
||||
{
|
||||
this.pRight.AddLeafPoint(array, t);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.pLeft.AddLeafPoint(array, t);
|
||||
}
|
||||
}
|
||||
this.tPoints = null;
|
||||
this.tData = null;
|
||||
}
|
||||
|
||||
// Token: 0x04000006 RID: 6
|
||||
protected internal int iDimensions;
|
||||
|
||||
// Token: 0x04000007 RID: 7
|
||||
protected internal int iBucketCapacity;
|
||||
|
||||
// Token: 0x04000008 RID: 8
|
||||
protected internal double[][] tPoints;
|
||||
|
||||
// Token: 0x04000009 RID: 9
|
||||
protected internal T[] tData;
|
||||
|
||||
// Token: 0x0400000A RID: 10
|
||||
protected internal KDNode<T> pLeft;
|
||||
|
||||
// Token: 0x0400000B RID: 11
|
||||
protected internal KDNode<T> pRight;
|
||||
|
||||
// Token: 0x0400000C RID: 12
|
||||
protected internal int iSplitDimension;
|
||||
|
||||
// Token: 0x0400000D RID: 13
|
||||
protected internal double fSplitValue;
|
||||
|
||||
// Token: 0x0400000E RID: 14
|
||||
protected internal double[] tMinBound;
|
||||
|
||||
// Token: 0x0400000F RID: 15
|
||||
protected internal double[] tMaxBound;
|
||||
|
||||
// Token: 0x04000010 RID: 16
|
||||
protected internal bool bSinglePoint;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
|
||||
namespace KDTree
|
||||
{
|
||||
// Token: 0x02000006 RID: 6
|
||||
public class KDTree<T> : KDNode<T>
|
||||
{
|
||||
// Token: 0x06000026 RID: 38 RVA: 0x00002F60 File Offset: 0x00001160
|
||||
public KDTree(int iDimensions)
|
||||
: base(iDimensions, 24)
|
||||
{
|
||||
}
|
||||
|
||||
// Token: 0x06000027 RID: 39 RVA: 0x00002F6E File Offset: 0x0000116E
|
||||
public KDTree(int iDimensions, int iBucketCapacity)
|
||||
: base(iDimensions, iBucketCapacity)
|
||||
{
|
||||
}
|
||||
|
||||
// Token: 0x06000028 RID: 40 RVA: 0x00002F7C File Offset: 0x0000117C
|
||||
public NearestNeighbour<T> NearestNeighbors(double[] tSearchPoint, int iMaxReturned, double fDistance = -1.0)
|
||||
{
|
||||
DistanceFunctions distanceFunctions = new SquareEuclideanDistanceFunction();
|
||||
return this.NearestNeighbors(tSearchPoint, distanceFunctions, iMaxReturned, fDistance);
|
||||
}
|
||||
|
||||
// Token: 0x06000029 RID: 41 RVA: 0x00002FA0 File Offset: 0x000011A0
|
||||
public NearestNeighbour<T> NearestNeighbors(double[] tSearchPoint, DistanceFunctions kDistanceFunction, int iMaxReturned, double fDistance)
|
||||
{
|
||||
return new NearestNeighbour<T>(this, tSearchPoint, kDistanceFunction, iMaxReturned, fDistance);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?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-9A315339FA49}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>KDTree</RootNamespace>
|
||||
<AssemblyName>KDTree</AssemblyName>
|
||||
<TargetFrameworkVersion>v2.0</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>
|
||||
<AppDesigner Include="Properties\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="DistanceFunctions.cs" />
|
||||
<Compile Include="IntervalHeap.cs" />
|
||||
<Compile Include="KDNode.cs" />
|
||||
<Compile Include="KDTree.cs" />
|
||||
<Compile Include="MinHeap.cs" />
|
||||
<Compile Include="NearestNeighbour.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="SquareEuclideanDistanceFunction.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\mscorlib\mscorlib.csproj">
|
||||
<Project>{99604a24-13d0-4c83-a3aa-9a315339fa4c}</Project>
|
||||
<Name>mscorlib</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -0,0 +1,143 @@
|
||||
using System;
|
||||
|
||||
namespace KDTree
|
||||
{
|
||||
// Token: 0x02000007 RID: 7
|
||||
public class MinHeap<T>
|
||||
{
|
||||
// Token: 0x0600002A RID: 42 RVA: 0x00002FBD File Offset: 0x000011BD
|
||||
public MinHeap()
|
||||
: this(MinHeap<T>.DEFAULT_SIZE)
|
||||
{
|
||||
}
|
||||
|
||||
// Token: 0x0600002B RID: 43 RVA: 0x00002FCD File Offset: 0x000011CD
|
||||
public MinHeap(int iCapacity)
|
||||
{
|
||||
this.tData = new T[iCapacity];
|
||||
this.tKeys = new double[iCapacity];
|
||||
this.Capacity = iCapacity;
|
||||
this.Size = 0;
|
||||
}
|
||||
|
||||
// Token: 0x17000009 RID: 9
|
||||
// (get) Token: 0x0600002C RID: 44 RVA: 0x00003000 File Offset: 0x00001200
|
||||
// (set) Token: 0x0600002D RID: 45 RVA: 0x00003017 File Offset: 0x00001217
|
||||
public int Size { get; private set; }
|
||||
|
||||
// Token: 0x1700000A RID: 10
|
||||
// (get) Token: 0x0600002E RID: 46 RVA: 0x00003020 File Offset: 0x00001220
|
||||
// (set) Token: 0x0600002F RID: 47 RVA: 0x00003037 File Offset: 0x00001237
|
||||
public int Capacity { get; private set; }
|
||||
|
||||
// Token: 0x06000030 RID: 48 RVA: 0x00003040 File Offset: 0x00001240
|
||||
public void Insert(double key, T value)
|
||||
{
|
||||
if (this.Size >= this.Capacity)
|
||||
{
|
||||
this.Capacity *= 2;
|
||||
T[] array = new T[this.Capacity];
|
||||
Array.Copy(this.tData, array, this.tData.Length);
|
||||
this.tData = array;
|
||||
double[] array2 = new double[this.Capacity];
|
||||
Array.Copy(this.tKeys, array2, this.tKeys.Length);
|
||||
this.tKeys = array2;
|
||||
}
|
||||
this.tData[this.Size] = value;
|
||||
this.tKeys[this.Size] = key;
|
||||
this.SiftUp(this.Size);
|
||||
this.Size++;
|
||||
}
|
||||
|
||||
// Token: 0x06000031 RID: 49 RVA: 0x00003100 File Offset: 0x00001300
|
||||
public void RemoveMin()
|
||||
{
|
||||
if (this.Size == 0)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
this.Size--;
|
||||
this.tData[0] = this.tData[this.Size];
|
||||
this.tKeys[0] = this.tKeys[this.Size];
|
||||
this.tData[this.Size] = default(T);
|
||||
this.SiftDown(0);
|
||||
}
|
||||
|
||||
// Token: 0x1700000B RID: 11
|
||||
// (get) Token: 0x06000032 RID: 50 RVA: 0x00003188 File Offset: 0x00001388
|
||||
public T Min
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.Size == 0)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
return this.tData[0];
|
||||
}
|
||||
}
|
||||
|
||||
// Token: 0x1700000C RID: 12
|
||||
// (get) Token: 0x06000033 RID: 51 RVA: 0x000031BC File Offset: 0x000013BC
|
||||
public double MinKey
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this.Size == 0)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
return this.tKeys[0];
|
||||
}
|
||||
}
|
||||
|
||||
// Token: 0x06000034 RID: 52 RVA: 0x000031EC File Offset: 0x000013EC
|
||||
private void SiftUp(int iChild)
|
||||
{
|
||||
int num = (iChild - 1) / 2;
|
||||
while (iChild != 0 && this.tKeys[iChild] < this.tKeys[num])
|
||||
{
|
||||
T t = this.tData[num];
|
||||
double num2 = this.tKeys[num];
|
||||
this.tData[num] = this.tData[iChild];
|
||||
this.tKeys[num] = this.tKeys[iChild];
|
||||
this.tData[iChild] = t;
|
||||
this.tKeys[iChild] = num2;
|
||||
iChild = num;
|
||||
num = (iChild - 1) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Token: 0x06000035 RID: 53 RVA: 0x00003280 File Offset: 0x00001480
|
||||
private void SiftDown(int iParent)
|
||||
{
|
||||
for (int i = iParent * 2 + 1; i < this.Size; i = iParent * 2 + 1)
|
||||
{
|
||||
if (i + 1 < this.Size && this.tKeys[i] > this.tKeys[i + 1])
|
||||
{
|
||||
i++;
|
||||
}
|
||||
if (this.tKeys[iParent] <= this.tKeys[i])
|
||||
{
|
||||
break;
|
||||
}
|
||||
T t = this.tData[iParent];
|
||||
double num = this.tKeys[iParent];
|
||||
this.tData[iParent] = this.tData[i];
|
||||
this.tKeys[iParent] = this.tKeys[i];
|
||||
this.tData[i] = t;
|
||||
this.tKeys[i] = num;
|
||||
iParent = i;
|
||||
}
|
||||
}
|
||||
|
||||
// Token: 0x04000012 RID: 18
|
||||
private static int DEFAULT_SIZE = 64;
|
||||
|
||||
// Token: 0x04000013 RID: 19
|
||||
private T[] tData;
|
||||
|
||||
// Token: 0x04000014 RID: 20
|
||||
private double[] tKeys;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace KDTree
|
||||
{
|
||||
// Token: 0x02000008 RID: 8
|
||||
public class NearestNeighbour<T> : IEnumerator
|
||||
{
|
||||
// Token: 0x06000037 RID: 55 RVA: 0x00003360 File Offset: 0x00001560
|
||||
public NearestNeighbour(KDNode<T> pRoot, double[] tSearchPoint, DistanceFunctions kDistance, int iMaxPoints, double fThreshold)
|
||||
{
|
||||
if (tSearchPoint.Length != pRoot.iDimensions)
|
||||
{
|
||||
throw new Exception("Dimensionality of search point and kd-tree are not the same.");
|
||||
}
|
||||
this.tSearchPoint = new double[tSearchPoint.Length];
|
||||
Array.Copy(tSearchPoint, this.tSearchPoint, tSearchPoint.Length);
|
||||
this.iPointsRemaining = Math.Min(iMaxPoints, pRoot.Size);
|
||||
this.fThreshold = fThreshold;
|
||||
this.kDistanceFunction = kDistance;
|
||||
this.pRoot = pRoot;
|
||||
this.iMaxPointsReturned = iMaxPoints;
|
||||
this._CurrentDistance = -1.0;
|
||||
this.pEvaluated = new IntervalHeap<T>();
|
||||
this.pPending = new MinHeap<KDNode<T>>();
|
||||
this.pPending.Insert(0.0, pRoot);
|
||||
}
|
||||
|
||||
// Token: 0x06000038 RID: 56 RVA: 0x00003444 File Offset: 0x00001644
|
||||
public bool MoveNext()
|
||||
{
|
||||
bool flag;
|
||||
if (this.iPointsRemaining == 0)
|
||||
{
|
||||
this._Current = default(T);
|
||||
flag = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (this.pPending.Size > 0 && (this.pEvaluated.Size == 0 || this.pPending.MinKey < this.pEvaluated.MinKey))
|
||||
{
|
||||
KDNode<T> kdnode = this.pPending.Min;
|
||||
this.pPending.RemoveMin();
|
||||
while (!kdnode.IsLeaf)
|
||||
{
|
||||
KDNode<T> kdnode2;
|
||||
if (this.tSearchPoint[kdnode.iSplitDimension] > kdnode.fSplitValue)
|
||||
{
|
||||
kdnode2 = kdnode.pLeft;
|
||||
kdnode = kdnode.pRight;
|
||||
}
|
||||
else
|
||||
{
|
||||
kdnode2 = kdnode.pRight;
|
||||
kdnode = kdnode.pLeft;
|
||||
}
|
||||
double num = this.kDistanceFunction.DistanceToRectangle(this.tSearchPoint, kdnode2.tMinBound, kdnode2.tMaxBound);
|
||||
if (this.fThreshold < 0.0 || num <= this.fThreshold)
|
||||
{
|
||||
if (this.pEvaluated.Size < this.iPointsRemaining || num <= this.pEvaluated.MaxKey)
|
||||
{
|
||||
this.pPending.Insert(num, kdnode2);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (kdnode.bSinglePoint)
|
||||
{
|
||||
double num = this.kDistanceFunction.Distance(kdnode.tPoints[0], this.tSearchPoint);
|
||||
if (this.fThreshold < 0.0 || num < this.fThreshold)
|
||||
{
|
||||
if (this.pEvaluated.Size < this.iPointsRemaining || num <= this.pEvaluated.MaxKey)
|
||||
{
|
||||
for (int i = 0; i < kdnode.Size; i++)
|
||||
{
|
||||
if (this.pEvaluated.Size == this.iPointsRemaining)
|
||||
{
|
||||
this.pEvaluated.ReplaceMax(num, kdnode.tData[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.pEvaluated.Insert(num, kdnode.tData[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < kdnode.Size; i++)
|
||||
{
|
||||
double num = this.kDistanceFunction.Distance(kdnode.tPoints[i], this.tSearchPoint);
|
||||
if (this.fThreshold < 0.0 || num < this.fThreshold)
|
||||
{
|
||||
if (this.pEvaluated.Size < this.iPointsRemaining)
|
||||
{
|
||||
this.pEvaluated.Insert(num, kdnode.tData[i]);
|
||||
}
|
||||
else if (num < this.pEvaluated.MaxKey)
|
||||
{
|
||||
this.pEvaluated.ReplaceMax(num, kdnode.tData[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.pEvaluated.Size == 0)
|
||||
{
|
||||
flag = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.iPointsRemaining--;
|
||||
this._CurrentDistance = this.pEvaluated.MinKey;
|
||||
this._Current = this.pEvaluated.Min;
|
||||
this.pEvaluated.RemoveMin();
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
// Token: 0x06000039 RID: 57 RVA: 0x000037D4 File Offset: 0x000019D4
|
||||
public void Reset()
|
||||
{
|
||||
this.iPointsRemaining = Math.Min(this.iMaxPointsReturned, this.pRoot.Size);
|
||||
this._CurrentDistance = -1.0;
|
||||
this.pEvaluated = new IntervalHeap<T>();
|
||||
this.pPending = new MinHeap<KDNode<T>>();
|
||||
this.pPending.Insert(0.0, this.pRoot);
|
||||
}
|
||||
|
||||
// Token: 0x1700000D RID: 13
|
||||
// (get) Token: 0x0600003A RID: 58 RVA: 0x00003840 File Offset: 0x00001A40
|
||||
object IEnumerator.Current
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._Current;
|
||||
}
|
||||
}
|
||||
|
||||
// Token: 0x1700000E RID: 14
|
||||
// (get) Token: 0x0600003B RID: 59 RVA: 0x00003860 File Offset: 0x00001A60
|
||||
public double CurrentDistance
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._CurrentDistance;
|
||||
}
|
||||
}
|
||||
|
||||
// Token: 0x1700000F RID: 15
|
||||
// (get) Token: 0x0600003C RID: 60 RVA: 0x00003878 File Offset: 0x00001A78
|
||||
public T Current
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._Current;
|
||||
}
|
||||
}
|
||||
|
||||
// Token: 0x04000017 RID: 23
|
||||
private double[] tSearchPoint;
|
||||
|
||||
// Token: 0x04000018 RID: 24
|
||||
private DistanceFunctions kDistanceFunction;
|
||||
|
||||
// Token: 0x04000019 RID: 25
|
||||
private MinHeap<KDNode<T>> pPending;
|
||||
|
||||
// Token: 0x0400001A RID: 26
|
||||
private IntervalHeap<T> pEvaluated;
|
||||
|
||||
// Token: 0x0400001B RID: 27
|
||||
private KDNode<T> pRoot = null;
|
||||
|
||||
// Token: 0x0400001C RID: 28
|
||||
private int iMaxPointsReturned = 0;
|
||||
|
||||
// Token: 0x0400001D RID: 29
|
||||
private int iPointsRemaining;
|
||||
|
||||
// Token: 0x0400001E RID: 30
|
||||
private double fThreshold;
|
||||
|
||||
// Token: 0x0400001F RID: 31
|
||||
private double _CurrentDistance = -1.0;
|
||||
|
||||
// Token: 0x04000020 RID: 32
|
||||
private T _Current = default(T);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyProduct("KDTree")]
|
||||
[assembly: AssemblyTitle("KDTree")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2013")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: Guid("b1f6e08e-691d-42c0-9eea-7e9de37deb76")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
|
||||
namespace KDTree
|
||||
{
|
||||
// Token: 0x02000003 RID: 3
|
||||
public class SquareEuclideanDistanceFunction : DistanceFunctions
|
||||
{
|
||||
// Token: 0x06000003 RID: 3 RVA: 0x00002050 File Offset: 0x00000250
|
||||
public double Distance(double[] p1, double[] p2)
|
||||
{
|
||||
double num = 0.0;
|
||||
for (int i = 0; i < p1.Length; i++)
|
||||
{
|
||||
double num2 = p1[i] - p2[i];
|
||||
num += num2 * num2;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
// Token: 0x06000004 RID: 4 RVA: 0x00002094 File Offset: 0x00000294
|
||||
public double DistanceToRectangle(double[] point, double[] min, double[] max)
|
||||
{
|
||||
double num = 0.0;
|
||||
for (int i = 0; i < point.Length; i++)
|
||||
{
|
||||
double num2 = 0.0;
|
||||
if (point[i] > max[i])
|
||||
{
|
||||
num2 = point[i] - max[i];
|
||||
}
|
||||
else if (point[i] < min[i])
|
||||
{
|
||||
num2 = point[i] - min[i];
|
||||
}
|
||||
num += num2 * num2;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user