diff --git a/Content/BP_PointCloud.uasset b/Content/BP_PointCloud.uasset
index b730c627f98a9a952404a479005bc656cb881805..630f4bc467f5517f4b0d0712ef2c32feeb0479c6 100644
Binary files a/Content/BP_PointCloud.uasset and b/Content/BP_PointCloud.uasset differ
diff --git a/Content/MagicWandMap.umap b/Content/MagicWandMap.umap
index 1db0e16a514f1f959cebb98ac2a2e703aacb7123..bd7492ae734fcd1e7e27825d4ae8845abe574fec 100644
Binary files a/Content/MagicWandMap.umap and b/Content/MagicWandMap.umap differ
diff --git a/Plugins/UEPlugin-Kdtree b/Plugins/UEPlugin-Kdtree
new file mode 160000
index 0000000000000000000000000000000000000000..94ef56d465cf19d96e17b6e34c3a3739e1384a7e
--- /dev/null
+++ b/Plugins/UEPlugin-Kdtree
@@ -0,0 +1 @@
+Subproject commit 94ef56d465cf19d96e17b6e34c3a3739e1384a7e
diff --git a/Source/MetaCastBachelor/MagicWand.cpp b/Source/MetaCastBachelor/MagicWand.cpp
index 85419994c0a810256f93296032dbcb11374cb068..4b2f64b31da4379dd4a162aac5eccaa57b57b51b 100644
--- a/Source/MetaCastBachelor/MagicWand.cpp
+++ b/Source/MetaCastBachelor/MagicWand.cpp
@@ -1,4 +1,6 @@
 #include "MagicWand.h"
+
+#include "KdtreeBPLibrary.h"
 #include "Utilities.h"
 #include "Generators/MarchingCubes.h"
 
@@ -88,7 +90,7 @@ void UMagicWand::InitMagicWandSelection()
 	World = GetWorld();
 	
 	AbortMarchingCubes = true;
-	AccumulatedTime = 0.0f;
+	//AccumulatedTime = 0.0f;
 }
 
 void UMagicWand::SelectParticles(const FVector& InputPosition)
@@ -96,7 +98,8 @@ void UMagicWand::SelectParticles(const FVector& InputPosition)
 	if (AccumulatedTime >=  1 / EvaluationsPerSecond)
 	{
 		AccumulatedTime = -10000;
-		
+
+		UE_LOG(LogTemp, Warning, TEXT("Input recognized!"));
 		AsyncTask(ENamedThreads::Type::AnyBackgroundHiPriTask, [this]()
 		{
 			const FVector SelectionWorldPosition = SelectionObject->GetComponentLocation();
@@ -104,7 +107,7 @@ void UMagicWand::SelectParticles(const FVector& InputPosition)
 
 			PerformMagicWandSelection(SelectionLocalPosition);
 
-			UE_LOG(LogTemp, Warning, TEXT("Calculations done!"));
+			//UE_LOG(LogTemp, Warning, TEXT("Calculations done!"));
 		});
 		
 	}
@@ -118,6 +121,8 @@ void UMagicWand::PerformMagicWandSelection(const FVector& InputPosition)
         return;
     }
 
+	UE_LOG(LogTemp, Warning, TEXT("Starting Selection!"));
+
 	//UE_LOG(LogTemp, Warning, TEXT("Looking for Seed Index:"));
     // Find the closest point to the input position as the seed
     const int32 InputVoxelIndex = MyDensityField->WorldPositionToIndex(InputPosition);
@@ -126,21 +131,42 @@ void UMagicWand::PerformMagicWandSelection(const FVector& InputPosition)
     int32 SeedIndex = INDEX_NONE;
     float MinDistance = FLT_MAX;
 
-    for (const int CurrentNeighborIndex : Neighbors)
-    {
-	    TArray<int32> PointIndices = MyDensityField->VoxelPointLookupTable->GetPointsInVoxel(CurrentNeighborIndex);
 
-    	for(const int32 CurrentIndex : PointIndices)
-    	{
-    		FVector CurrentPosition = MyDensityField->IndexToVoxelPosition(CurrentIndex);
-    		const float Distance = FVector::Dist(InputPosition, CurrentPosition);
-    		if (Distance < MinDistance)
-    		{
-    			MinDistance = Distance;
-    			SeedIndex = CurrentIndex;
-    		}
-    	}
-    }
+	for(int NeighborDistance = 0; NeighborDistance < 3; ++NeighborDistance)
+	{
+		const int NumNeighbors = Neighbors.Num();
+
+		for (int i = 0; i < NumNeighbors; ++i)
+		{
+			const int CurrentNeighborIndex = Neighbors[i];
+			TArray<int32> NeighborsOfNeighbors = MyDensityField->IndexToVoxelNeighbors(CurrentNeighborIndex);
+
+			for (int CurrentNeighborOfNeighborIndex : NeighborsOfNeighbors)
+			{
+				if (!Neighbors.Contains(CurrentNeighborOfNeighborIndex))
+				{
+					Neighbors.Add(CurrentNeighborOfNeighborIndex);
+				}
+			}
+		}
+	}
+	
+    
+	for (const int CurrentNeighborIndex : Neighbors)
+	{
+		TArray<int32> PointIndices = MyDensityField->VoxelPointLookupTable->GetPointsInVoxel(CurrentNeighborIndex);
+
+		for(const int32 CurrentIndex : PointIndices)
+		{
+			FVector CurrentPosition = MyDensityField->IndexToVoxelPosition(CurrentIndex);
+			const float Distance = FVector::Dist(InputPosition, CurrentPosition);
+			if (Distance < MinDistance)
+			{
+				MinDistance = Distance;
+				SeedIndex = CurrentIndex;
+			}
+		}
+	}
 
     if (SeedIndex != INDEX_NONE)
     {
@@ -149,80 +175,76 @@ void UMagicWand::PerformMagicWandSelection(const FVector& InputPosition)
     	
         //Expand selection from the seed
         ExpandSelection(SeedIndex);
+    }else
+    {
+	    AccumulatedTime = 0;
     }
-
-	
 }
 
 void UMagicWand::ExpandSelection(const int32 SeedIndex)
 {
+	UE_LOG(LogTemp, Warning, TEXT("Expanding!"));
     TQueue<int32> ToProcess;
     ToProcess.Enqueue(SeedIndex);
 	
     SelectedClusterIndices.Add(SeedIndex);
     MyPointCloud->SelectionFlags[SeedIndex] = true;
+
+	const float SquaredProximityThreshold = ProximityThreshold * ProximityThreshold;
+	TArray<int> Indices;
+	TArray<FVector> Data;
 	
     while (!ToProcess.IsEmpty())
     {
         int32 CurrentQueuePointIndex;
         ToProcess.Dequeue(CurrentQueuePointIndex);
 
-        FVector CurrentQueuePointPosition = MyPointCloud->PositionVectors[CurrentQueuePointIndex];
+        const FVector CurrentQueuePointPosition = MyPointCloud->PositionVectors[CurrentQueuePointIndex];
 
-    	const int32 CurrentVoxelQueueIndex = MyDensityField->WorldPositionToIndex(CurrentQueuePointPosition);
-
-    	/*
-    	TArray<int32> Neighbors = MyDensityField->IndexToVoxelNeighbors(CurrentVoxelQueueIndex);
-    	Neighbors.Add(CurrentVoxelQueueIndex);
+    	Indices.Empty();
+    	Data.Empty();
     	
-    	for (const int CurrentVoxelNeighborIndex : Neighbors)
-    	{    		
-    		TArray<int32> PointIndices = MyDensityField->VoxelPointLookupTable->GetPointsInVoxel(CurrentVoxelNeighborIndex);
-
-    		for(const int32 CurrentPointComparisonIndex : PointIndices)
-    		{
-    			if(MyPointCloud->SelectionFlags[CurrentPointComparisonIndex])
-    			{
-    				continue;
-    			}
-    			FVector CurrentComparisonPosition = MyDensityField->IndexToVoxelPosition(CurrentPointComparisonIndex);
-
-    			if (FVector::Dist(CurrentQueuePointPosition, CurrentComparisonPosition) <= ProximityThreshold)
-    			{
-    				ToProcess.Enqueue(CurrentPointComparisonIndex);
-    				SelectedClusterIndices.Add(CurrentPointComparisonIndex);
-    				MyPointCloud->SelectionFlags[CurrentPointComparisonIndex] = true;
-    			}
-    		}
-    	}*/
-		// -------------------
+    	UKdtreeBPLibrary::CollectFromKdtree(MyPointCloud->MyKdTree, CurrentQueuePointPosition, MyPointCloud->InfluenceRadius, Indices, Data);
 
+		for(int i = 0; i < Indices.Num(); ++i)
+		{
+			const int CurrentPointComparisonIndex = Indices[i];
+			
+			if(MyPointCloud->SelectionFlags[CurrentPointComparisonIndex])
+			{
+				continue;
+			}
+			
+			ToProcess.Enqueue(CurrentPointComparisonIndex);
+			MyPointCloud->SelectionFlags[CurrentPointComparisonIndex] = true;
+		}
+    	
+    	/*
     	const int32 StartX = FMath::Max(0, FMath::FloorToInt((CurrentQueuePointPosition.X - ProximityThreshold - MyPointCloud->MinBounds.X) / MyDensityField->GetStep().X));
     	const int32 EndX = FMath::Min(MyDensityField->GetXNum() - 1, FMath::FloorToInt((CurrentQueuePointPosition.X + ProximityThreshold - MyPointCloud->MinBounds.X) / MyDensityField->GetStep().X));
     	const int32 StartY = FMath::Max(0, FMath::FloorToInt((CurrentQueuePointPosition.Y - ProximityThreshold - MyPointCloud->MinBounds.Y) / MyDensityField->GetStep().Y));
     	const int32 EndY = FMath::Min(MyDensityField->GetYNum() - 1, FMath::FloorToInt((CurrentQueuePointPosition.Y + ProximityThreshold - MyPointCloud->MinBounds.Y) / MyDensityField->GetStep().Y));
     	const int32 StartZ = FMath::Max(0, FMath::FloorToInt((CurrentQueuePointPosition.Z - ProximityThreshold - MyPointCloud->MinBounds.Z) / MyDensityField->GetStep().Z));
     	const int32 EndZ = FMath::Min(MyDensityField->GetZNum() - 1, FMath::FloorToInt((CurrentQueuePointPosition.Z + ProximityThreshold - MyPointCloud->MinBounds.Z) / MyDensityField->GetStep().Z));
-
-
-    	/*
+    	
+    	
     	UE_LOG(LogTemp, Warning, TEXT("CurrentQueuePointPosition: %s"), *CurrentQueuePointPosition.ToString());
     	UE_LOG(LogTemp, Warning, TEXT("StartX: %d"), StartX);
     	UE_LOG(LogTemp, Warning, TEXT("EndX: %d"), EndX);
     	UE_LOG(LogTemp, Warning, TEXT("StartY: %d"), StartY);
     	UE_LOG(LogTemp, Warning, TEXT("EndY: %d"), EndY);
     	UE_LOG(LogTemp, Warning, TEXT("StartZ: %d"), StartZ);
-    	UE_LOG(LogTemp, Warning, TEXT("EndZ: %d"), EndZ);*/
+    	UE_LOG(LogTemp, Warning, TEXT("EndZ: %d"), EndZ);
 
-    	ParallelFor(EndZ - StartZ + 1, [&](const int32 ZOffset) {
-		    const int32 Z = StartZ + ZOffset;
-			
+    	for (int32 Z = StartZ; Z <= EndZ; ++Z)
+    	{			
     		for (int32 Y = StartY; Y <= EndY; ++Y)
     		{
 				for (int32 X = StartX; X <= EndX; ++X)
 				{
 					const int32 CurrentVoxelComparisonIndex = MyDensityField->GridPositionToIndex(X, Y, Z);
 
+					/*
 					if(!MyDensityField->IsValidIndex(CurrentVoxelComparisonIndex))
 					{
 						continue;
@@ -238,26 +260,21 @@ void UMagicWand::ExpandSelection(const int32 SeedIndex)
 						}
     					
 						FVector CurrentComparisonPosition = MyPointCloud->PositionVectors[CurrentPointComparisonIndex];
-						const double Distance = FVector::Distance(CurrentQueuePointPosition, CurrentComparisonPosition);
-
-						//UE_LOG(LogTemp, Warning, TEXT("CurrentQueuePointPosition: %s"), *CurrentQueuePointPosition.ToString());
-						//UE_LOG(LogTemp, Warning, TEXT("CurrentComparisonPosition: %s"), *CurrentComparisonPosition.ToString());
+						const double SquaredDistance = FVector::DistSquared(CurrentQueuePointPosition, CurrentComparisonPosition);
 
-						//UE_LOG(LogTemp, Warning, TEXT("Distance: %f"), Distance);
-
-						if (Distance <= ProximityThreshold)
+						if (SquaredDistance <= SquaredProximityThreshold)
 						{
 							ToProcess.Enqueue(CurrentPointComparisonIndex);
-							SelectedClusterIndices.Add(CurrentPointComparisonIndex);
+							//SelectedClusterIndices.Add(CurrentPointComparisonIndex);
 							MyPointCloud->SelectionFlags[CurrentPointComparisonIndex] = true;
 						}
 					}
 				}
 			}
-		});
-    	
+		}*/
     }
 
+	UE_LOG(LogTemp, Warning, TEXT("Calculations done!"));
 	AccumulatedTime = 0;
 }
 
diff --git a/Source/MetaCastBachelor/MagicWand.h b/Source/MetaCastBachelor/MagicWand.h
index a59cde4361a78a9264d4b423cff265ffddc52c9b..e84de2e169ddbefc7983caa6f739693055a0104a 100644
--- a/Source/MetaCastBachelor/MagicWand.h
+++ b/Source/MetaCastBachelor/MagicWand.h
@@ -30,6 +30,7 @@ class UMagicWand : public UMetaCastBaseline
 	float MarchingCubeSize = 0;
 	UPROPERTY(EditAnywhere)
 	int EvaluationsPerSecond = 10;
+	UPROPERTY(EditAnywhere)
 	float AccumulatedTime = 0.0;
 	UPROPERTY(EditAnywhere)
 	float ProximityThreshold = 0.1f;
diff --git a/Source/MetaCastBachelor/MetaCastBachelor.Build.cs b/Source/MetaCastBachelor/MetaCastBachelor.Build.cs
index 89ad2bf109f5efc435ddf3eb31f0c0a180427878..26018c6cd8b8a9be0fbf29a9ff606fc2c9973a1b 100644
--- a/Source/MetaCastBachelor/MetaCastBachelor.Build.cs
+++ b/Source/MetaCastBachelor/MetaCastBachelor.Build.cs
@@ -10,7 +10,7 @@ public class MetaCastBachelor : ModuleRules
 	
 		PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "ProceduralMeshComponent", "EnhancedInput"});
 
-		PrivateDependencyModuleNames.AddRange(new string[] {"GPUPointCloudRenderer", "GPUPointCloudRendererEditor", "RWTHVRToolkit", "ProceduralMeshComponent"});
+		PrivateDependencyModuleNames.AddRange(new string[] {"GPUPointCloudRenderer", "GPUPointCloudRendererEditor", "RWTHVRToolkit", "ProceduralMeshComponent", "Kdtree"});
 
 		// Uncomment if you are using Slate UI
 		// PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
diff --git a/Source/MetaCastBachelor/MetaPoint.cpp b/Source/MetaCastBachelor/MetaPoint.cpp
index 2e908f081531254cac5f4c038fb546e1cd7c5f26..e42fe892d1832d81a714777f8d1bc68910814102 100644
--- a/Source/MetaCastBachelor/MetaPoint.cpp
+++ b/Source/MetaCastBachelor/MetaPoint.cpp
@@ -1,7 +1,6 @@
 #include "MetaPoint.h"
 #include "Utilities.h"
 #include "Generators/MarchingCubes.h"
-#include "UObject/GCObjectScopeGuard.h"
 
 UMetaPoint::UMetaPoint() : LocalMaximumIndex(0), MyDensityField(nullptr), MetaPointThreshold(0), World(nullptr)
 {
diff --git a/Source/MetaCastBachelor/PointCloud.cpp b/Source/MetaCastBachelor/PointCloud.cpp
index d319ce91f39e29ecdb9443e723229bac0bd796cc..a5f6813ffe3a9127732fc9946fb34915cc576035 100644
--- a/Source/MetaCastBachelor/PointCloud.cpp
+++ b/Source/MetaCastBachelor/PointCloud.cpp
@@ -1,9 +1,10 @@
 #include "PointCloud.h"
+#include "KdtreeBPLibrary.h"
 #include "PointCloudDataReader.h"
 
 // Sets default values
 APointCloud::APointCloud()
-	: MyDensityField(nullptr), PointCloudVisualizer(nullptr), SelectedMaterial(nullptr), UnselectedMaterial(nullptr)
+	: MyDensityField(nullptr), MyKdTree(), PointCloudVisualizer(nullptr), SelectedMaterial(nullptr), UnselectedMaterial(nullptr)
 {
 	// Set this actor to call Tick() every frame.
 	PrimaryActorTick.bCanEverTick = true;
@@ -18,6 +19,10 @@ void APointCloud::BeginPlay()
 	ReadPointCloudFromFile(PointInputData, FlagInputData);
 	InitPointCloudVisualizer();
 	SetupDensityFieldFromPointCloud();
+	
+	UKdtreeBPLibrary::BuildKdtree(MyKdTree, PositionVectors);
+	//UKdtreeBPLibrary::DumpKdtreeToConsole(MyKdTree);
+	UKdtreeBPLibrary::ValidateKdtree(MyKdTree);
 }
 
 void APointCloud::ReadPointCloudFromFile(const FFilePath FileNamePoints, const FFilePath FileNameFlags)
diff --git a/Source/MetaCastBachelor/PointCloud.h b/Source/MetaCastBachelor/PointCloud.h
index 9de2a628025c9b51483411f91b94d78166a0cca7..68b6499becbfef3bf8418d98dad08bdc37cfb567 100644
--- a/Source/MetaCastBachelor/PointCloud.h
+++ b/Source/MetaCastBachelor/PointCloud.h
@@ -1,6 +1,7 @@
 #pragma once
 #include "CoreMinimal.h"
 #include "GPUPointCloudRendererComponent.h"
+#include "KdtreeCommon.h"
 #include "GameFramework/Actor.h"
 #include "MetaCastBachelor/DensityField.h"
 #include "PointCloud.generated.h"
@@ -12,29 +13,30 @@ class APointCloud : public AActor
 	GENERATED_BODY()
 	
 public:
-	UPROPERTY(EditAnywhere)
-	float InfluenceRadius = 3.0f;
-
+	mutable FCriticalSection DataGuard;
 	FDensityField* MyDensityField;
+	FVector MinBounds;
+	FVector MaxBounds;
+	FKdtree MyKdTree;
+
 	UPROPERTY()
 	TArray<FVector> PositionVectors;
+	
 	UPROPERTY()
 	TArray<bool> DefaultFlags;
+	
 	UPROPERTY()
 	TArray<bool> SelectionFlags;
+	
 	UPROPERTY()
 	TArray<FColor> PointColors;
-	mutable FCriticalSection DataGuard;
 
-	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Bounds")
-	FVector MinBounds;
-
-	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Bounds")
-	FVector MaxBounds;
-	
 	UPROPERTY()
 	UGPUPointCloudRendererComponent* PointCloudVisualizer;
-	
+
+	UPROPERTY(EditAnywhere)
+	float InfluenceRadius = 3.0f;
+
 	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Visualization")
 	float SplatSize = 1.0f;
 	
@@ -49,8 +51,7 @@ public:
 	
 	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Materials")
 	UMaterialInterface* UnselectedMaterial;
-
-	// Sets default values for this actor's properties
+	
 	APointCloud();
 	void InitPointCloudVisualizer();
 	void UpdateBounds();