<commit_before>// Copyright 2017 Phyronnaz

#include "VoxelPrivatePCH.h"
#include "VoxelTools.h"
#include "Engine/World.h"
#include "DrawDebugHelpers.h"
#include "ValueOctree.h"
#include "ChunkOctree.h"
#include "MeshImporter.h"

void UVoxelTools::SetValueSphere(AVoxelWorld* World, FVector Position, float Radius, bool bAdd, bool bQueueUpdate, bool bApplyUpdates, bool bAsync)
{
	if (World == nullptr)
	{
		UE_LOG(VoxelLog, Error, TEXT("World is NULL"));
		return;
	}
	check(World);
	FIntVector LocalPosition = World->GlobalToLocal(Position);
	int IntRadius = FMath::CeilToInt(Radius);

	TArray<FIntVector> Corners = {
		LocalPosition + FIntVector(-IntRadius, -IntRadius, -IntRadius),
		LocalPosition + FIntVector(+IntRadius, -IntRadius, -IntRadius),
		LocalPosition + FIntVector(-IntRadius, +IntRadius, -IntRadius),
		LocalPosition + FIntVector(+IntRadius, +IntRadius, -IntRadius),
		LocalPosition + FIntVector(-IntRadius, -IntRadius, +IntRadius),
		LocalPosition + FIntVector(+IntRadius, -IntRadius, +IntRadius),
		LocalPosition + FIntVector(-IntRadius, +IntRadius, +IntRadius),
		LocalPosition + FIntVector(+IntRadius, +IntRadius, +IntRadius)
	};

	// Get smallest octrees
	ValueOctree* SmallValueOctree = World->GetValueOctree().Get();
	ValueOctree* OldSmallValueOctree = SmallValueOctree;
	check(SmallValueOctree);

	bool ContinueShrinking = true;
	while (ContinueShrinking)
	{
		ContinueShrinking = !SmallValueOctree->IsLeaf();
		for (auto Corner : Corners)
		{
			ContinueShrinking = ContinueShrinking && SmallValueOctree->IsInOctree(Corner);
		}

		if (ContinueShrinking)
		{
			OldSmallValueOctree = SmallValueOctree;
			SmallValueOctree = SmallValueOctree->GetChild(Corners[0]);
		}
	}
	SmallValueOctree = OldSmallValueOctree;

	for (int x = -IntRadius; x <= IntRadius; x++)
	{
		for (int y = -IntRadius; y <= IntRadius; y++)
		{
			for (int z = -IntRadius; z <= IntRadius; z++)
			{
				FIntVector CurrentPosition = LocalPosition + FIntVector(x, y, z);
				float Distance = FVector(x, y, z).Size();

				if (Distance <= Radius + 1)
				{
					float Value = (bAdd ? -1 : 1) * (Radius - Distance);

					if ((Value < 0 && bAdd) || (Value >= 0 && !bAdd) || (SmallValueOctree->GetValue(CurrentPosition) * Value > 0))
					{
						SmallValueOctree->SetValue(CurrentPosition, Value);
						if (bQueueUpdate)
						{
							World->QueueUpdate(CurrentPosition);
						}
					}
				}
			}
		}
	}
	if (bApplyUpdates)
	{
		World->ApplyQueuedUpdates(bAsync);
	}
}

void UVoxelTools::SetColorSphere(AVoxelWorld* World, FVector Position, float Radius, FLinearColor Color, float FadeDistance, bool bQueueUpdate, bool bApplyUpdates, bool bAsync)
{
	if (World == nullptr)
	{
		UE_LOG(VoxelLog, Error, TEXT("World is NULL"));
		return;
	}
	check(World);
	FIntVector LocalPosition = World->GlobalToLocal(Position);
	int IntRadius = FMath::CeilToInt(Radius);

	for (int x = -IntRadius; x <= IntRadius; x++)
	{
		for (int y = -IntRadius; y <= IntRadius; y++)
		{
			for (int z = -IntRadius; z <= IntRadius; z++)
			{
				FIntVector CurrentPosition = LocalPosition + FIntVector(x, y, z);
				float Distance = FVector(x, y, z).Size();
				float Alpha = (FMath::Clamp(Radius - Distance, -1.f, FadeDistance) + 1) / (1 + FadeDistance);
				FColor CurrentColor = FLinearColor::LerpUsingHSV(World->GetColor(CurrentPosition), Color, Alpha).ToFColor(true);

				World->SetColor(CurrentPosition, CurrentColor);
				if (bQueueUpdate)
				{
					World->QueueUpdate(CurrentPosition);
				}
			}
		}
	}
	if (bApplyUpdates)
	{
		World->ApplyQueuedUpdates(bAsync);
	}
}

void UVoxelTools::SetValueCone(AVoxelWorld * World, FVector Position, float Radius, float Height, bool bAdd, bool bQueueUpdate, bool bApplyUpdates, bool bAsync)
{
	if (World == nullptr)
	{
		UE_LOG(VoxelLog, Error, TEXT("World is NULL"));
		return;
	}
	check(World);
	FIntVector LocalPosition = World->GlobalToLocal(Position);
	int IntRadius = FMath::CeilToInt(Radius);
	int IntHeight = FMath::CeilToInt(Height);

	for (int x = -IntRadius; x <= IntRadius; x++)
	{
		for (int y = -IntRadius; y <= IntRadius; y++)
		{
			for (int z = 0; z <= IntHeight; z++)
			{
				FIntVector CurrentPosition = LocalPosition + FIntVector(x, y, z);
				float CurrentRadius = z * (Radius / Height);
				float Distance = FVector2D(x, y).Size();

				if (Distance <= CurrentRadius + 1)
				{
					float Alpha = FMath::Clamp(CurrentRadius - Distance, -1.f, 1.f);

					int Value = (bAdd ? -1 : 1) * (int)(127 * Alpha);

					if ((Value < 0 && bAdd) || (Value >= 0 && !bAdd) || (World->GetValue(CurrentPosition) * Value > 0))
					{
						World->SetValue(CurrentPosition, Value);
						if (bQueueUpdate)
						{
							World->QueueUpdate(CurrentPosition);
						}
					}
				}
			}
		}
	}
	if (bApplyUpdates)
	{
		World->ApplyQueuedUpdates(bAsync);
	}
}

void UVoxelTools::SetValueProjection(AVoxelWorld* World, FVector Position, FVector Normal, float Radius, int Stength, bool bAdd, float MaxDistance, bool bQueueUpdate, bool bApplyUpdates, bool bAsync, bool bDebugLines, bool bDebugPoints)
{
	if (World == nullptr)
	{
		UE_LOG(VoxelLog, Error, TEXT("World is NULL"));
		return;
	}
	check(World);
	FVector ToolPosition = Position + Normal * MaxDistance / 2;

	// Compute tangent
	FVector Tangent;
	// N dot T = 0
	// <=> N.X * T.X + N.Y * T.Y + N.Z * T.Z = 0
	// <=> T.Z = -1 / N.Z * (N.X * T.X + N.Y * T.Y)
	Tangent.X = 1;
	Tangent.Y = 1;
	Tangent.Z = -1 / Normal.Z * (Normal.X * Tangent.X + Normal.Y * Tangent.Y);
	Tangent.Normalize();

	// Compute bitangent
	FVector Bitangent = FVector::CrossProduct(Tangent, Normal).GetSafeNormal();

	TArray<FIntVector> Points;
	float Scale = World->GetTransform().GetScale3D().Size() / 4;

	int IntRadius = FMath::CeilToInt(Radius);
	for (int x = -IntRadius; x <= IntRadius; x++)
	{
		for (int y = -IntRadius; y <= IntRadius; y++)
		{
			if (x*x + y*y < Radius*Radius)
			{
				FHitResult Hit;
				FVector Start = ToolPosition + Tangent * x * Scale + Bitangent * y * Scale;
				FVector End = Start - Normal * MaxDistance;
				if (bDebugLines)
				{
					DrawDebugLine(World->GetWorld(), Start, End, FColor::Magenta, false, 1);
				}
				if (World->GetWorld()->LineTraceSingleByChannel(Hit, Start, End, ECollisionChannel::ECC_WorldDynamic))
				{
					if (bDebugPoints)
					{
						DrawDebugPoint(World->GetWorld(), Hit.ImpactPoint, 2, FColor::Red, false, 1);
					}
					Points.AddUnique(World->GlobalToLocal(Hit.ImpactPoint));
				}
			}
		}
	}
	for (FIntVector Point : Points)
	{
		if (bAdd)
		{
			World->Add(Point, Stength);
		}
		else
		{
			World->Remove(Point, Stength);
		}
		if (bQueueUpdate)
		{
			World->QueueUpdate(Point);
		}
	}
	if (bApplyUpdates)
	{
		World->ApplyQueuedUpdates(bAsync);
	}
}

void UVoxelTools::SetColorProjection(AVoxelWorld * World, FVector Position, FVector Normal, float Radius, FLinearColor Color, float FadeDistance, float MaxDistance, bool bQueueUpdate, bool bApplyUpdates, bool bAsync, bool bDebugLines, bool bDebugPoints)
{
	if (World == NULL)
	{
		UE_LOG(VoxelLog, Error, TEXT("World is NULL"));
		return;
	}
	check(World);
	FVector ToolPosition = Position + Normal * MaxDistance / 2;

	// Compute tangent
	FVector Tangent;
	// N dot T = 0
	// <=> N.X * T.X + N.Y * T.Y + N.Z * T.Z = 0
	// <=> T.Z = -1 / N.Z * (N.X * T.X + N.Y * T.Y)
	Tangent.X = 1;
	Tangent.Y = 1;
	Tangent.Z = -1 / Normal.Z * (Normal.X * Tangent.X + Normal.Y * Tangent.Y);
	Tangent.Normalize();

	// Compute bitangent
	FVector Bitangent = FVector::CrossProduct(Tangent, Normal).GetSafeNormal();

	TArray<FIntVector> Positions;
	TArray<FColor> Colors;

	float Scale = World->GetTransform().GetScale3D().Size() / 4;

	int IntRadius = FMath::CeilToInt(Radius);
	for (int x = -IntRadius; x <= IntRadius; x++)
	{
		for (int y = -IntRadius; y <= IntRadius; y++)
		{
			FHitResult Hit;
			FVector Start = ToolPosition + Tangent * x * Scale + Bitangent * y * Scale;
			FVector End = Start - Normal * MaxDistance;
			if (bDebugLines)
			{
				DrawDebugLine(World->GetWorld(), Start, End, FColor::Magenta, false, 1);
			}

			if (World->GetWorld()->LineTraceSingleByChannel(Hit, Start, End, ECollisionChannel::ECC_WorldDynamic))
			{
				if (bDebugPoints)
				{
					DrawDebugPoint(World->GetWorld(), Hit.ImpactPoint, 2, FColor::Red, false, 1);
				}

				FIntVector CurrentPosition = World->GlobalToLocal(Hit.ImpactPoint);
				float Distance = FVector2D(x, y).Size();
				float Alpha = (FMath::Clamp(Radius - Distance, -1.f, FadeDistance) + 1) / (1 + FadeDistance);
				FColor CurrentColor = FLinearColor::LerpUsingHSV(World->GetColor(CurrentPosition), Color, Alpha).ToFColor(true);

				if (!Positions.Contains(CurrentPosition))
				{
					Positions.Add(CurrentPosition);
					Colors.Add(CurrentColor);
				}
			}
		}
	}
	for (int i = 0; i < Positions.Num(); i++)
	{
		World->SetColor(Positions[i], Colors[i]);

		if (bQueueUpdate)
		{
			World->QueueUpdate(Positions[i]);
		}
	}
	if (bApplyUpdates)
	{
		World->ApplyQueuedUpdates(bAsync);
	}
}

void UVoxelTools::SmoothValue(AVoxelWorld * World, FVector Position, FVector Normal, float Radius, float Speed, float MaxDistance, bool bQueueUpdate, bool bApplyUpdates, bool bAsync, bool bDebugLines, bool bDebugPoints)
{
	if (World == nullptr)
	{
		UE_LOG(VoxelLog, Error, TEXT("World is NULL"));
		return;
	}
	check(World);
	FVector ToolPosition = Position + Normal * MaxDistance / 2;

	// Compute tangent
	FVector Tangent;
	// N dot T = 0
	// <=> N.X * T.X + N.Y * T.Y + N.Z * T.Z = 0
	// <=> T.Z = -1 / N.Z * (N.X * T.X + N.Y * T.Y)
	Tangent.X = 1;
	Tangent.Y = 1;
	Tangent.Z = -1 / Normal.Z * (Normal.X * Tangent.X + Normal.Y * Tangent.Y);
	Tangent.Normalize();

	// Compute bitangent
	FVector Bitangent = FVector::CrossProduct(Tangent, Normal).GetSafeNormal();

	TArray<FIntVector> Positions;
	float MeanValue = 0;

	float Scale = World->GetTransform().GetScale3D().Size() / 4;

	int IntRadius = FMath::CeilToInt(Radius);
	for (int x = -IntRadius; x <= IntRadius; x++)
	{
		for (int y = -IntRadius; y <= IntRadius; y++)
		{
			if (x*x + y*y < Radius*Radius)
			{
				FHitResult Hit;
				FVector Start = ToolPosition + Tangent * x * Scale + Bitangent * y * Scale;
				FVector End = Start - Normal * MaxDistance;
				if (bDebugLines)
				{
					DrawDebugLine(World->GetWorld(), Start, End, FColor::Magenta, false, 1);
				}

				if (World->GetWorld()->LineTraceSingleByChannel(Hit, Start, End, ECollisionChannel::ECC_WorldDynamic))
				{
					if (bDebugPoints)
					{
						DrawDebugPoint(World->GetWorld(), Hit.ImpactPoint, 2, FColor::Red, false, 1);
					}

					FIntVector CurrentPosition = World->GlobalToLocal(Hit.ImpactPoint);

					if (!Positions.Contains(CurrentPosition))
					{
						Positions.Add(CurrentPosition);
						MeanValue += World->GetValue(CurrentPosition);
					}
				}
			}
		}
	}

	if (Positions.Num() != 0)
	{
		MeanValue /= Positions.Num();
	}

	for (FIntVector CurrentPosition : Positions)
	{
		World->SetValue(CurrentPosition, FMath::Lerp(World->GetValue(CurrentPosition), MeanValue, Speed));

		if (bQueueUpdate)
		{
			World->QueueUpdate(CurrentPosition);
		}
	}
	if (bApplyUpdates)
	{
		World->ApplyQueuedUpdates(bAsync);
	}
}

void UVoxelTools::ImportMesh(bool bAdd, AVoxelWorld* World, UPrimitiveComponent* Component, AActor* Actor)
{
	if (Actor == nullptr)
	{
		UE_LOG(VoxelLog, Error, TEXT("ImportMesh: Actor is Invalid"));
	}
	else
	{
		FVector Origin;
		FVector BoxExtent;
		Actor->GetActorBounds(false, Origin, BoxExtent);
		MeshImporter::ImportMesh(bAdd, Component, World, Origin - BoxExtent, Origin + BoxExtent);
	}
}
<commit_msg>Fixed projection<commit_after>// Copyright 2017 Phyronnaz

#include "VoxelPrivatePCH.h"
#include "VoxelTools.h"
#include "Engine/World.h"
#include "DrawDebugHelpers.h"
#include "ValueOctree.h"
#include "ChunkOctree.h"
#include "MeshImporter.h"

void UVoxelTools::SetValueSphere(AVoxelWorld* World, FVector Position, float Radius, bool bAdd, bool bQueueUpdate, bool bApplyUpdates, bool bAsync)
{
	if (World == nullptr)
	{
		UE_LOG(VoxelLog, Error, TEXT("World is NULL"));
		return;
	}
	check(World);
	FIntVector LocalPosition = World->GlobalToLocal(Position);
	int IntRadius = FMath::CeilToInt(Radius);

	TArray<FIntVector> Corners = {
		LocalPosition + FIntVector(-IntRadius, -IntRadius, -IntRadius),
		LocalPosition + FIntVector(+IntRadius, -IntRadius, -IntRadius),
		LocalPosition + FIntVector(-IntRadius, +IntRadius, -IntRadius),
		LocalPosition + FIntVector(+IntRadius, +IntRadius, -IntRadius),
		LocalPosition + FIntVector(-IntRadius, -IntRadius, +IntRadius),
		LocalPosition + FIntVector(+IntRadius, -IntRadius, +IntRadius),
		LocalPosition + FIntVector(-IntRadius, +IntRadius, +IntRadius),
		LocalPosition + FIntVector(+IntRadius, +IntRadius, +IntRadius)
	};

	// Get smallest octrees
	ValueOctree* SmallValueOctree = World->GetValueOctree().Get();
	ValueOctree* OldSmallValueOctree = SmallValueOctree;
	check(SmallValueOctree);

	bool ContinueShrinking = true;
	while (ContinueShrinking)
	{
		ContinueShrinking = !SmallValueOctree->IsLeaf();
		for (auto Corner : Corners)
		{
			ContinueShrinking = ContinueShrinking && SmallValueOctree->IsInOctree(Corner);
		}

		if (ContinueShrinking)
		{
			OldSmallValueOctree = SmallValueOctree;
			SmallValueOctree = SmallValueOctree->GetChild(Corners[0]);
		}
	}
	SmallValueOctree = OldSmallValueOctree;

	for (int x = -IntRadius; x <= IntRadius; x++)
	{
		for (int y = -IntRadius; y <= IntRadius; y++)
		{
			for (int z = -IntRadius; z <= IntRadius; z++)
			{
				FIntVector CurrentPosition = LocalPosition + FIntVector(x, y, z);
				float Distance = FVector(x, y, z).Size();

				if (Distance <= Radius + 1)
				{
					float Value = (bAdd ? -1 : 1) * (Radius - Distance);

					if ((Value < 0 && bAdd) || (Value >= 0 && !bAdd) || (SmallValueOctree->GetValue(CurrentPosition) * Value > 0))
					{
						SmallValueOctree->SetValue(CurrentPosition, Value);
						if (bQueueUpdate)
						{
							World->QueueUpdate(CurrentPosition);
						}
					}
				}
			}
		}
	}
	if (bApplyUpdates)
	{
		World->ApplyQueuedUpdates(bAsync);
	}
}

void UVoxelTools::SetColorSphere(AVoxelWorld* World, FVector Position, float Radius, FLinearColor Color, float FadeDistance, bool bQueueUpdate, bool bApplyUpdates, bool bAsync)
{
	if (World == nullptr)
	{
		UE_LOG(VoxelLog, Error, TEXT("World is NULL"));
		return;
	}
	check(World);
	FIntVector LocalPosition = World->GlobalToLocal(Position);
	int IntRadius = FMath::CeilToInt(Radius);

	for (int x = -IntRadius; x <= IntRadius; x++)
	{
		for (int y = -IntRadius; y <= IntRadius; y++)
		{
			for (int z = -IntRadius; z <= IntRadius; z++)
			{
				FIntVector CurrentPosition = LocalPosition + FIntVector(x, y, z);
				float Distance = FVector(x, y, z).Size();
				float Alpha = (FMath::Clamp(Radius - Distance, -1.f, FadeDistance) + 1) / (1 + FadeDistance);
				FColor CurrentColor = FLinearColor::LerpUsingHSV(World->GetColor(CurrentPosition), Color, Alpha).ToFColor(true);

				World->SetColor(CurrentPosition, CurrentColor);
				if (bQueueUpdate)
				{
					World->QueueUpdate(CurrentPosition);
				}
			}
		}
	}
	if (bApplyUpdates)
	{
		World->ApplyQueuedUpdates(bAsync);
	}
}

void UVoxelTools::SetValueCone(AVoxelWorld * World, FVector Position, float Radius, float Height, bool bAdd, bool bQueueUpdate, bool bApplyUpdates, bool bAsync)
{
	if (World == nullptr)
	{
		UE_LOG(VoxelLog, Error, TEXT("World is NULL"));
		return;
	}
	check(World);
	FIntVector LocalPosition = World->GlobalToLocal(Position);
	int IntRadius = FMath::CeilToInt(Radius);
	int IntHeight = FMath::CeilToInt(Height);

	for (int x = -IntRadius; x <= IntRadius; x++)
	{
		for (int y = -IntRadius; y <= IntRadius; y++)
		{
			for (int z = 0; z <= IntHeight; z++)
			{
				FIntVector CurrentPosition = LocalPosition + FIntVector(x, y, z);
				float CurrentRadius = z * (Radius / Height);
				float Distance = FVector2D(x, y).Size();

				if (Distance <= CurrentRadius + 1)
				{
					float Alpha = FMath::Clamp(CurrentRadius - Distance, -1.f, 1.f);

					int Value = (bAdd ? -1 : 1) * (int)(127 * Alpha);

					if ((Value < 0 && bAdd) || (Value >= 0 && !bAdd) || (World->GetValue(CurrentPosition) * Value > 0))
					{
						World->SetValue(CurrentPosition, Value);
						if (bQueueUpdate)
						{
							World->QueueUpdate(CurrentPosition);
						}
					}
				}
			}
		}
	}
	if (bApplyUpdates)
	{
		World->ApplyQueuedUpdates(bAsync);
	}
}

void UVoxelTools::SetValueProjection(AVoxelWorld* World, FVector Position, FVector Normal, float Radius, int Stength, bool bAdd, float MaxDistance, bool bQueueUpdate, bool bApplyUpdates, bool bAsync, bool bDebugLines, bool bDebugPoints)
{
	if (World == nullptr)
	{
		UE_LOG(VoxelLog, Error, TEXT("World is NULL"));
		return;
	}
	check(World);
	FVector ToolPosition = Position + Normal * MaxDistance / 2;

	// Compute tangent
	FVector Tangent;
	// N dot T = 0
	// <=> N.X * T.X + N.Y * T.Y + N.Z * T.Z = 0
	// <=> T.Z = -1 / N.Z * (N.X * T.X + N.Y * T.Y)
	Tangent.X = 1;
	Tangent.Y = 1;
	Tangent.Z = -1 / Normal.Z * (Normal.X * Tangent.X + Normal.Y * Tangent.Y);
	Tangent.Normalize();

	// Compute bitangent
	FVector Bitangent = FVector::CrossProduct(Tangent, Normal).GetSafeNormal();

	TArray<FIntVector> Points;
	float Scale = World->GetTransform().GetScale3D().Size() / 4;

	int IntRadius = FMath::CeilToInt(Radius);
	for (int x = -IntRadius; x <= IntRadius; x++)
	{
		for (int y = -IntRadius; y <= IntRadius; y++)
		{
			if (x*x + y*y < Radius*Radius)
			{
				FHitResult Hit;
				FVector Start = ToolPosition + Tangent * x * Scale + Bitangent * y * Scale;
				FVector End = Start - Normal * MaxDistance;
				if (bDebugLines)
				{
					DrawDebugLine(World->GetWorld(), Start, End, FColor::Magenta, false, 1);
				}
				if (World->GetWorld()->LineTraceSingleByChannel(Hit, Start, End, ECollisionChannel::ECC_WorldDynamic) && Hit.Actor->IsA(AVoxelChunk::StaticClass()))
				{
					if (bDebugPoints)
					{
						DrawDebugPoint(World->GetWorld(), Hit.ImpactPoint, 2, FColor::Red, false, 1);
					}
					Points.AddUnique(World->GlobalToLocal(Hit.ImpactPoint));
				}
			}
		}
	}
	for (FIntVector Point : Points)
	{
		if (bAdd)
		{
			World->Add(Point, Stength);
		}
		else
		{
			World->Remove(Point, Stength);
		}
		if (bQueueUpdate)
		{
			World->QueueUpdate(Point);
		}
	}
	if (bApplyUpdates)
	{
		World->ApplyQueuedUpdates(bAsync);
	}
}

void UVoxelTools::SetColorProjection(AVoxelWorld * World, FVector Position, FVector Normal, float Radius, FLinearColor Color, float FadeDistance, float MaxDistance, bool bQueueUpdate, bool bApplyUpdates, bool bAsync, bool bDebugLines, bool bDebugPoints)
{
	if (World == NULL)
	{
		UE_LOG(VoxelLog, Error, TEXT("World is NULL"));
		return;
	}
	check(World);
	FVector ToolPosition = Position + Normal * MaxDistance / 2;

	// Compute tangent
	FVector Tangent;
	// N dot T = 0
	// <=> N.X * T.X + N.Y * T.Y + N.Z * T.Z = 0
	// <=> T.Z = -1 / N.Z * (N.X * T.X + N.Y * T.Y)
	Tangent.X = 1;
	Tangent.Y = 1;
	Tangent.Z = -1 / Normal.Z * (Normal.X * Tangent.X + Normal.Y * Tangent.Y);
	Tangent.Normalize();

	// Compute bitangent
	FVector Bitangent = FVector::CrossProduct(Tangent, Normal).GetSafeNormal();

	TArray<FIntVector> Positions;
	TArray<FColor> Colors;

	float Scale = World->GetTransform().GetScale3D().Size() / 4;

	int IntRadius = FMath::CeilToInt(Radius);
	for (int x = -IntRadius; x <= IntRadius; x++)
	{
		for (int y = -IntRadius; y <= IntRadius; y++)
		{
			FHitResult Hit;
			FVector Start = ToolPosition + Tangent * x * Scale + Bitangent * y * Scale;
			FVector End = Start - Normal * MaxDistance;
			if (bDebugLines)
			{
				DrawDebugLine(World->GetWorld(), Start, End, FColor::Magenta, false, 1);
			}

			if (World->GetWorld()->LineTraceSingleByChannel(Hit, Start, End, ECollisionChannel::ECC_WorldDynamic) && Hit.Actor->IsA(AVoxelChunk::StaticClass()))
			{
				if (bDebugPoints)
				{
					DrawDebugPoint(World->GetWorld(), Hit.ImpactPoint, 2, FColor::Red, false, 1);
				}

				FIntVector CurrentPosition = World->GlobalToLocal(Hit.ImpactPoint);
				float Distance = FVector2D(x, y).Size();
				float Alpha = (FMath::Clamp(Radius - Distance, -1.f, FadeDistance) + 1) / (1 + FadeDistance);
				FColor CurrentColor = FLinearColor::LerpUsingHSV(World->GetColor(CurrentPosition), Color, Alpha).ToFColor(true);

				if (!Positions.Contains(CurrentPosition))
				{
					Positions.Add(CurrentPosition);
					Colors.Add(CurrentColor);
				}
			}
		}
	}
	for (int i = 0; i < Positions.Num(); i++)
	{
		World->SetColor(Positions[i], Colors[i]);

		if (bQueueUpdate)
		{
			World->QueueUpdate(Positions[i]);
		}
	}
	if (bApplyUpdates)
	{
		World->ApplyQueuedUpdates(bAsync);
	}
}

void UVoxelTools::SmoothValue(AVoxelWorld * World, FVector Position, FVector Normal, float Radius, float Speed, float MaxDistance, bool bQueueUpdate, bool bApplyUpdates, bool bAsync, bool bDebugLines, bool bDebugPoints)
{
	if (World == nullptr)
	{
		UE_LOG(VoxelLog, Error, TEXT("World is NULL"));
		return;
	}
	check(World);
	FVector ToolPosition = Position + Normal * MaxDistance / 2;

	// Compute tangent
	FVector Tangent;
	// N dot T = 0
	// <=> N.X * T.X + N.Y * T.Y + N.Z * T.Z = 0
	// <=> T.Z = -1 / N.Z * (N.X * T.X + N.Y * T.Y)
	Tangent.X = 1;
	Tangent.Y = 1;
	Tangent.Z = -1 / Normal.Z * (Normal.X * Tangent.X + Normal.Y * Tangent.Y);
	Tangent.Normalize();

	// Compute bitangent
	FVector Bitangent = FVector::CrossProduct(Tangent, Normal).GetSafeNormal();

	TArray<FIntVector> Positions;
	float MeanValue = 0;

	float Scale = World->GetTransform().GetScale3D().Size() / 4;

	int IntRadius = FMath::CeilToInt(Radius);
	for (int x = -IntRadius; x <= IntRadius; x++)
	{
		for (int y = -IntRadius; y <= IntRadius; y++)
		{
			if (x*x + y*y < Radius*Radius)
			{
				FHitResult Hit;
				FVector Start = ToolPosition + Tangent * x * Scale + Bitangent * y * Scale;
				FVector End = Start - Normal * MaxDistance;
				if (bDebugLines)
				{
					DrawDebugLine(World->GetWorld(), Start, End, FColor::Magenta, false, 1);
				}

				if (World->GetWorld()->LineTraceSingleByChannel(Hit, Start, End, ECollisionChannel::ECC_WorldDynamic))
				{
					if (bDebugPoints)
					{
						DrawDebugPoint(World->GetWorld(), Hit.ImpactPoint, 2, FColor::Red, false, 1);
					}

					FIntVector CurrentPosition = World->GlobalToLocal(Hit.ImpactPoint);

					if (!Positions.Contains(CurrentPosition))
					{
						Positions.Add(CurrentPosition);
						MeanValue += World->GetValue(CurrentPosition);
					}
				}
			}
		}
	}

	if (Positions.Num() != 0)
	{
		MeanValue /= Positions.Num();
	}

	for (FIntVector CurrentPosition : Positions)
	{
		World->SetValue(CurrentPosition, FMath::Lerp(World->GetValue(CurrentPosition), MeanValue, Speed));

		if (bQueueUpdate)
		{
			World->QueueUpdate(CurrentPosition);
		}
	}
	if (bApplyUpdates)
	{
		World->ApplyQueuedUpdates(bAsync);
	}
}

void UVoxelTools::ImportMesh(bool bAdd, AVoxelWorld* World, UPrimitiveComponent* Component, AActor* Actor)
{
	if (Actor == nullptr)
	{
		UE_LOG(VoxelLog, Error, TEXT("ImportMesh: Actor is Invalid"));
	}
	else
	{
		FVector Origin;
		FVector BoxExtent;
		Actor->GetActorBounds(false, Origin, BoxExtent);
		MeshImporter::ImportMesh(bAdd, Component, World, Origin - BoxExtent, Origin + BoxExtent);
	}
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "ShadowNode.h"

#include <better/small_vector.h>

#include <react/core/ComponentDescriptor.h>
#include <react/core/ShadowNodeFragment.h>
#include <react/debug/DebugStringConvertible.h>
#include <react/debug/debugStringConvertibleUtils.h>

namespace facebook {
namespace react {

using AncestorList = ShadowNode::AncestorList;

SharedShadowNodeSharedList ShadowNode::emptySharedShadowNodeSharedList() {
  static const auto emptySharedShadowNodeSharedList =
      std::make_shared<SharedShadowNodeList>();
  return emptySharedShadowNodeSharedList;
}

bool ShadowNode::sameFamily(const ShadowNode &first, const ShadowNode &second) {
  return first.family_ == second.family_;
}

#pragma mark - Constructors

ShadowNode::ShadowNode(
    const ShadowNodeFragment &fragment,
    const ComponentDescriptor &componentDescriptor)
    : props_(fragment.props),
      children_(
          fragment.children ? fragment.children
                            : emptySharedShadowNodeSharedList()),
      state_(fragment.state),
      family_(std::make_shared<ShadowNodeFamily const>(
          fragment.tag,
          fragment.surfaceId,
          fragment.eventEmitter,
          componentDescriptor)),
      childrenAreShared_(true),
      revision_(1) {
  assert(props_);
  assert(children_);

  for (const auto &child : *children_) {
    child->family_->setParent(family_);
  }
}

ShadowNode::ShadowNode(
    const ShadowNode &sourceShadowNode,
    const ShadowNodeFragment &fragment)
    : props_(fragment.props ? fragment.props : sourceShadowNode.props_),
      children_(
          fragment.children ? fragment.children : sourceShadowNode.children_),
      localData_(
          fragment.localData ? fragment.localData
                             : sourceShadowNode.localData_),
      state_(
          fragment.state ? fragment.state
                         : sourceShadowNode.getMostRecentState()),
      family_(sourceShadowNode.family_),
      childrenAreShared_(true),
      revision_(sourceShadowNode.revision_ + 1) {
  // `tag`, `surfaceId`, and `eventEmitter` cannot be changed with cloning.
  assert(fragment.tag == ShadowNodeFragment::tagPlaceholder());
  assert(fragment.surfaceId == ShadowNodeFragment::surfaceIdPlaceholder());
  assert(
      fragment.eventEmitter == ShadowNodeFragment::eventEmitterPlaceholder());

  assert(props_);
  assert(children_);

  if (fragment.children) {
    for (const auto &child : *children_) {
      child->family_->setParent(family_);
    }
  }
}

UnsharedShadowNode ShadowNode::clone(const ShadowNodeFragment &fragment) const {
  return family_->componentDescriptor_.cloneShadowNode(*this, fragment);
}

#pragma mark - Getters

ComponentName ShadowNode::getComponentName() const {
  return family_->componentDescriptor_.getComponentName();
}

ComponentHandle ShadowNode::getComponentHandle() const {
  return family_->componentDescriptor_.getComponentHandle();
}

const SharedShadowNodeList &ShadowNode::getChildren() const {
  return *children_;
}

const SharedProps &ShadowNode::getProps() const {
  return props_;
}

const SharedEventEmitter &ShadowNode::getEventEmitter() const {
  return family_->eventEmitter_;
}

Tag ShadowNode::getTag() const {
  return family_->tag_;
}

SurfaceId ShadowNode::getSurfaceId() const {
  return family_->surfaceId_;
}

const ComponentDescriptor &ShadowNode::getComponentDescriptor() const {
  return family_->componentDescriptor_;
}

const State::Shared &ShadowNode::getState() const {
  return state_;
}

State::Shared ShadowNode::getMostRecentState() const {
  if (state_) {
    auto commitedState = state_->getMostRecentState();

    // Commited state can be `null` in case if no one node was commited yet;
    // in this case we return own `state`.
    return commitedState ? commitedState : state_;
  }

  return ShadowNodeFragment::statePlaceholder();
}

SharedLocalData ShadowNode::getLocalData() const {
  return localData_;
}

void ShadowNode::sealRecursive() const {
  if (getSealed()) {
    return;
  }

  seal();

  props_->seal();

  for (auto child : *children_) {
    child->sealRecursive();
  }
}

#pragma mark - Mutating Methods

void ShadowNode::appendChild(const SharedShadowNode &child) {
  ensureUnsealed();

  cloneChildrenIfShared();
  auto nonConstChildren =
      std::const_pointer_cast<SharedShadowNodeList>(children_);
  nonConstChildren->push_back(child);

  child->family_->setParent(family_);
}

void ShadowNode::replaceChild(
    const SharedShadowNode &oldChild,
    const SharedShadowNode &newChild,
    int suggestedIndex) {
  ensureUnsealed();

  cloneChildrenIfShared();

  auto nonConstChildren =
      std::const_pointer_cast<SharedShadowNodeList>(children_);

  if (suggestedIndex != -1 && suggestedIndex < nonConstChildren->size()) {
    if (nonConstChildren->at(suggestedIndex) == oldChild) {
      (*nonConstChildren)[suggestedIndex] = newChild;
      return;
    }
  }

  std::replace(
      nonConstChildren->begin(), nonConstChildren->end(), oldChild, newChild);

  newChild->family_->setParent(family_);
}

void ShadowNode::setLocalData(const SharedLocalData &localData) {
  ensureUnsealed();
  localData_ = localData;
}

void ShadowNode::cloneChildrenIfShared() {
  if (!childrenAreShared_) {
    return;
  }
  childrenAreShared_ = false;
  children_ = std::make_shared<SharedShadowNodeList>(*children_);
}

void ShadowNode::setMounted(bool mounted) const {
  family_->eventEmitter_->setEnabled(mounted);
  if (mounted && state_) {
    state_->commit(*this);
  }
}

AncestorList ShadowNode::getAncestors(
    ShadowNode const &ancestorShadowNode) const {
  auto ancestors = AncestorList{};
  auto families = better::small_vector<ShadowNodeFamily const *, 64>{};
  auto ancestorFamily = ancestorShadowNode.family_.get();
  auto descendantFamily = family_.get();

  auto family = descendantFamily;
  while (family && family != ancestorFamily) {
    families.push_back(family);
    family = family->parent_.lock().get();
  }

  if (family != ancestorFamily) {
    ancestors.clear();
    return ancestors;
  }

  auto parentNode = &ancestorShadowNode;
  for (auto it = families.rbegin(); it != families.rend(); it++) {
    auto childFamily = *it;
    auto found = bool{false};
    auto childIndex = int{0};
    for (const auto &childNode : *parentNode->children_) {
      if (childNode->family_.get() == childFamily) {
        ancestors.push_back({*parentNode, childIndex});
        parentNode = childNode.get();
        found = true;
        break;
      }
      childIndex++;
    }

    if (!found) {
      ancestors.clear();
      return ancestors;
    }
  }

  return ancestors;
}

#pragma mark - DebugStringConvertible

#if RN_DEBUG_STRING_CONVERTIBLE
std::string ShadowNode::getDebugName() const {
  return getComponentName();
}

std::string ShadowNode::getDebugValue() const {
  return "r" + folly::to<std::string>(revision_) +
      (getSealed() ? "/sealed" : "");
}

SharedDebugStringConvertibleList ShadowNode::getDebugChildren() const {
  auto debugChildren = SharedDebugStringConvertibleList{};

  for (auto child : *children_) {
    auto debugChild =
        std::dynamic_pointer_cast<const DebugStringConvertible>(child);
    if (debugChild) {
      debugChildren.push_back(debugChild);
    }
  }

  return debugChildren;
}

SharedDebugStringConvertibleList ShadowNode::getDebugProps() const {
  return props_->getDebugProps() +
      SharedDebugStringConvertibleList{
          debugStringConvertibleItem("tag", folly::to<std::string>(getTag()))};
}
#endif

} // namespace react
} // namespace facebook
<commit_msg>fix typo in code (#26655)<commit_after>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "ShadowNode.h"

#include <better/small_vector.h>

#include <react/core/ComponentDescriptor.h>
#include <react/core/ShadowNodeFragment.h>
#include <react/debug/DebugStringConvertible.h>
#include <react/debug/debugStringConvertibleUtils.h>

namespace facebook {
namespace react {

using AncestorList = ShadowNode::AncestorList;

SharedShadowNodeSharedList ShadowNode::emptySharedShadowNodeSharedList() {
  static const auto emptySharedShadowNodeSharedList =
      std::make_shared<SharedShadowNodeList>();
  return emptySharedShadowNodeSharedList;
}

bool ShadowNode::sameFamily(const ShadowNode &first, const ShadowNode &second) {
  return first.family_ == second.family_;
}

#pragma mark - Constructors

ShadowNode::ShadowNode(
    const ShadowNodeFragment &fragment,
    const ComponentDescriptor &componentDescriptor)
    : props_(fragment.props),
      children_(
          fragment.children ? fragment.children
                            : emptySharedShadowNodeSharedList()),
      state_(fragment.state),
      family_(std::make_shared<ShadowNodeFamily const>(
          fragment.tag,
          fragment.surfaceId,
          fragment.eventEmitter,
          componentDescriptor)),
      childrenAreShared_(true),
      revision_(1) {
  assert(props_);
  assert(children_);

  for (const auto &child : *children_) {
    child->family_->setParent(family_);
  }
}

ShadowNode::ShadowNode(
    const ShadowNode &sourceShadowNode,
    const ShadowNodeFragment &fragment)
    : props_(fragment.props ? fragment.props : sourceShadowNode.props_),
      children_(
          fragment.children ? fragment.children : sourceShadowNode.children_),
      localData_(
          fragment.localData ? fragment.localData
                             : sourceShadowNode.localData_),
      state_(
          fragment.state ? fragment.state
                         : sourceShadowNode.getMostRecentState()),
      family_(sourceShadowNode.family_),
      childrenAreShared_(true),
      revision_(sourceShadowNode.revision_ + 1) {
  // `tag`, `surfaceId`, and `eventEmitter` cannot be changed with cloning.
  assert(fragment.tag == ShadowNodeFragment::tagPlaceholder());
  assert(fragment.surfaceId == ShadowNodeFragment::surfaceIdPlaceholder());
  assert(
      fragment.eventEmitter == ShadowNodeFragment::eventEmitterPlaceholder());

  assert(props_);
  assert(children_);

  if (fragment.children) {
    for (const auto &child : *children_) {
      child->family_->setParent(family_);
    }
  }
}

UnsharedShadowNode ShadowNode::clone(const ShadowNodeFragment &fragment) const {
  return family_->componentDescriptor_.cloneShadowNode(*this, fragment);
}

#pragma mark - Getters

ComponentName ShadowNode::getComponentName() const {
  return family_->componentDescriptor_.getComponentName();
}

ComponentHandle ShadowNode::getComponentHandle() const {
  return family_->componentDescriptor_.getComponentHandle();
}

const SharedShadowNodeList &ShadowNode::getChildren() const {
  return *children_;
}

const SharedProps &ShadowNode::getProps() const {
  return props_;
}

const SharedEventEmitter &ShadowNode::getEventEmitter() const {
  return family_->eventEmitter_;
}

Tag ShadowNode::getTag() const {
  return family_->tag_;
}

SurfaceId ShadowNode::getSurfaceId() const {
  return family_->surfaceId_;
}

const ComponentDescriptor &ShadowNode::getComponentDescriptor() const {
  return family_->componentDescriptor_;
}

const State::Shared &ShadowNode::getState() const {
  return state_;
}

State::Shared ShadowNode::getMostRecentState() const {
  if (state_) {
    auto committedState = state_->getMostRecentState();

    // Committed state can be `null` in case if no one node was committed yet;
    // in this case we return own `state`.
    return committedState ? committedState : state_;
  }

  return ShadowNodeFragment::statePlaceholder();
}

SharedLocalData ShadowNode::getLocalData() const {
  return localData_;
}

void ShadowNode::sealRecursive() const {
  if (getSealed()) {
    return;
  }

  seal();

  props_->seal();

  for (auto child : *children_) {
    child->sealRecursive();
  }
}

#pragma mark - Mutating Methods

void ShadowNode::appendChild(const SharedShadowNode &child) {
  ensureUnsealed();

  cloneChildrenIfShared();
  auto nonConstChildren =
      std::const_pointer_cast<SharedShadowNodeList>(children_);
  nonConstChildren->push_back(child);

  child->family_->setParent(family_);
}

void ShadowNode::replaceChild(
    const SharedShadowNode &oldChild,
    const SharedShadowNode &newChild,
    int suggestedIndex) {
  ensureUnsealed();

  cloneChildrenIfShared();

  auto nonConstChildren =
      std::const_pointer_cast<SharedShadowNodeList>(children_);

  if (suggestedIndex != -1 && suggestedIndex < nonConstChildren->size()) {
    if (nonConstChildren->at(suggestedIndex) == oldChild) {
      (*nonConstChildren)[suggestedIndex] = newChild;
      return;
    }
  }

  std::replace(
      nonConstChildren->begin(), nonConstChildren->end(), oldChild, newChild);

  newChild->family_->setParent(family_);
}

void ShadowNode::setLocalData(const SharedLocalData &localData) {
  ensureUnsealed();
  localData_ = localData;
}

void ShadowNode::cloneChildrenIfShared() {
  if (!childrenAreShared_) {
    return;
  }
  childrenAreShared_ = false;
  children_ = std::make_shared<SharedShadowNodeList>(*children_);
}

void ShadowNode::setMounted(bool mounted) const {
  family_->eventEmitter_->setEnabled(mounted);
  if (mounted && state_) {
    state_->commit(*this);
  }
}

AncestorList ShadowNode::getAncestors(
    ShadowNode const &ancestorShadowNode) const {
  auto ancestors = AncestorList{};
  auto families = better::small_vector<ShadowNodeFamily const *, 64>{};
  auto ancestorFamily = ancestorShadowNode.family_.get();
  auto descendantFamily = family_.get();

  auto family = descendantFamily;
  while (family && family != ancestorFamily) {
    families.push_back(family);
    family = family->parent_.lock().get();
  }

  if (family != ancestorFamily) {
    ancestors.clear();
    return ancestors;
  }

  auto parentNode = &ancestorShadowNode;
  for (auto it = families.rbegin(); it != families.rend(); it++) {
    auto childFamily = *it;
    auto found = bool{false};
    auto childIndex = int{0};
    for (const auto &childNode : *parentNode->children_) {
      if (childNode->family_.get() == childFamily) {
        ancestors.push_back({*parentNode, childIndex});
        parentNode = childNode.get();
        found = true;
        break;
      }
      childIndex++;
    }

    if (!found) {
      ancestors.clear();
      return ancestors;
    }
  }

  return ancestors;
}

#pragma mark - DebugStringConvertible

#if RN_DEBUG_STRING_CONVERTIBLE
std::string ShadowNode::getDebugName() const {
  return getComponentName();
}

std::string ShadowNode::getDebugValue() const {
  return "r" + folly::to<std::string>(revision_) +
      (getSealed() ? "/sealed" : "");
}

SharedDebugStringConvertibleList ShadowNode::getDebugChildren() const {
  auto debugChildren = SharedDebugStringConvertibleList{};

  for (auto child : *children_) {
    auto debugChild =
        std::dynamic_pointer_cast<const DebugStringConvertible>(child);
    if (debugChild) {
      debugChildren.push_back(debugChild);
    }
  }

  return debugChildren;
}

SharedDebugStringConvertibleList ShadowNode::getDebugProps() const {
  return props_->getDebugProps() +
      SharedDebugStringConvertibleList{
          debugStringConvertibleItem("tag", folly::to<std::string>(getTag()))};
}
#endif

} // namespace react
} // namespace facebook
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    TestPickingManager.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

/*==============================================================================

  Library: MSVTK

  Copyright (c) Kitware Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0.txt

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

==============================================================================*/

// .NAME Test of PickingManager.
// .SECTION Description
// Tests PickingManager internal data structure.

// VTK includes
#include "vtkNew.h"
#include "vtkObjectFactory.h"
#include "vtkPicker.h"
#include "vtkPickingManager.h"
#include "vtkSmartPointer.h"

#define VTK_VERIFY(test, errorStr) this->VTKVerify((test), (errorStr), __LINE__)

class PickingManagerTest
{
public:
  bool TestProperties();
  bool TestAddPickers();
  bool TestRemovePickers();
  bool TestRemoveObjects();

  bool VTKVerify(bool test, const char* errorStr, int line);
  void PrintErrorMessage(int line, const char* errorStr);

protected:
  std::pair<vtkPicker*, vtkObject*> AddPickerObject(int pickerType,
                                                    int objectType);

  bool AddPicker(int pickerType, int objectType,
                 int numberOfPickers, int numberOfObjectsLinked);

  bool AddPickerTwice(int pickerType0, int objectType0,
                      int pickerType1, int objectType1,
                      bool samePicker, int numberOfPickers,
                      int numberOfObjectsLinked0, int numberOfObjectsLinked1);

  bool RemovePicker(int pickerType, int numberOfPickers);
  bool RemoveOneOfPickers(int pickerType0, int objectType0,
                          int pickerType1, int objectType1,
                          bool samePicker, int numberOfPickers,
                          int numberOfObjectsLinked0,
                          int numberOfObjectsLinked1);

  bool RemoveObject(int pickerType, int objectType,
                    int numberOfPickers, int numberOfObjectsLinked1);

  bool CheckState(int numberOfPickers,
                  vtkPicker* picker = 0,
                  int NumberOfObjectsLinked = 0);

private:
  vtkSmartPointer<vtkPickingManager> PickingManager;
};

//------------------------------------------------------------------------------
int TestPickingManager(int, char*[])
{
  PickingManagerTest pickingManagerTest;

  bool res = true;

  res = res && pickingManagerTest.TestProperties();
  res = res && pickingManagerTest.TestAddPickers();
  res = res && pickingManagerTest.TestRemovePickers();
  res = res && pickingManagerTest.TestRemoveObjects();

  return res ? EXIT_SUCCESS : EXIT_FAILURE;
}

//------------------------------------------------------------------------------
bool PickingManagerTest::TestProperties()
{
  this->PickingManager = vtkPickingManager::New();

  bool res = true;

  // Default
  res = VTK_VERIFY(this->PickingManager->GetEnabled() == 0,
                   "Error manager not disabled by default") && res;
  res = VTK_VERIFY(this->PickingManager->GetOptimizeOnInteractorEvents() == 1,
                   "Error optimizationOnInteractor not enabled by default:")
        && res;
  res = VTK_VERIFY(this->PickingManager->GetInteractor() == 0,
                   "Error interactor not null by default:") && res;
  res = VTK_VERIFY(this->PickingManager->GetNumberOfPickers() == 0,
                   "Error numberOfPickers not nul by default:") && res;
  res = VTK_VERIFY(this->PickingManager->GetNumberOfObjectsLinked(0) == 0,
                   "Error NumberOfObjectsLinked not nul with null picker:")
        && res;

  // Settings properties
  this->PickingManager->EnabledOn();
  res = VTK_VERIFY(this->PickingManager->GetEnabled() == 1,
                   "Error manager not does not enable:") && res;
  this->PickingManager->SetOptimizeOnInteractorEvents(false);
  res = VTK_VERIFY(this->PickingManager->GetOptimizeOnInteractorEvents() == 1,
    "Error OptimizeOnInteractorEvents does not get disabled:")
    && res;

  return res;
}

//------------------------------------------------------------------------------
bool PickingManagerTest::TestAddPickers()
{
  bool res = true;

  // Simple Add
  res = VTK_VERIFY(this->AddPicker(0, 0, 0, 0),
                   "Error adding a null picker:") && res;
  res = VTK_VERIFY(this->AddPicker(0, 1, 0, 0),
                   "Error adding a null picker with an object:") && res;
  res = VTK_VERIFY(this->AddPicker(1, 0, 1, 1),
                   "Error adding a picker with a null object:") && res;
  res = VTK_VERIFY(this->AddPicker(1, 1, 1, 1),
                   "Error adding a picker with an object:") && res;

  // Twice Add
  res = VTK_VERIFY(this->AddPickerTwice(1, 0, 1, 0, false, 2, 1, 1),
                   "Error adding two pickers with null objects:") && res;
  res = VTK_VERIFY(this->AddPickerTwice(1, 0, 1, 0, true, 1, 2, 2),
                   "Error adding same picker with null objects:") && res;
  res = VTK_VERIFY(this->AddPickerTwice(1, 1, 1, 1, false, 2, 1, 1),
                   "Error adding pickers with valid objects:") && res;
  res = VTK_VERIFY(this->AddPickerTwice(1, 1, 1, 1, true, 1, 2, 2),
                  "Error adding same picker with valid objects:") && res;

  // Particular case: same picker with same valid object
  this->PickingManager = vtkPickingManager::New();
  vtkNew<vtkPicker> picker;
  vtkNew<vtkObject> object;
  this->PickingManager->AddPicker(picker.GetPointer(), object.GetPointer());
  this->PickingManager->AddPicker(picker.GetPointer(), object.GetPointer());

  res = VTK_VERIFY(this->CheckState(1, picker.GetPointer(), 1),
                  "Error adding same picker with same object:") && res;

  return res;
}

//------------------------------------------------------------------------------
bool PickingManagerTest::TestRemovePickers()
{
  bool res = true;

  // Remove Picker following a simple add
  res = VTK_VERIFY(this->RemovePicker(0, 0),
                   "Error removing null picker:") && res;
  res = VTK_VERIFY(this->RemovePicker(1, 0),
                   "Error removing existing picker:") && res;

  // Remove Picker following a multiples add
  res = VTK_VERIFY(this->RemoveOneOfPickers(1, 0, 1, 0, false, 1, 0, 1),
                   "Error removing a picker with null object:") && res;
  res = VTK_VERIFY(this->RemoveOneOfPickers(1, 0, 1, 0, true, 1, 1, 1),
                   "Error removing a picker with null objects:") && res;
  res = VTK_VERIFY(this->RemoveOneOfPickers(1, 1, 1, 1, true, 1, 1, 1),
                   "Error adding pickers with valid objects:") && res;

  // Particular case same picker with same valid object
  this->PickingManager = vtkPickingManager::New();
  vtkNew<vtkPicker> picker;
  vtkNew<vtkObject> object;
  this->PickingManager->AddPicker(picker.GetPointer(), object.GetPointer());
  this->PickingManager->AddPicker(picker.GetPointer(), object.GetPointer());
  this->PickingManager->RemovePicker(picker.GetPointer(), object.GetPointer());

  res = VTK_VERIFY(this->CheckState(0, picker.GetPointer(), 0),
                  "Error removing a picker with same object:") && res;

  return res;
}

//------------------------------------------------------------------------------
bool PickingManagerTest::TestRemoveObjects()
{
  bool res = true;

  // Remove Object following a simple add
  res = VTK_VERIFY(this->RemoveObject(0, 0, 0, 0),
                   "Error removing null object without picker:") && res;
  res = VTK_VERIFY(this->RemoveObject(1, 0, 0, 0),
                   "Error removing null object with a picker:") && res;
  res = VTK_VERIFY(this->RemoveObject(0, 1, 0, 0),
                   "Error removing object without picker:") && res;
  res = VTK_VERIFY(this->RemoveObject(1, 1, 0, 0),
                   "Error removing object with a picker:") && res;

  // Particular cases same picker with same valid object
  this->PickingManager = vtkPickingManager::New();
  vtkNew<vtkPicker> picker;
  vtkNew<vtkObject> object;
  this->PickingManager->AddPicker(picker.GetPointer(), object.GetPointer());
  this->PickingManager->AddPicker(picker.GetPointer(), object.GetPointer());
  this->PickingManager->RemoveObject(object.GetPointer());

  res = VTK_VERIFY(this->CheckState(0, picker.GetPointer(), 0),
                  "Error removing an object with same picker:") && res;

  this->PickingManager = vtkPickingManager::New();
  vtkNew<vtkObject> object2;
  this->PickingManager->AddPicker(picker.GetPointer(), object.GetPointer());
  this->PickingManager->AddPicker(picker.GetPointer(), object2.GetPointer());
  this->PickingManager->RemoveObject(object.GetPointer());

  res = VTK_VERIFY(this->CheckState(1, picker.GetPointer(), 1),
                  "Error removing one of the objects with same picker:") && res;

  this->PickingManager = vtkPickingManager::New();
  vtkNew<vtkPicker> picker2;
  this->PickingManager->AddPicker(picker.GetPointer(), object.GetPointer());
  this->PickingManager->AddPicker(picker2.GetPointer(), object.GetPointer());
  this->PickingManager->RemoveObject(object.GetPointer());

  res = VTK_VERIFY(this->CheckState(0, picker.GetPointer(), 0),
                  "Error removing object with different pickers:") && res;

  return res;
}

//------------------------------------------------------------------------------
std::pair<vtkPicker*, vtkObject*> PickingManagerTest::
AddPickerObject(int pickerType, int objectType)
{
  vtkSmartPointer<vtkPicker> picker = (pickerType == 0) ? 0 : vtkPicker::New();
  vtkSmartPointer<vtkObject> object = (objectType == 0) ? 0 : vtkObject::New();

  this->PickingManager->AddPicker(picker, object);

  return std::pair<vtkPicker*, vtkObject*>(picker, object);
}

//------------------------------------------------------------------------------
bool PickingManagerTest::AddPicker(int pickerType, int objectType,
                                   int numberOfPickers,
                                   int numberOfObjectsLinked)
{
  this->PickingManager = vtkPickingManager::New();

  vtkSmartPointer<vtkPicker> picker =
    this->AddPickerObject(pickerType, objectType).first;

  return this->CheckState(numberOfPickers,
                          picker.GetPointer(),
                          numberOfObjectsLinked);
}

//------------------------------------------------------------------------------
bool PickingManagerTest::
AddPickerTwice(int pickerType0, int objectType0,
               int pickerType1, int objectType1,
               bool samePicker, int numberOfPickers,
               int numberOfObjectsLinked0, int numberOfObjectsLinked1)
{
  this->PickingManager = vtkPickingManager::New();

  vtkSmartPointer<vtkPicker> picker0 =
    this->AddPickerObject(pickerType0, objectType0).first;

  vtkSmartPointer<vtkPicker> picker1 = (samePicker) ? picker0.GetPointer() :
    this->AddPickerObject(pickerType1, objectType1).first;

  if (samePicker)
    {
    this->PickingManager->AddPicker(picker1.GetPointer());
    }

  return (this->CheckState(numberOfPickers,
                           picker0.GetPointer(), numberOfObjectsLinked0) &&
          this->CheckState(numberOfPickers,
                           picker1.GetPointer(), numberOfObjectsLinked1));
}

//------------------------------------------------------------------------------
bool PickingManagerTest::RemovePicker(int pickerType, int numberOfPickers)
{
  this->PickingManager = vtkPickingManager::New();
  vtkSmartPointer<vtkPicker> picker = 0;

  if (pickerType > 0)
    {
    picker = this->AddPickerObject(pickerType, 0).first;
    }

  this->PickingManager->RemovePicker(picker.GetPointer());

  return this->CheckState(numberOfPickers, 0, 0);
}

//------------------------------------------------------------------------------
bool PickingManagerTest::
RemoveOneOfPickers(int pickerType0, int objectType0,
                   int pickerType1, int objectType1,
                   bool samePicker, int numberOfPickers,
                   int numberOfObjectsLinked0, int numberOfObjectsLinked1)
{
  this->PickingManager = vtkPickingManager::New();

  vtkSmartPointer<vtkPicker> picker0 =
    this->AddPickerObject(pickerType0, objectType0).first;

  vtkSmartPointer<vtkPicker> picker1 = (samePicker) ? picker0.GetPointer() :
    this->AddPickerObject(pickerType1, objectType1).first;

  if (samePicker)
    {
    this->PickingManager->AddPicker(picker1.GetPointer());
    }

  this->PickingManager->RemovePicker(picker0.GetPointer());

  return (this->CheckState(numberOfPickers,
                           picker0.GetPointer(), numberOfObjectsLinked0) &&
          this->CheckState(numberOfPickers,
                           picker1.GetPointer(), numberOfObjectsLinked1));
}

//------------------------------------------------------------------------------
bool PickingManagerTest::
RemoveObject(int pickerType, int objectType,
             int numberOfPickers, int numberOfObjectsLinked1)
{
  this->PickingManager = vtkPickingManager::New();

  std::pair<vtkSmartPointer<vtkPicker>, vtkSmartPointer<vtkObject> >
    pickerObject = this->AddPickerObject(pickerType, objectType);

  this->PickingManager->RemoveObject(pickerObject.second.GetPointer());

  return this->CheckState(numberOfPickers,
                          pickerObject.first.GetPointer(),
                          numberOfObjectsLinked1);
}

//------------------------------------------------------------------------------
void PickingManagerTest::PrintErrorMessage(int line, const char* errorStr)
{
  std::cout << line << ": "
            << errorStr << "\n";

  if(PickingManager)
    {
    PickingManager->Print(std::cout);
    }
}

//------------------------------------------------------------------------------
bool PickingManagerTest::VTKVerify(bool test,
                                   const char* errorStr,
                                   int line = -1)
{
  if (!test)
    {
    this->PrintErrorMessage(line, errorStr);
    }

  return test;
}

//------------------------------------------------------------------------------
bool PickingManagerTest::CheckState(int numberOfPickers,
                                    vtkPicker* picker,
                                    int numberOfObjectsLinked)
{
  return (this->PickingManager->GetNumberOfPickers() == numberOfPickers &&
          this->PickingManager->GetNumberOfObjectsLinked(picker) ==
            numberOfObjectsLinked);
}
<commit_msg>Fix TestPickingManager memory leaks and inverted test<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    TestPickingManager.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

/*==============================================================================

  Library: MSVTK

  Copyright (c) Kitware Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0.txt

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

==============================================================================*/

// .NAME Test of PickingManager.
// .SECTION Description
// Tests PickingManager internal data structure.

// VTK includes
#include "vtkNew.h"
#include "vtkObjectFactory.h"
#include "vtkPicker.h"
#include "vtkPickingManager.h"
#include "vtkSmartPointer.h"

#define VTK_VERIFY(test, errorStr) this->VTKVerify((test), (errorStr), __LINE__)

class PickingManagerTest
{
public:
  bool TestProperties();
  bool TestAddPickers();
  bool TestRemovePickers();
  bool TestRemoveObjects();

  bool VTKVerify(bool test, const char* errorStr, int line);
  void PrintErrorMessage(int line, const char* errorStr);

protected:
  std::pair<vtkSmartPointer<vtkPicker>, vtkSmartPointer<vtkObject> >
  AddPickerObject(int pickerType, int objectType);

  bool AddPicker(int pickerType, int objectType,
                 int numberOfPickers, int numberOfObjectsLinked);

  bool AddPickerTwice(int pickerType0, int objectType0,
                      int pickerType1, int objectType1,
                      bool samePicker, int numberOfPickers,
                      int numberOfObjectsLinked0, int numberOfObjectsLinked1);

  bool RemovePicker(int pickerType, int numberOfPickers);
  bool RemoveOneOfPickers(int pickerType0, int objectType0,
                          int pickerType1, int objectType1,
                          bool samePicker, int numberOfPickers,
                          int numberOfObjectsLinked0,
                          int numberOfObjectsLinked1);

  bool RemoveObject(int pickerType, int objectType,
                    int numberOfPickers, int numberOfObjectsLinked1);

  bool CheckState(int numberOfPickers,
                  vtkPicker* picker = 0,
                  int NumberOfObjectsLinked = 0);

private:
  vtkSmartPointer<vtkPickingManager> PickingManager;
};

//------------------------------------------------------------------------------
int TestPickingManager(int, char*[])
{
  PickingManagerTest pickingManagerTest;

  bool res = true;

  res = res && pickingManagerTest.TestProperties();
  res = res && pickingManagerTest.TestAddPickers();
  res = res && pickingManagerTest.TestRemovePickers();
  res = res && pickingManagerTest.TestRemoveObjects();

  return res ? EXIT_SUCCESS : EXIT_FAILURE;
}

//------------------------------------------------------------------------------
bool PickingManagerTest::TestProperties()
{
  this->PickingManager = vtkSmartPointer<vtkPickingManager>::New();

  bool res = true;

  // Default
  res = VTK_VERIFY(this->PickingManager->GetEnabled() == 0,
                   "Error manager not disabled by default") && res;
  res = VTK_VERIFY(this->PickingManager->GetOptimizeOnInteractorEvents() == 1,
                   "Error optimizationOnInteractor not enabled by default:")
        && res;
  res = VTK_VERIFY(this->PickingManager->GetInteractor() == 0,
                   "Error interactor not null by default:") && res;
  res = VTK_VERIFY(this->PickingManager->GetNumberOfPickers() == 0,
                   "Error numberOfPickers not nul by default:") && res;
  res = VTK_VERIFY(this->PickingManager->GetNumberOfObjectsLinked(0) == 0,
                   "Error NumberOfObjectsLinked not nul with null picker:")
        && res;

  // Settings properties
  this->PickingManager->EnabledOn();
  res = VTK_VERIFY(this->PickingManager->GetEnabled() == 1,
                   "Error manager not does not enable:") && res;
  this->PickingManager->SetOptimizeOnInteractorEvents(false);
  res = VTK_VERIFY(this->PickingManager->GetOptimizeOnInteractorEvents() == 0,
    "Error OptimizeOnInteractorEvents does not get disabled:")
    && res;

  return res;
}

//------------------------------------------------------------------------------
bool PickingManagerTest::TestAddPickers()
{
  bool res = true;

  // Simple Add
  res = VTK_VERIFY(this->AddPicker(0, 0, 0, 0),
                   "Error adding a null picker:") && res;
  res = VTK_VERIFY(this->AddPicker(0, 1, 0, 0),
                   "Error adding a null picker with an object:") && res;
  res = VTK_VERIFY(this->AddPicker(1, 0, 1, 1),
                   "Error adding a picker with a null object:") && res;
  res = VTK_VERIFY(this->AddPicker(1, 1, 1, 1),
                   "Error adding a picker with an object:") && res;

  // Twice Add
  res = VTK_VERIFY(this->AddPickerTwice(1, 0, 1, 0, false, 2, 1, 1),
                   "Error adding two pickers with null objects:") && res;
  res = VTK_VERIFY(this->AddPickerTwice(1, 0, 1, 0, true, 1, 2, 2),
                   "Error adding same picker with null objects:") && res;
  res = VTK_VERIFY(this->AddPickerTwice(1, 1, 1, 1, false, 2, 1, 1),
                   "Error adding pickers with valid objects:") && res;
  res = VTK_VERIFY(this->AddPickerTwice(1, 1, 1, 1, true, 1, 2, 2),
                  "Error adding same picker with valid objects:") && res;

  // Particular case: same picker with same valid object
  this->PickingManager = vtkSmartPointer<vtkPickingManager>::New();
  vtkNew<vtkPicker> picker;
  vtkNew<vtkObject> object;
  this->PickingManager->AddPicker(picker.GetPointer(), object.GetPointer());
  this->PickingManager->AddPicker(picker.GetPointer(), object.GetPointer());

  res = VTK_VERIFY(this->CheckState(1, picker.GetPointer(), 1),
                  "Error adding same picker with same object:") && res;

  return res;
}

//------------------------------------------------------------------------------
bool PickingManagerTest::TestRemovePickers()
{
  bool res = true;

  // Remove Picker following a simple add
  res = VTK_VERIFY(this->RemovePicker(0, 0),
                   "Error removing null picker:") && res;
  res = VTK_VERIFY(this->RemovePicker(1, 0),
                   "Error removing existing picker:") && res;

  // Remove Picker following a multiples add
  res = VTK_VERIFY(this->RemoveOneOfPickers(1, 0, 1, 0, false, 1, 0, 1),
                   "Error removing a picker with null object:") && res;
  res = VTK_VERIFY(this->RemoveOneOfPickers(1, 0, 1, 0, true, 1, 1, 1),
                   "Error removing a picker with null objects:") && res;
  res = VTK_VERIFY(this->RemoveOneOfPickers(1, 1, 1, 1, true, 1, 1, 1),
                   "Error adding pickers with valid objects:") && res;

  // Particular case same picker with same valid object
  this->PickingManager = vtkSmartPointer<vtkPickingManager>::New();
  vtkNew<vtkPicker> picker;
  vtkNew<vtkObject> object;
  this->PickingManager->AddPicker(picker.GetPointer(), object.GetPointer());
  this->PickingManager->AddPicker(picker.GetPointer(), object.GetPointer());
  this->PickingManager->RemovePicker(picker.GetPointer(), object.GetPointer());

  res = VTK_VERIFY(this->CheckState(0, picker.GetPointer(), 0),
                  "Error removing a picker with same object:") && res;

  return res;
}

//------------------------------------------------------------------------------
bool PickingManagerTest::TestRemoveObjects()
{
  bool res = true;

  // Remove Object following a simple add
  res = VTK_VERIFY(this->RemoveObject(0, 0, 0, 0),
                   "Error removing null object without picker:") && res;
  res = VTK_VERIFY(this->RemoveObject(1, 0, 0, 0),
                   "Error removing null object with a picker:") && res;
  res = VTK_VERIFY(this->RemoveObject(0, 1, 0, 0),
                   "Error removing object without picker:") && res;
  res = VTK_VERIFY(this->RemoveObject(1, 1, 0, 0),
                   "Error removing object with a picker:") && res;

  // Particular cases same picker with same valid object
  this->PickingManager = vtkSmartPointer<vtkPickingManager>::New();
  vtkNew<vtkPicker> picker;
  vtkNew<vtkObject> object;
  this->PickingManager->AddPicker(picker.GetPointer(), object.GetPointer());
  this->PickingManager->AddPicker(picker.GetPointer(), object.GetPointer());
  this->PickingManager->RemoveObject(object.GetPointer());

  res = VTK_VERIFY(this->CheckState(0, picker.GetPointer(), 0),
                  "Error removing an object with same picker:") && res;

  this->PickingManager = vtkSmartPointer<vtkPickingManager>::New();
  vtkNew<vtkObject> object2;
  this->PickingManager->AddPicker(picker.GetPointer(), object.GetPointer());
  this->PickingManager->AddPicker(picker.GetPointer(), object2.GetPointer());
  this->PickingManager->RemoveObject(object.GetPointer());

  res = VTK_VERIFY(this->CheckState(1, picker.GetPointer(), 1),
                  "Error removing one of the objects with same picker:") && res;

  this->PickingManager = vtkSmartPointer<vtkPickingManager>::New();
  vtkNew<vtkPicker> picker2;
  this->PickingManager->AddPicker(picker.GetPointer(), object.GetPointer());
  this->PickingManager->AddPicker(picker2.GetPointer(), object.GetPointer());
  this->PickingManager->RemoveObject(object.GetPointer());

  res = VTK_VERIFY(this->CheckState(0, picker.GetPointer(), 0),
                  "Error removing object with different pickers:") && res;

  return res;
}

//------------------------------------------------------------------------------
std::pair<vtkSmartPointer<vtkPicker>, vtkSmartPointer<vtkObject> > PickingManagerTest::
AddPickerObject(int pickerType, int objectType)
{
  vtkSmartPointer<vtkPicker> picker = (pickerType == 0) ? 0 : vtkSmartPointer<vtkPicker>::New();
  vtkSmartPointer<vtkObject> object = (objectType == 0) ? 0 : vtkSmartPointer<vtkObject>::New();

  this->PickingManager->AddPicker(picker, object);

  return std::pair<vtkSmartPointer<vtkPicker>, vtkSmartPointer<vtkObject> >(picker, object);
}

//------------------------------------------------------------------------------
bool PickingManagerTest::AddPicker(int pickerType, int objectType,
                                   int numberOfPickers,
                                   int numberOfObjectsLinked)
{
  this->PickingManager = vtkSmartPointer<vtkPickingManager>::New();

  vtkSmartPointer<vtkPicker> picker =
    this->AddPickerObject(pickerType, objectType).first;

  return this->CheckState(numberOfPickers,
                          picker.GetPointer(),
                          numberOfObjectsLinked);
}

//------------------------------------------------------------------------------
bool PickingManagerTest::
AddPickerTwice(int pickerType0, int objectType0,
               int pickerType1, int objectType1,
               bool samePicker, int numberOfPickers,
               int numberOfObjectsLinked0, int numberOfObjectsLinked1)
{
  this->PickingManager = vtkSmartPointer<vtkPickingManager>::New();

  vtkSmartPointer<vtkPicker> picker0 =
    this->AddPickerObject(pickerType0, objectType0).first;

  vtkSmartPointer<vtkPicker> picker1 = (samePicker) ? picker0 :
    this->AddPickerObject(pickerType1, objectType1).first;

  if (samePicker)
    {
    this->PickingManager->AddPicker(picker1.GetPointer());
    }

  return (this->CheckState(numberOfPickers,
                           picker0.GetPointer(), numberOfObjectsLinked0) &&
          this->CheckState(numberOfPickers,
                           picker1.GetPointer(), numberOfObjectsLinked1));
}

//------------------------------------------------------------------------------
bool PickingManagerTest::RemovePicker(int pickerType, int numberOfPickers)
{
  this->PickingManager = vtkSmartPointer<vtkPickingManager>::New();
  vtkSmartPointer<vtkPicker> picker = this->AddPickerObject(pickerType, 0).first;

  this->PickingManager->RemovePicker(picker.GetPointer());

  return this->CheckState(numberOfPickers, 0, 0);
}

//------------------------------------------------------------------------------
bool PickingManagerTest::
RemoveOneOfPickers(int pickerType0, int objectType0,
                   int pickerType1, int objectType1,
                   bool samePicker, int numberOfPickers,
                   int numberOfObjectsLinked0, int numberOfObjectsLinked1)
{
  this->PickingManager = vtkSmartPointer<vtkPickingManager>::New();

  vtkSmartPointer<vtkPicker> picker0 =
    this->AddPickerObject(pickerType0, objectType0).first;

  vtkSmartPointer<vtkPicker> picker1 = (samePicker) ? picker0 :
    this->AddPickerObject(pickerType1, objectType1).first;

  if (samePicker)
    {
    this->PickingManager->AddPicker(picker1.GetPointer());
    }

  this->PickingManager->RemovePicker(picker0.GetPointer());

  return (this->CheckState(numberOfPickers,
                           picker0.GetPointer(), numberOfObjectsLinked0) &&
          this->CheckState(numberOfPickers,
                           picker1.GetPointer(), numberOfObjectsLinked1));
}

//------------------------------------------------------------------------------
bool PickingManagerTest::
RemoveObject(int pickerType, int objectType,
             int numberOfPickers, int numberOfObjectsLinked1)
{
  this->PickingManager = vtkSmartPointer<vtkPickingManager>::New();

  std::pair<vtkSmartPointer<vtkPicker>, vtkSmartPointer<vtkObject> >
    pickerObject = this->AddPickerObject(pickerType, objectType);

  this->PickingManager->RemoveObject(pickerObject.second);

  return this->CheckState(numberOfPickers,
                          pickerObject.first,
                          numberOfObjectsLinked1);
}

//------------------------------------------------------------------------------
void PickingManagerTest::PrintErrorMessage(int line, const char* errorStr)
{
  std::cout << line << ": "
            << errorStr << "\n";

  if(PickingManager)
    {
    PickingManager->Print(std::cout);
    }
}

//------------------------------------------------------------------------------
bool PickingManagerTest::VTKVerify(bool test,
                                   const char* errorStr,
                                   int line = -1)
{
  if (!test)
    {
    this->PrintErrorMessage(line, errorStr);
    }

  return test;
}

//------------------------------------------------------------------------------
bool PickingManagerTest::CheckState(int numberOfPickers,
                                    vtkPicker* picker,
                                    int numberOfObjectsLinked)
{
  return (this->PickingManager->GetNumberOfPickers() == numberOfPickers &&
          this->PickingManager->GetNumberOfObjectsLinked(picker) ==
            numberOfObjectsLinked);
}
<|endoftext|>


<commit_before>/************************************************************************
    filename:   CEGuiOpenGLBaseApplication.cpp
    created:    24/9/2004
    author:     Paul D Turner
*************************************************************************/
/*************************************************************************
    Crazy Eddie's GUI System (http://www.cegui.org.uk)
    Copyright (C)2004 - 2005 Paul D Turner (paul@cegui.org.uk)

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*************************************************************************/
#ifdef HAVE_CONFIG_H
#   include "config.h"
#endif

// this controls conditional compile of file for MSVC
#include "CEGUIConfig.h"
#ifdef CEGUI_SAMPLES_USE_OPENGL

#include "CEGuiOpenGLBaseApplication.h"
#include "renderers/OpenGLGUIRenderer/openglrenderer.h"
#include "CEGuiSample.h"
#include "CEGUI.h"

#include <GL/glut.h>
#include <GL/gl.h>
#include <GL/glu.h>

#include <stdexcept>
#include <stdlib.h>

#ifdef _MSC_VER
# if defined(DEBUG) || defined (_DEBUG)
#   pragma comment (lib, "OpenGLGUIRenderer_d.lib")
# else
#   pragma comment (lib, "OpenGLGUIRenderer.lib")
# endif
#endif

/*************************************************************************
    Static Data
*************************************************************************/
bool CEGuiOpenGLBaseApplication::d_quitFlag = false;

/*************************************************************************
    Constructor.
*************************************************************************/
CEGuiOpenGLBaseApplication::CEGuiOpenGLBaseApplication()
{
    // fake args for glutInit
    int argc = 1;
    char* argv = "SampleApp";

    // Do GLUT init
    glutInit(&argc, &argv);
    glutInitDisplayMode(GLUT_DEPTH|GLUT_DOUBLE|GLUT_RGBA);
    glutInitWindowSize(800, 600);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("Crazy Eddie's GUI Mk-2 - Sample Application");
    glutSetCursor(GLUT_CURSOR_NONE);

    glutDisplayFunc(&CEGuiOpenGLBaseApplication::drawFrame);
    glutReshapeFunc(&CEGuiOpenGLBaseApplication::reshape);
    glutMotionFunc(&CEGuiOpenGLBaseApplication::mouseMotion);
    glutPassiveMotionFunc(&CEGuiOpenGLBaseApplication::mouseMotion);
    glutMouseFunc(&CEGuiOpenGLBaseApplication::mouseButton);
    glutKeyboardFunc(&CEGuiOpenGLBaseApplication::keyChar);
    glutSpecialFunc(&CEGuiOpenGLBaseApplication::keySpecial);

    // Set the clear color
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    d_renderer = new CEGUI::OpenGLRenderer(1024);
    new CEGUI::System(d_renderer);
}

/*************************************************************************
    Destructor.
*************************************************************************/
CEGuiOpenGLBaseApplication::~CEGuiOpenGLBaseApplication()
{
    delete CEGUI::System::getSingletonPtr();
    delete d_renderer;
}

/*************************************************************************
    Start the base application
*************************************************************************/
bool CEGuiOpenGLBaseApplication::execute(CEGuiSample* sampleApp)
{
    sampleApp->initialiseSample();

    glutMainLoop();

    return true;
}

/*************************************************************************
    Performs any required cleanup of the base application system.
*************************************************************************/
void CEGuiOpenGLBaseApplication::cleanup()
{
    // nothing to do here.
}

/*************************************************************************
    Set whether the app should quit
*************************************************************************/
void CEGuiOpenGLBaseApplication::setQuitting(bool quit)
{
    d_quitFlag = quit;
}

/*************************************************************************
    Is this app quitting
*************************************************************************/
bool CEGuiOpenGLBaseApplication::isQuitting() const
{
    return d_quitFlag;
}

/*************************************************************************
    Does whatever is required in one single frame
*************************************************************************/
void CEGuiOpenGLBaseApplication::drawFrame(void)
{
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0.0, 0.0, 12, 0.0, 0.0, -100, 0.0, 1.0, 0.0);

    CEGUI::System::getSingleton().renderGUI();

    glFlush();
    glutPostRedisplay();
    glutSwapBuffers();

    // here we check the 'quitting' state and cleanup as required.
    // this is probably not the best way to do this, but since we're
    // using glut, and glutMainLoop can never return, we need some
    // way of checking when to exit.  And this is it...
    if (d_quitFlag)
    {
        // cleanup cegui system
        CEGUI::Renderer* renderer = CEGUI::System::getSingleton().getRenderer();
        delete CEGUI::System::getSingletonPtr();
        delete renderer;

        // exit
        exit(0);
    }
}

void CEGuiOpenGLBaseApplication::reshape(int w, int h)
{
    glViewport (0, 0, (GLsizei) w, (GLsizei) h);
    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
    gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 50.0);
    glMatrixMode(GL_MODELVIEW);
}

void CEGuiOpenGLBaseApplication::mouseMotion(int x, int y)
{
    CEGUI::System::getSingleton().injectMousePosition(x, y);
}

void CEGuiOpenGLBaseApplication::mouseButton(int button, int state, int x, int y)
{
    switch(button)
    {
    case  GLUT_LEFT_BUTTON:
        if (state == GLUT_UP)
        {
            CEGUI::System::getSingleton().injectMouseButtonUp(CEGUI::LeftButton);
        }
        else
        {
            CEGUI::System::getSingleton().injectMouseButtonDown(CEGUI::LeftButton);

        }
        break;

    case GLUT_RIGHT_BUTTON:
        if (state == GLUT_UP)
        {
            CEGUI::System::getSingleton().injectMouseButtonUp(CEGUI::RightButton);
        }
        else
        {
            CEGUI::System::getSingleton().injectMouseButtonDown(CEGUI::RightButton);
        }
        break;

    case GLUT_MIDDLE_BUTTON:
        if (state == GLUT_UP)
        {
            CEGUI::System::getSingleton().injectMouseButtonDown(CEGUI::MiddleButton);
        }
        else
        {
            CEGUI::System::getSingleton().injectMouseButtonDown(CEGUI::MiddleButton);
        }
        break;
    }

}

void CEGuiOpenGLBaseApplication::keyChar(unsigned char key, int x, int y)
{
    // extract some keys may be handled via key code and generate those too
    switch (key)
    {
    case 0x08:  // backspace
        CEGUI::System::getSingleton().injectKeyDown(CEGUI::Key::Backspace);
        break;
    case 0x7F:  // delete
        CEGUI::System::getSingleton().injectKeyDown(CEGUI::Key::Delete);
        break;
    case 0x1B:  // Escape
        CEGUI::System::getSingleton().injectKeyDown(CEGUI::Key::Escape);
        break;
    case 0x0D:  // CR (Return)
        CEGUI::System::getSingleton().injectKeyDown(CEGUI::Key::Return);
        break;
    }

    // always inject Character even if we have done key-down injection
    CEGUI::System::getSingleton().injectChar(static_cast<CEGUI::utf32>(key));
}

void CEGuiOpenGLBaseApplication::keySpecial(int key, int x, int y)
{
    switch (key)
    {
    case GLUT_KEY_LEFT:
        CEGUI::System::getSingleton().injectKeyDown(CEGUI::Key::ArrowLeft);
        break;
    case GLUT_KEY_RIGHT:
        CEGUI::System::getSingleton().injectKeyDown(CEGUI::Key::ArrowRight);
        break;
    case GLUT_KEY_UP:
        CEGUI::System::getSingleton().injectKeyDown(CEGUI::Key::ArrowUp);
        break;
    case GLUT_KEY_DOWN:
        CEGUI::System::getSingleton().injectKeyDown(CEGUI::Key::ArrowDown);
        break;
    case GLUT_KEY_HOME:
        CEGUI::System::getSingleton().injectKeyDown(CEGUI::Key::Home);
        break;
    case GLUT_KEY_END:
        CEGUI::System::getSingleton().injectKeyDown(CEGUI::Key::End);
        break;
    case GLUT_KEY_PAGE_UP:
        CEGUI::System::getSingleton().injectKeyDown(CEGUI::Key::PageUp);
        break;
    case GLUT_KEY_PAGE_DOWN:
        CEGUI::System::getSingleton().injectKeyDown(CEGUI::Key::PageDown);
        break;
    }
}

#endif

<commit_msg>Better 'special' key handling for OpenGL base app. Escape key now quits OpenGL base app.<commit_after>/************************************************************************
    filename:   CEGuiOpenGLBaseApplication.cpp
    created:    24/9/2004
    author:     Paul D Turner
*************************************************************************/
/*************************************************************************
    Crazy Eddie's GUI System (http://www.cegui.org.uk)
    Copyright (C)2004 - 2005 Paul D Turner (paul@cegui.org.uk)

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*************************************************************************/
#ifdef HAVE_CONFIG_H
#   include "config.h"
#endif

// this controls conditional compile of file for MSVC
#include "CEGUIConfig.h"
#ifdef CEGUI_SAMPLES_USE_OPENGL

#include "CEGuiOpenGLBaseApplication.h"
#include "renderers/OpenGLGUIRenderer/openglrenderer.h"
#include "CEGuiSample.h"
#include "CEGUI.h"

#include <GL/glut.h>
#include <GL/gl.h>
#include <GL/glu.h>

#include <stdexcept>
#include <stdlib.h>

#ifdef _MSC_VER
# if defined(DEBUG) || defined (_DEBUG)
#   pragma comment (lib, "OpenGLGUIRenderer_d.lib")
# else
#   pragma comment (lib, "OpenGLGUIRenderer.lib")
# endif
#endif

/*************************************************************************
    Simple key-map used to translate glut special keys to CEGUI keys.
    See: CEGuiOpenGLBaseApplication::keySpecial method.
*************************************************************************/
struct GlutKeyMapping
{
    int glutKey;
    CEGUI::uint  ceguiKey;
};

GlutKeyMapping specialKeyMap[] =
{
    {GLUT_KEY_F1, CEGUI::Key::F1},
    {GLUT_KEY_F2, CEGUI::Key::F2},
    {GLUT_KEY_F3, CEGUI::Key::F3},
    {GLUT_KEY_F4, CEGUI::Key::F4},
    {GLUT_KEY_F5, CEGUI::Key::F5},
    {GLUT_KEY_F6, CEGUI::Key::F6},
    {GLUT_KEY_F7, CEGUI::Key::F7},
    {GLUT_KEY_F8, CEGUI::Key::F8},
    {GLUT_KEY_F9, CEGUI::Key::F9},
    {GLUT_KEY_F10, CEGUI::Key::F10},
    {GLUT_KEY_F11, CEGUI::Key::F11},
    {GLUT_KEY_F12, CEGUI::Key::F12},
    {GLUT_KEY_LEFT, CEGUI::Key::ArrowLeft},
    {GLUT_KEY_UP, CEGUI::Key::ArrowUp},
    {GLUT_KEY_RIGHT, CEGUI::Key::ArrowRight},
    {GLUT_KEY_DOWN, CEGUI::Key::ArrowDown},
    {GLUT_KEY_PAGE_UP, CEGUI::Key::PageUp},
    {GLUT_KEY_PAGE_DOWN, CEGUI::Key::PageDown},
    {GLUT_KEY_HOME, CEGUI::Key::Home},
    {GLUT_KEY_END, CEGUI::Key::End},
    {GLUT_KEY_INSERT, CEGUI::Key::Insert},
    {-1, 0}
};

/*************************************************************************
    Static Data
*************************************************************************/
bool CEGuiOpenGLBaseApplication::d_quitFlag = false;

/*************************************************************************
    Constructor.
*************************************************************************/
CEGuiOpenGLBaseApplication::CEGuiOpenGLBaseApplication()
{
    // fake args for glutInit
    int argc = 1;
    char* argv = "SampleApp";

    // Do GLUT init
    glutInit(&argc, &argv);
    glutInitDisplayMode(GLUT_DEPTH|GLUT_DOUBLE|GLUT_RGBA);
    glutInitWindowSize(800, 600);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("Crazy Eddie's GUI Mk-2 - Sample Application");
    glutSetCursor(GLUT_CURSOR_NONE);

    glutDisplayFunc(&CEGuiOpenGLBaseApplication::drawFrame);
    glutReshapeFunc(&CEGuiOpenGLBaseApplication::reshape);
    glutMotionFunc(&CEGuiOpenGLBaseApplication::mouseMotion);
    glutPassiveMotionFunc(&CEGuiOpenGLBaseApplication::mouseMotion);
    glutMouseFunc(&CEGuiOpenGLBaseApplication::mouseButton);
    glutKeyboardFunc(&CEGuiOpenGLBaseApplication::keyChar);
    glutSpecialFunc(&CEGuiOpenGLBaseApplication::keySpecial);

    // Set the clear color
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    d_renderer = new CEGUI::OpenGLRenderer(1024);
    new CEGUI::System(d_renderer);
}

/*************************************************************************
    Destructor.
*************************************************************************/
CEGuiOpenGLBaseApplication::~CEGuiOpenGLBaseApplication()
{
    delete CEGUI::System::getSingletonPtr();
    delete d_renderer;
}

/*************************************************************************
    Start the base application
*************************************************************************/
bool CEGuiOpenGLBaseApplication::execute(CEGuiSample* sampleApp)
{
    sampleApp->initialiseSample();

    glutMainLoop();

    return true;
}

/*************************************************************************
    Performs any required cleanup of the base application system.
*************************************************************************/
void CEGuiOpenGLBaseApplication::cleanup()
{
    // nothing to do here.
}

/*************************************************************************
    Set whether the app should quit
*************************************************************************/
void CEGuiOpenGLBaseApplication::setQuitting(bool quit)
{
    d_quitFlag = quit;
}

/*************************************************************************
    Is this app quitting
*************************************************************************/
bool CEGuiOpenGLBaseApplication::isQuitting() const
{
    return d_quitFlag;
}

/*************************************************************************
    Does whatever is required in one single frame
*************************************************************************/
void CEGuiOpenGLBaseApplication::drawFrame(void)
{
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0.0, 0.0, 12, 0.0, 0.0, -100, 0.0, 1.0, 0.0);

    CEGUI::System::getSingleton().renderGUI();

    glFlush();
    glutPostRedisplay();
    glutSwapBuffers();

    // here we check the 'quitting' state and cleanup as required.
    // this is probably not the best way to do this, but since we're
    // using glut, and glutMainLoop can never return, we need some
    // way of checking when to exit.  And this is it...
    if (d_quitFlag)
    {
        // cleanup cegui system
        CEGUI::Renderer* renderer = CEGUI::System::getSingleton().getRenderer();
        delete CEGUI::System::getSingletonPtr();
        delete renderer;

        // exit
        exit(0);
    }
}

void CEGuiOpenGLBaseApplication::reshape(int w, int h)
{
    glViewport (0, 0, (GLsizei) w, (GLsizei) h);
    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
    gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 50.0);
    glMatrixMode(GL_MODELVIEW);
}

void CEGuiOpenGLBaseApplication::mouseMotion(int x, int y)
{
    CEGUI::System::getSingleton().injectMousePosition(x, y);
}

void CEGuiOpenGLBaseApplication::mouseButton(int button, int state, int x, int y)
{
    switch(button)
    {
    case  GLUT_LEFT_BUTTON:
        if (state == GLUT_UP)
        {
            CEGUI::System::getSingleton().injectMouseButtonUp(CEGUI::LeftButton);
        }
        else
        {
            CEGUI::System::getSingleton().injectMouseButtonDown(CEGUI::LeftButton);

        }
        break;

    case GLUT_RIGHT_BUTTON:
        if (state == GLUT_UP)
        {
            CEGUI::System::getSingleton().injectMouseButtonUp(CEGUI::RightButton);
        }
        else
        {
            CEGUI::System::getSingleton().injectMouseButtonDown(CEGUI::RightButton);
        }
        break;

    case GLUT_MIDDLE_BUTTON:
        if (state == GLUT_UP)
        {
            CEGUI::System::getSingleton().injectMouseButtonDown(CEGUI::MiddleButton);
        }
        else
        {
            CEGUI::System::getSingleton().injectMouseButtonDown(CEGUI::MiddleButton);
        }
        break;
    }

}

void CEGuiOpenGLBaseApplication::keyChar(unsigned char key, int x, int y)
{
    // extract some keys may be handled via key code and generate those too
    switch (key)
    {
    case 0x08:  // backspace
        CEGUI::System::getSingleton().injectKeyDown(CEGUI::Key::Backspace);
        break;
    case 0x7F:  // delete
        CEGUI::System::getSingleton().injectKeyDown(CEGUI::Key::Delete);
        break;
    case 0x1B:  // Escape
        d_quitFlag = true;
        break;
    case 0x0D:  // CR (Return)
        CEGUI::System::getSingleton().injectKeyDown(CEGUI::Key::Return);
        break;
    }

    // always inject Character even if we have done key-down injection
    CEGUI::System::getSingleton().injectChar(static_cast<CEGUI::utf32>(key));
}

void CEGuiOpenGLBaseApplication::keySpecial(int key, int x, int y)
{
    GlutKeyMapping* mapping = specialKeyMap;

    while (mapping->glutKey != -1)
    {
        if (mapping->glutKey == key)
        {
            CEGUI::System::getSingleton().injectKeyDown(mapping->ceguiKey);
            return;
        }

        ++mapping;
    }
}

#endif

<|endoftext|>