diff --git a/Content/LineMaterialOnTop.uasset b/Content/LineMaterialOnTop.uasset
new file mode 100644
index 0000000000000000000000000000000000000000..dc22cab6810dd4bb4d641ea9a133b9f921fb125f
Binary files /dev/null and b/Content/LineMaterialOnTop.uasset differ
diff --git a/Content/MagicWandMap.umap b/Content/MagicWandMap.umap
index 4e7456218f05c4b5c26de3ca4d0b7adcdecfd53e..ea280d4c79087af91cda2dfbfa349f9795314ad5 100644
Binary files a/Content/MagicWandMap.umap and b/Content/MagicWandMap.umap differ
diff --git a/Content/SelectionEnd.uasset b/Content/SelectionEnd.uasset
new file mode 100644
index 0000000000000000000000000000000000000000..5123c422a95b9f183074275e78f1bd61b41d527e
Binary files /dev/null and b/Content/SelectionEnd.uasset differ
diff --git a/Content/SelectionEndSound.uasset b/Content/SelectionEndSound.uasset
new file mode 100644
index 0000000000000000000000000000000000000000..f1d9214254da15bc2a58ec928f77ddd4b3a28a4c
Binary files /dev/null and b/Content/SelectionEndSound.uasset differ
diff --git a/Content/SelectionStart.uasset b/Content/SelectionStart.uasset
new file mode 100644
index 0000000000000000000000000000000000000000..de70358be6a09c33bec1f285cb456d42024ca72b
Binary files /dev/null and b/Content/SelectionStart.uasset differ
diff --git a/Content/SelectionStartSound.uasset b/Content/SelectionStartSound.uasset
new file mode 100644
index 0000000000000000000000000000000000000000..d75674c56db89afff2b1889918a640201d84c70c
Binary files /dev/null and b/Content/SelectionStartSound.uasset differ
diff --git a/Content/SelectionVolume.uasset b/Content/SelectionVolume.uasset
index f5d2c569e5837f227551627058837d7703770703..ee9355b4be96b567ea71a244e4fd54a1255459b8 100644
Binary files a/Content/SelectionVolume.uasset and b/Content/SelectionVolume.uasset differ
diff --git a/Source/MetaCastBachelor/FMagicWandSelectionTask.h b/Source/MetaCastBachelor/FMagicWandSelectionTask.h
new file mode 100644
index 0000000000000000000000000000000000000000..4fd03de9e4e7ac1c5980b4c19870114ad1c17c8a
--- /dev/null
+++ b/Source/MetaCastBachelor/FMagicWandSelectionTask.h
@@ -0,0 +1,80 @@
+#pragma once
+
+#include "CoreMinimal.h"
+#include "MagicWand.h"
+
+DECLARE_STATS_GROUP(TEXT("MagicWandTasks"), STATGROUP_MagicWandTasks, STATCAT_Advanced);
+
+class FMagicWandSelectionTask : public FRunnable
+{
+	UMagicWand* MagicWand;
+	TQueue<int32>* ProcessQueue;
+	float ProximityThreshold;
+	int ThreadLoad;
+	FRunnableThread* Thread = nullptr;   
+
+public:
+	FMagicWandSelectionTask(UMagicWand* InMagicWand, TQueue<int32>* InProcessQueue, const float InProximityThreshold, const int ThreadLoad)
+		: MagicWand(InMagicWand), ProcessQueue(InProcessQueue), ProximityThreshold(InProximityThreshold), ThreadLoad(ThreadLoad)
+	{
+		
+	}
+
+	virtual bool Init() override
+	{
+		return true;
+	}
+	
+	void Start()
+	{
+		if (!Thread)
+		{
+			Thread = FRunnableThread::Create(this, TEXT("FMagicWandSelectionTask"), 0, TPri_Highest);
+		}
+	}
+
+	virtual uint32 Run() override
+	{
+		MagicWand->ExpandFromAllPointsInQueue(ProcessQueue, ProximityThreshold, ThreadLoad);
+		delete ProcessQueue; // Ensure resources are freed properly
+		ProcessQueue = nullptr;
+		return 0;
+	}
+
+	void DoWork()
+	{
+		MagicWand->ExpandFromAllPointsInQueue(ProcessQueue, ProximityThreshold, ThreadLoad);
+		delete ProcessQueue; // Ensure resources are freed properly
+		ProcessQueue = nullptr;
+	}
+		
+	// Destructor to clean up the queue
+	virtual ~FMagicWandSelectionTask() override
+	{
+		if (ProcessQueue)
+		{
+			delete ProcessQueue;
+			ProcessQueue = nullptr;
+		}
+		if (Thread)
+		{
+			Thread->Kill(true);
+			delete Thread;
+		}
+	}
+
+	void ForceStop()
+	{
+		if (ProcessQueue)
+		{
+			delete ProcessQueue;
+			ProcessQueue = nullptr;
+		}
+		if (Thread)
+		{
+			Thread->Kill(true); // Forcefully terminates the thread
+			delete Thread;
+			Thread = nullptr;
+		}
+	}
+};
\ No newline at end of file
diff --git a/Source/MetaCastBachelor/MagicWand.cpp b/Source/MetaCastBachelor/MagicWand.cpp
index 39877f5160954d8f4647d7eddf17670a1049b871..e5404af1f9dab6e9e20eac7ff95472b847b2b5c2 100644
--- a/Source/MetaCastBachelor/MagicWand.cpp
+++ b/Source/MetaCastBachelor/MagicWand.cpp
@@ -1,14 +1,19 @@
 #include "MagicWand.h"
 #include "Utilities.h"
+#include "FMagicWandSelectionTask.h"
 #include "Components/LineBatchComponent.h"
 #include "Generators/MarchingCubes.h"
+#include "Kismet/GameplayStatics.h"
 
 //	INITIALIZATION
 
+class FMagicWandSelectionTask;
+
 UMagicWand::UMagicWand() : World(nullptr)
 {
 	// Create the procedural mesh component
 	ProceduralMesh = CreateDefaultSubobject<UProceduralMeshComponent>(TEXT("GeneratedMesh"));
+	MarchingCubeMesh = CreateDefaultSubobject<UProceduralMeshComponent>(TEXT("GeneratedMesh2"));
 	MyLineBatchComponent = CreateDefaultSubobject<ULineBatchComponent>(TEXT("LineDrawer"));
 }
 
@@ -32,6 +37,17 @@ void UMagicWand::InitProceduralMesh() const
 	ProceduralMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
 	ProceduralMesh->SetMobility(EComponentMobility::Movable);
 	ProceduralMesh->SetVisibility(true);
+
+	MarchingCubeMesh->SetMaterial(0, SelectionVolumeMat);
+	MarchingCubeMesh->SetMaterial(1, SelectionVolumeMat);
+	MarchingCubeMesh->SetMaterial(2, SelectionVolumeMat);
+	MarchingCubeMesh->bCastDynamicShadow = false;
+	MarchingCubeMesh->bRenderCustomDepth = true;
+	MarchingCubeMesh->SetCastShadow(false);
+	MarchingCubeMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
+	MarchingCubeMesh->SetMobility(EComponentMobility::Movable);
+	MarchingCubeMesh->SetVisibility(true);
+	MarchingCubeMesh->AttachToComponent(MyPointCloud->PointCloudVisualizer, FAttachmentTransformRules::SnapToTargetIncludingScale);
 }
 
 void UMagicWand::InitReferences()
@@ -104,7 +120,7 @@ void UMagicWand::GenerateVoxelMeshWithCubes(const TArray<int32> Voxels) const
 	});
 }
 
-void UMagicWand::GenerateVoxelMeshSmooth(const TArray<int32> Voxels)
+void UMagicWand::GenerateVoxelMeshSmooth(const TSet<int32> Voxels)
 {
 	if(IsMarchingCubesRunning)
 		return;
@@ -134,7 +150,7 @@ void UMagicWand::GenerateVoxelMeshSmooth(const TArray<int32> Voxels)
 		AbortMarchingCubes = false;
 		// Define the implicit function
 		MarchingCubes.Implicit = [this, Voxels](const FVector3d& Pos) {
-			const FVector PosConverted = FVector(Pos.X, Pos.Y, Pos.Z);
+			const FVector PosConverted(Pos.X, Pos.Y, Pos.Z);
 			const int Index = MyDensityField->WorldPositionToIndex(PosConverted);
 			return Voxels.Contains(Index) ? 1 : -1;
 		};
@@ -182,8 +198,8 @@ void UMagicWand::GenerateVoxelMeshSmooth(const TArray<int32> Voxels)
 		AsyncTask(ENamedThreads::Type::GameThread, [this, Vertices, Indices, Normals, VertexColors]()
 		{
 			FScopeLock MeshLock(&ProceduralMeshGuard);
-			ProceduralMesh->CreateMeshSection(0, Vertices, Indices, Normals, TArray<FVector2D>(), VertexColors, TArray<FProcMeshTangent>(), false);
-			ProceduralMesh->SetVisibility(true);
+			MarchingCubeMesh->CreateMeshSection(0, Vertices, Indices, Normals, TArray<FVector2D>(), VertexColors, TArray<FProcMeshTangent>(), false);
+			MarchingCubeMesh->SetVisibility(true);
 			IsMarchingCubesRunning = false;
 		});
 	});
@@ -269,40 +285,61 @@ void UMagicWand::GenerateCylinderBetweenPoints(const FVector& Start, const FVect
 void UMagicWand::HandleMetaSelectPressed(const FInputActionInstance& Instance)
 {
 	Super::HandleMetaSelectPressed(Instance);
+
+	if(NumberThreads.GetValue() > 0) return;
+
+	ProceduralMesh->ClearAllMeshSections();
+	FScopeLock Lock(&SelectionCacheLock);
+	SelectionCache.Empty();
+	SortedProximityRanges.Empty();
+	SeedPointIndex = INDEX_NONE;
 	
 	const FVector SelectionStartPositionWorld = SelectionObject->GetComponentLocation();
 	const FVector SelectionStartPositionLocal = MyPointCloud->PointCloudVisualizer->GetComponentTransform().InverseTransformPosition(SelectionStartPositionWorld);
 	
 	FindSeed(SelectionStartPositionLocal);
+	CountSelectionTime = 1 / MagicWandUpdatesPerSecond;
+	IsMagicWandInitialized = true;
 }
 
 void UMagicWand::HandleMetaSelectReleased(const FInputActionInstance& Instance)
 {
 	Super::HandleMetaSelectReleased(Instance);
 
-	const FVector SelectionWorldPosition = SelectionObject->GetComponentLocation();
-	const FVector SelectionLocalPosition = MyPointCloud->PointCloudVisualizer->GetComponentTransform().InverseTransformPosition(SelectionWorldPosition);
-	
-	InitMagicWandSelection();
+	IsMagicWandInitialized = false;
+	ProceduralMesh->ClearAllMeshSections();
+	MarchingCubeMesh->SetVisibility(false);
+	FScopeLock Lock(&SelectionCacheLock);
+		
+	if(SelectionEndSound)
+	{
+		UGameplayStatics::PlaySound2D(World, SelectionEndSound);
+	}
 
-	AsyncTask(ENamedThreads::Type::AnyBackgroundHiPriTask, [this, &SelectionLocalPosition]()
+	TArray<int32> SelectionArray = CurrentSelection.GetPointIndexList();
+	for(const int Index : SelectionArray)
 	{
-		PerformMagicWandSelection();
-	});
+		if(MyPointCloud && MyPointCloud->SelectionFlags.IsValidIndex(Index))
+		{
+			MyPointCloud->SelectionFlags[Index] = true;
+		}
+	}
+
+	CurrentSelection = FSelectionManager(CurrentSelection.GetSelectionFlags().Num());
 }
 
 void UMagicWand::HandleMetaEraseReleased(const FInputActionInstance& Instance)
 {
 	Super::HandleMetaEraseReleased(Instance);
-	
-	FScopeLock Lock(&ThreadNumberLock);
-	AbortMagicWand.Store(true);
 
-	//deselect all particles
-	for (int32 i = 0; i < MyPointCloud->SelectionFlags.Num(); ++i)
+	if(NumberThreads.GetValue() > 0 || CurrentSelection.SelectedCount() == 0)
 	{
-		MyPointCloud->SelectionFlags[i] = false;
+		return;
 	}
+	
+	//AbortMagicWand.Store(true);
+	CurrentSelection = FSelectionManager(CurrentSelection.GetSelectionFlags().Num());
+	MyPointCloud->SelectionFlags = CurrentSelection.GetSelectionFlags();
 }
 
 //	MAGIC WAND SELECTION
@@ -311,10 +348,10 @@ void UMagicWand::InitMagicWandSelection()
 {	
 	ProceduralMesh->ClearAllMeshSections();
 	AbortMarchingCubes = true;
-	AbortMagicWand.Store(false);
+	//AbortMagicWand.Store(false);
 }
 
-void UMagicWand::PerformMagicWandSelection()
+void UMagicWand::PerformMagicWandSelection(const float ProximityThreshold)
 {
 	if (MyPointCloud->SelectionFlags.Num() != MyPointCloud->PositionVectors.Num())
 	{
@@ -322,13 +359,26 @@ void UMagicWand::PerformMagicWandSelection()
 		return;
 	}
 
-	//UE_LOG(LogTemp, Warning, TEXT("Starting MagicWand Selection!"));
-
-	// Find the closest point to the input position as the seed
-
 	if (SeedPointIndex != INDEX_NONE)
 	{
-		ExpandSelectionFromPointIndex(SeedPointIndex);
+		if(SelectionStartSound)
+		{
+			UGameplayStatics::PlaySound2D(World, SelectionStartSound);
+		}
+		
+		CurrentSelection = GetSelectionResultsFromProximity(ProximityThreshold);
+		CurrentSelection.SelectIndex(SeedPointIndex);
+		
+		TQueue<int32>* ProcessQueue = new TQueue<int32>{};
+		
+		for (int32 Index : CurrentSelection.GetPointIndexList())
+		{
+			ProcessQueue->Enqueue(Index);
+		}
+		
+		FMagicWandSelectionTask* Task = new FMagicWandSelectionTask(this, ProcessQueue, ProximityThreshold, CurrentSelection.SelectedCount());
+		NumberThreads.Increment();
+		Task->Start();
 	}
 }
 
@@ -381,127 +431,111 @@ void UMagicWand::FindSeed(const FVector& InputPosition)
 	}
 }
 
-void UMagicWand::ExpandSelectionFromPointIndex(const int32 PointIndex)
+void UMagicWand::ExpandFromAllPointsInQueue(TQueue<int32>* ProcessQueue, const float ProximityThreshold, int ThreadLoad)
 {
-	{
-		FScopeLock Lock(&ThreadNumberLock);
-		NumberThreads.Increment();
-	}
-	
-	TQueue<int32>* ProcessQueue = new TQueue<int32>{};
-	ProcessQueue->Enqueue(PointIndex);
-	MyPointCloud->SelectionFlags[PointIndex] = true;
-
-	const float SquaredProximityThreshold = ProximityThreshold * ProximityThreshold;
-	int NumberToProcess = 0;
-	
-	while (!ProcessQueue->IsEmpty() && !AbortMagicWand.Load())
-	{
-		if(NumberToProcess > 1000 && NumberThreads.GetValue() < MaxThreadCount) CreateNewExpansionThread(ProcessQueue, NumberToProcess);
-
-		int32 CurrentQueuePointIndex;
-		ProcessQueue->Dequeue(CurrentQueuePointIndex);
-		const FVector CurrentQueuePointPosition = MyPointCloud->PositionVectors[CurrentQueuePointIndex];
-    	
-		ExpandThroughNeighborsInRange(ProcessQueue, SquaredProximityThreshold, NumberToProcess, CurrentQueuePointPosition);
-		NumberToProcess--;
-	}
-	
-	AbortSelection();
-}
-
-void UMagicWand::ExpandSelectionFromPointIndexQueue(TQueue<int32>* ProcessQueue)
-{
-	{
-		FScopeLock Lock(&ThreadNumberLock);
-		NumberThreads.Increment();
-	}
 	//UE_LOG(LogTemp, Warning, TEXT("Opened New Thread! Number of Threads now: %d"), NumberThreads.GetValue());
-	const float SquaredProximityThreshold = ProximityThreshold * ProximityThreshold;
-	int NumberToProcess = 0;
-	
-	while (!ProcessQueue->IsEmpty() && !AbortMagicWand.Load())
+
+	TSet<int32> MyFullVoxelList;
+	MyFullVoxelList.Reserve(1000000);
+	FVoxelPointLookupTable MyVoxelPointLookupTable = *MyDensityField->VoxelPointLookupTable;
+			
+	while (!ProcessQueue->IsEmpty())
 	{    	
-		if(NumberToProcess > 1000  && NumberThreads.GetValue() < MaxThreadCount) CreateNewExpansionThread(ProcessQueue, NumberToProcess);
+		if(ThreadLoad > 1000  && NumberThreads.GetValue() < MaxThreadCount) CreateNewExpansionThread(ProcessQueue, ThreadLoad, ProximityThreshold);
 
 		int32 CurrentQueuePointIndex;
 		ProcessQueue->Dequeue(CurrentQueuePointIndex);
-		const FVector CurrentQueuePointPosition = MyPointCloud->PositionVectors[CurrentQueuePointIndex];
+		
+		if(MyPointCloud && MyPointCloud->PositionVectors.IsValidIndex(CurrentQueuePointIndex))
+		{
+			const FVector CurrentQueuePointPosition = MyPointCloud->PositionVectors[CurrentQueuePointIndex];
 
-		ExpandThroughNeighborsInRange(ProcessQueue, SquaredProximityThreshold, NumberToProcess, CurrentQueuePointPosition);
-		NumberToProcess--;
+			ExpandFromPoint(ProcessQueue, ProximityThreshold, ThreadLoad, CurrentQueuePointPosition, &MyFullVoxelList, &MyVoxelPointLookupTable);
+		}
+		
+		ThreadLoad--;
 	}
 	
-	AbortSelection();
+	FinishSelectionThread(ProximityThreshold);
 }
 
-void UMagicWand::ExpandThroughNeighborsInRange(TQueue<int32>* ProcessQueue, const float SquaredProximityThreshold, int& NumberToProcess, const FVector& CurrentQueuePointPosition) const
+void UMagicWand::ExpandFromPoint(TQueue<int32>* ProcessQueue, const float ProximityThreshold, int& ThreadLoad, const FVector& ExpansionPoint, TSet<int32>* MyFullVoxelList, FVoxelPointLookupTable* MyVoxelPointLookupTable)
 {
-	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));
-    	
+	const FVector Step = MyDensityField->GetStep();
+	const int32 StartX = FMath::Max(0, FMath::FloorToInt((ExpansionPoint.X - ProximityThreshold - MyPointCloud->MinBounds.X) / Step.X));
+	const int32 EndX = FMath::Min(MyDensityField->GetXNum() - 1, FMath::FloorToInt((ExpansionPoint.X + ProximityThreshold - MyPointCloud->MinBounds.X) / Step.X));
+	const int32 StartY = FMath::Max(0, FMath::FloorToInt((ExpansionPoint.Y - ProximityThreshold - MyPointCloud->MinBounds.Y) / Step.Y));
+	const int32 EndY = FMath::Min(MyDensityField->GetYNum() - 1, FMath::FloorToInt((ExpansionPoint.Y + ProximityThreshold - MyPointCloud->MinBounds.Y) / Step.Y));
+	const int32 StartZ = FMath::Max(0, FMath::FloorToInt((ExpansionPoint.Z - ProximityThreshold - MyPointCloud->MinBounds.Z) / Step.Z));
+	const int32 EndZ = FMath::Min(MyDensityField->GetZNum() - 1, FMath::FloorToInt((ExpansionPoint.Z + ProximityThreshold - MyPointCloud->MinBounds.Z) / Step.Z));
+
+	const float SquaredProximityThreshold = ProximityThreshold * ProximityThreshold;
+		
 	for (int32 Z = StartZ; Z <= EndZ; ++Z)
 	{			
 		for (int32 Y = StartY; Y <= EndY; ++Y)
 		{
 			for (int32 X = StartX; X <= EndX; ++X)
 			{
-				if(AbortMagicWand.Load()) return;
 				const int32 CurrentVoxelComparisonIndex = MyDensityField->GridPositionToIndex(X, Y, Z);
-					
-				if(!MyDensityField->IsValidIndex(CurrentVoxelComparisonIndex))
+				
+				if(MyFullVoxelList->Contains(CurrentVoxelComparisonIndex))
 				{
 					continue;
 				}
+				
+				TArray<int32> PointIndices = MyVoxelPointLookupTable->GetPointsInVoxel(CurrentVoxelComparisonIndex);
 
-				TArray<int32> PointIndices = MyDensityField->VoxelPointLookupTable->GetPointsInVoxel(CurrentVoxelComparisonIndex);
-
+				int Selected = 0;
 				for(const int32 CurrentPointComparisonIndex : PointIndices)
 				{
-					if(MyPointCloud->SelectionFlags[CurrentPointComparisonIndex])
+					if(CurrentSelection.IsSelected(CurrentPointComparisonIndex))
 					{
+						Selected++;
 						continue;
 					}
     					
 					FVector CurrentComparisonPosition = MyPointCloud->PositionVectors[CurrentPointComparisonIndex];
-					const double SquaredDistance = FVector::DistSquared(CurrentQueuePointPosition, CurrentComparisonPosition);
+					const double SquaredDistance = FVector::DistSquared(ExpansionPoint, CurrentComparisonPosition);
 
 					if (SquaredDistance <= SquaredProximityThreshold)
 					{
 						ProcessQueue->Enqueue(CurrentPointComparisonIndex);
-						NumberToProcess++;
+						ThreadLoad++;
+						Selected++;
 							
-						if(AbortMagicWand.Load()) return;
-							
-						MyPointCloud->SelectionFlags[CurrentPointComparisonIndex] = true;
+						CurrentSelection.SelectIndex(CurrentPointComparisonIndex);
 					}
 				}
+				
+				if(Selected == PointIndices.Num())
+				{
+					MyFullVoxelList->Add(CurrentVoxelComparisonIndex);
+				}
 			}
 		}
 	}
 }
 
-void UMagicWand::AbortSelection()
+void UMagicWand::FinishSelectionThread(const float ProximityThreshold)
 {
 	NumberThreads.Decrement();
 		
 	//UE_LOG(LogTemp, Warning, TEXT("Thread Closed! Number of Threads now: %d"), NumberThreads.GetValue());
 	if(NumberThreads.GetValue() == 0)
 	{
-		//AbortMagicWand.Store(false);
-		//UE_LOG(LogTemp, Warning, TEXT("Aborted!"));
+		CacheSelectionResults(ProximityThreshold, CurrentSelection);
+		
+		//UE_LOG(LogTemp, Error, TEXT("Finished!"));
 	}else if(NumberThreads.GetValue() < 0)
 	{
 		UE_LOG(LogTemp, Error, TEXT("More Threads closed than opened!"));
 	}
 }
 
-void UMagicWand::CreateNewExpansionThread(TQueue<int32>* ProcessQueue, int& NumberToProcess)
+void UMagicWand::CreateNewExpansionThread(TQueue<int32>* ProcessQueue, int& NumberToProcess, const float ProximityThreshold)
 {
+	NumberThreads.Increment();
 	TQueue<int32>* TempQueue = new TQueue<int32>{};
 	const int NumberRemove = NumberToProcess / 2;
 			
@@ -513,10 +547,42 @@ void UMagicWand::CreateNewExpansionThread(TQueue<int32>* ProcessQueue, int& Numb
 		TempQueue->Enqueue(CurrentQueuePointIndex);
 	}
 
-	AsyncTask(ENamedThreads::Type::AnyBackgroundHiPriTask, [this, TempQueue]()
+	FMagicWandSelectionTask* Task = new FMagicWandSelectionTask(this, TempQueue, ProximityThreshold, NumberRemove);
+	Task->Start();
+}
+
+void UMagicWand::CacheSelectionResults(const float ProximityThreshold, const FSelectionManager& SelectionResults)
+{
+	FScopeLock Lock(&SelectionCacheLock);
+	// Check if the proximity range is already present
+	if (!SortedProximityRanges.Contains(ProximityThreshold))
 	{
-		ExpandSelectionFromPointIndexQueue(TempQueue);
-	});
+		// Add new range to the array and sort it
+		SortedProximityRanges.Add(ProximityThreshold);
+		SortedProximityRanges.Sort();
+
+		// Update the cache with new indices for a given proximity range
+		SelectionCache.Add(ProximityThreshold, SelectionResults);
+	}
+}
+
+FSelectionManager UMagicWand::GetSelectionResultsFromProximity(const float ProximityThreshold)
+{
+	FScopeLock Lock(&SelectionCacheLock);
+
+	for(int i = SortedProximityRanges.Num() - 1; i >= 0; --i)
+	{
+		const float CurrentRange = SortedProximityRanges[i];
+
+		if(CurrentRange <= ProximityThreshold)
+		{
+			//UE_LOG(LogTemp, Error, TEXT("Cached selection found for proximity range %f, closest smaller proximity was %f"), ProximityThreshold, CurrentRange);
+			return SelectionCache[CurrentRange];
+		}
+	}
+
+	//UE_LOG(LogTemp, Error, TEXT("No cached selection found for proximity range %f"), ProximityThreshold);
+	return FSelectionManager(MyPointCloud->SelectionFlags.Num());
 }
 
 //	TICK
@@ -525,16 +591,21 @@ void UMagicWand::TickComponent(const float DeltaTime, const ELevelTick TickType,
 {
 	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
 
-	/*
-	AccumulatedTime.Store(AccumulatedTime.Load() + DeltaTime);
-	ProceduralMesh->SetVisibility(Select);*/
+	CountSelectionTime += DeltaTime;
+
+	if(!Select)
+	{
+		MarchingCubeMesh->SetVisibility(false);
+	}
 }
 
 void UMagicWand::SelectParticles(const FVector& InputPosition)
 {
+	if(!IsMagicWandInitialized) return;
+	
 	const FVector CurrentSelectionPositionWorld = SelectionObject->GetComponentLocation();
 	const FVector CurrentSelectionPositionLocal = MyPointCloud->PointCloudVisualizer->GetComponentTransform().InverseTransformPosition(CurrentSelectionPositionWorld);
-	ProximityThreshold =  FMath::Clamp(FVector::Dist(SeedPointPositionLocal, CurrentSelectionPositionLocal) / ThresholdDistanceScaling, MinThreshold, MaxThreshold);
+	const float ProximityThreshold =  FMath::Clamp(FVector::Dist(SeedPointPositionLocal, CurrentSelectionPositionLocal) / ThresholdDistanceScaling, MinThreshold, MaxThreshold);
 
 	const FVector SelectionDirectionLocal = CurrentSelectionPositionLocal - SeedPointPositionLocal;
 	const FVector ProximityEndPointLocal = SeedPointPositionLocal + (SelectionDirectionLocal.GetSafeNormal() * ProximityThreshold);
@@ -544,4 +615,28 @@ void UMagicWand::SelectParticles(const FVector& InputPosition)
 	
 	GenerateCylinderBetweenPoints(SelectionStartPositionWorld, ProximityEndPointWorld, 0.05, 8, FColor::Red, 1);
 	GenerateCylinderBetweenPoints((CurrentSelectionPositionWorld - ProximityEndPointWorld).GetSafeNormal() * 0.05 + ProximityEndPointWorld, CurrentSelectionPositionWorld, 0.05, 8, FColor::Green, 0);
+
+	if(CountSelectionTime >= 1.0f / MagicWandUpdatesPerSecond && NumberThreads.GetValue() == 0)
+	{
+		CountSelectionTime = 0;
+		//AbortMagicWand.Store(false);
+		PerformMagicWandSelection(ProximityThreshold);
+
+		FScopeLock Lock(&SelectionCacheLock);
+
+		TSet<int32> Voxels;
+		TArray<int32> PointIndices = CurrentSelection.GetPointIndexList();
+		for (int32 i = 0; i < PointIndices.Num(); i++)
+		{
+			const int Index = PointIndices[i];
+			if(MyPointCloud->PositionVectors.IsValidIndex(Index))
+			{
+				FVector Point = MyPointCloud->PositionVectors[Index];
+				int32 VoxelFromIndex = MyDensityField->WorldPositionToIndex(Point);
+				Voxels.Add(VoxelFromIndex);
+			}
+		}
+		
+		GenerateVoxelMeshSmooth(Voxels);
+	}
 }
\ No newline at end of file
diff --git a/Source/MetaCastBachelor/MagicWand.h b/Source/MetaCastBachelor/MagicWand.h
index 683796acda160ae94acbef6a60ae2811326ea7ba..5137d0fc493030e5985dc89b12e7462112ff733b 100644
--- a/Source/MetaCastBachelor/MagicWand.h
+++ b/Source/MetaCastBachelor/MagicWand.h
@@ -1,6 +1,7 @@
 #pragma once
 
 #include "CoreMinimal.h"
+#include "MagicWandSelectionManager.h"
 #include "ProceduralMeshComponent.h"
 #include "MetaCastBaseline.h"
 #include "Generators/MarchingCubes.h"
@@ -12,28 +13,49 @@ class UMagicWand : public UMetaCastBaseline
 {
 	GENERATED_BODY()
 
-	//	INTERNAL
+	//	MAGIC WAND
 
 	TAtomic<bool> AbortMagicWand = false;
+	FSelectionManager CurrentSelection;
+	TMap<float, FSelectionManager> SelectionCache;
+	TArray<float> SortedProximityRanges;
+	FVector SeedPointPositionLocal;
 	FDensityField* MyDensityField;
-	bool IsMarchingCubesRunning = false;
-	bool AbortMarchingCubes = false;
-	FThreadSafeCounter NumberThreads = 0;
+	float CountSelectionTime = 0;
+	bool IsMagicWandInitialized = false;
+
+	//	THREADING
+	
 	mutable FCriticalSection ProceduralMeshGuard;
+	mutable FCriticalSection SelectionCacheLock;
 	mutable FCriticalSection ThreadNumberLock;
-	UPROPERTY()
-	UProceduralMeshComponent* ProceduralMesh;
+	mutable FThreadSafeCounter NumberThreads = 0;
+
+	//	VISUALIZATION
+	
+	bool IsMarchingCubesRunning = false;
+	bool AbortMarchingCubes = false;
+	float MarchingCubeSize = 0;
+		
+	//	REFERENCES
+	
 	UPROPERTY()
 	UWorld* World;
-	FVector SeedPointPositionLocal;
+	
 	UPROPERTY()
 	ULineBatchComponent* MyLineBatchComponent;
-	float ProximityThreshold = 0.1f;
-	float MarchingCubeSize = 0;
-	int32 SeedPointIndex;
+
+	UPROPERTY()
+	UProceduralMeshComponent* ProceduralMesh;
 	
-	//	USER EXPORTED
+	UPROPERTY()
+	UProceduralMeshComponent* MarchingCubeMesh;
+	
+	//	USER EDITABLE PROPERTIES
 
+	UPROPERTY(EditAnywhere)
+	float MagicWandUpdatesPerSecond = 3;
+	
 	UPROPERTY(EditAnywhere)
 	float ThresholdDistanceScaling = 20;
 
@@ -48,8 +70,19 @@ class UMagicWand : public UMetaCastBaseline
 	
 	UPROPERTY(EditAnywhere)
 	int MaxThreadCount = 100;
-	
+
+	UPROPERTY(EditAnywhere)
+	bool UpdateMagicWandDuringDrag = false;
+
+	UPROPERTY(EditAnywhere)
+	USoundWave* SelectionEndSound;
+
+	UPROPERTY(EditAnywhere)
+	USoundWave* SelectionStartSound;
+
 public:
+	int32 SeedPointIndex;
+	
 	//	INITIALIZATION
 	
 	UMagicWand();
@@ -67,19 +100,19 @@ public:
 	//	VISUALIZATION
 	
 	void GenerateVoxelMeshWithCubes(const TArray<int32> Voxels) const;
-	void GenerateVoxelMeshSmooth(const TArray<int32> Voxels);
+	void GenerateVoxelMeshSmooth(const TSet<int32> Voxels);
 
 	//	MAGIC WAND SELECTION
 
 	void InitMagicWandSelection();
-	void FindSeedIndex(const FVector& InputPosition, int32& SeedIndex) const;
-	void PerformMagicWandSelection();
+	void PerformMagicWandSelection(const float ProximityThreshold);
 	void FindSeed(const FVector& InputPosition);
-	void ExpandSelectionFromPointIndex(int32 PointIndex);
-	void ExpandSelectionFromPointIndexQueue(TQueue<int32>* ProcessQueue);
-	void ExpandThroughNeighborsInRange(TQueue<int32>* ProcessQueue, const float SquaredProximityThreshold, int& NumberToProcess, const FVector& CurrentQueuePointPosition) const;
-	void AbortSelection();
-	void CreateNewExpansionThread(TQueue<int32>* ProcessQueue, int& NumberToProcess);
+	void ExpandFromAllPointsInQueue(TQueue<int32>* ProcessQueue, const float ProximityThreshold, int ThreadLoad);
+	void ExpandFromPoint(TQueue<int32>* ProcessQueue, const float ProximityThreshold, int& ThreadLoad, const FVector& ExpansionPoint, TSet<int32>* MyFullVoxelList, FVoxelPointLookupTable* MyVoxelPointLookupTable);
+	void FinishSelectionThread(const float ProximityThreshold);
+	void CreateNewExpansionThread(TQueue<int32>* ProcessQueue, int& NumberToProcess, const float ProximityThreshold);
+	void CacheSelectionResults(const float ProximityThreshold, const FSelectionManager& SelectionResults);
+	FSelectionManager GetSelectionResultsFromProximity(float ProximityThreshold);
 
 	//	TICK
 	
diff --git a/Source/MetaCastBachelor/MagicWandSelectionManager.h b/Source/MetaCastBachelor/MagicWandSelectionManager.h
new file mode 100644
index 0000000000000000000000000000000000000000..2c88a4234b84f48eb83bdcc9e0e1e8dbbd7db286
--- /dev/null
+++ b/Source/MetaCastBachelor/MagicWandSelectionManager.h
@@ -0,0 +1,109 @@
+#pragma once
+#include "CoreMinimal.h"
+
+class FSelectionManager
+{
+    TArray<int32> PointIndexList;  // List of selected indices
+    TArray<bool> SelectionFlags;   // Flags to indicate if an index is selected
+    int SelectionCount;            // Counter for selected indices
+	TSet<int32> FullVoxelList;
+
+public:
+    explicit FSelectionManager(const int32 NumElements) : SelectionCount(0)
+    {
+        SelectionFlags.Init(false, NumElements);
+        PointIndexList.Reserve(NumElements); // Preallocate space to optimize appending
+    }
+
+    explicit FSelectionManager(const TArray<bool>& InSelectionFlags) : SelectionFlags(InSelectionFlags)
+    {
+    	SelectionCount = 0;
+    	for (int i = 0; i < InSelectionFlags.Num(); i++)
+    	{
+    		if (InSelectionFlags[i])
+    		{
+    			PointIndexList.Add(i);
+    			SelectionCount++;
+    		}
+    	}
+    }
+
+    FSelectionManager(): SelectionCount(0) {}
+
+
+    /** Adds an index to the selection if it isn't already selected */
+    void SelectIndex(const int32 Index)
+    {
+        if (!SelectionFlags[Index])
+        {
+            PointIndexList.Add(Index);
+            SelectionFlags[Index] = true;
+            SelectionCount++;
+        }
+    }
+
+    /** Removes a specific index from the selection */
+    bool UnselectIndex(const int32 IndexToRemove)
+    {
+        if (IsValidIndex(IndexToRemove) && SelectionFlags[IndexToRemove])
+        {
+	        const int32 RemoveAt = PointIndexList.IndexOfByKey(IndexToRemove);
+            if (RemoveAt != INDEX_NONE)
+            {
+                PointIndexList.RemoveAt(RemoveAt);
+                SelectionFlags[IndexToRemove] = false;
+                SelectionCount--;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /** Returns true if any indices are selected */
+    bool IsAnythingSelected() const
+    {
+        return SelectionCount > 0;
+    }
+
+    /** Checks if a specific index is selected */
+    bool IsSelected(const int32 Index) const
+    {
+        return IsValidIndex(Index) && SelectionFlags[Index];
+    }
+
+    /** Resets the selection status of all indices */
+    void Reset()
+    {
+        SelectionFlags.Init(false, SelectionFlags.Num());
+        PointIndexList.Empty();
+        SelectionCount = 0;
+    }
+
+    /** Returns the number of selected indices */
+    int32 SelectedCount() const
+    {
+        return SelectionCount;
+    }
+
+    /** Checks if the given index is within the valid range */
+    bool IsValidIndex(const int32 Index) const
+    {
+        return Index >= 0 && Index < SelectionFlags.Num();
+    }
+
+    /** Returns the number of indices in the selection list (for debugging) */
+    int32 QueueSize() const
+    {
+        return PointIndexList.Num();
+    }
+
+	const TArray<int32>& GetPointIndexList() const
+	{
+		return PointIndexList;
+	}
+
+	const TArray<bool>& GetSelectionFlags() const
+	{
+		return SelectionFlags;
+	}
+};
\ No newline at end of file
diff --git a/Source/MetaCastBachelor/PointCloud.cpp b/Source/MetaCastBachelor/PointCloud.cpp
index a5f6813ffe3a9127732fc9946fb34915cc576035..0eb4c858e7b6153576a83ac6fc77c9203387fbae 100644
--- a/Source/MetaCastBachelor/PointCloud.cpp
+++ b/Source/MetaCastBachelor/PointCloud.cpp
@@ -20,9 +20,9 @@ void APointCloud::BeginPlay()
 	InitPointCloudVisualizer();
 	SetupDensityFieldFromPointCloud();
 	
-	UKdtreeBPLibrary::BuildKdtree(MyKdTree, PositionVectors);
+	//UKdtreeBPLibrary::BuildKdtree(MyKdTree, PositionVectors);
 	//UKdtreeBPLibrary::DumpKdtreeToConsole(MyKdTree);
-	UKdtreeBPLibrary::ValidateKdtree(MyKdTree);
+	//UKdtreeBPLibrary::ValidateKdtree(MyKdTree);
 }
 
 void APointCloud::ReadPointCloudFromFile(const FFilePath FileNamePoints, const FFilePath FileNameFlags)
diff --git a/Source/MetaCastBachelor/VoxelPointLookupTable.h b/Source/MetaCastBachelor/VoxelPointLookupTable.h
index 52076a383f10db918ba8b2d2209b593999648435..43553c3fbae6f1c5893d918ae51f3e84c045ea3b 100644
--- a/Source/MetaCastBachelor/VoxelPointLookupTable.h
+++ b/Source/MetaCastBachelor/VoxelPointLookupTable.h
@@ -8,6 +8,19 @@ class FVoxelPointLookupTable
 
 public:
 	FVoxelPointLookupTable();
+	
+	FVoxelPointLookupTable(const FVoxelPointLookupTable& Other)
+	: VoxelToPointIndicesMap(Other.VoxelToPointIndicesMap), LinkedDensityField(Other.LinkedDensityField)
+	{}
+
+	FVoxelPointLookupTable& operator=(const FVoxelPointLookupTable& Other)
+	{
+		if (this != &Other) {
+			VoxelToPointIndicesMap = Other.VoxelToPointIndicesMap;
+			LinkedDensityField = Other.LinkedDensityField;
+		}
+		return *this;
+	}
 
 	virtual ~FVoxelPointLookupTable();