text: // Copyright 2020 Phyronnaz
  
  #include "VoxelTools/VoxelMathLibrary.h"
  #include "VoxelUtilities/VoxelBaseUtilities.h"
  
  FVector UVoxelMathLibrary::GetUnitVectorFromRandom(FVector2D Random)
  {
  	// From Raytracing Gems, Chapter 16
  
  	// Compute radius r (branchless).
  	Random = 2 * Random - 1;
  	const float d = 1 - (FMath::Abs(Random.X) + FMath::Abs(Random.Y));
  	const float Radius = 1 - FMath::Abs(d);
  
  	// Compute phi in the first quadrant (branchless, except for the division-by-zero test),
  	// using sign(random) to map the result to the correct quadrant below
  	const float Phi = (Radius == 0) ? 0 : (PI / 4) * ((FMath::Abs(Random.Y) - FMath::Abs(Random.X)) / Radius + 1);
  	const float f = Radius * FMath::Sqrt(2 - Radius * Radius);
  
  	FVector Result;
  	Result.X = f * FMath::Sign(Random.X) * FMath::Cos(Phi);
  	Result.Y = f * FMath::Sign(Random.Y) * FMath::Sin(Phi);
  	Result.Z = FMath::Sign(d) * (1 - Radius * Radius);
  
  	ensure(Result.IsUnit());
  	return Result;
  }
  
  ///////////////////////////////////////////////////////////////////////////////
  ///////////////////////////////////////////////////////////////////////////////
  ///////////////////////////////////////////////////////////////////////////////
  
  FVoxelHaltonStream UVoxelMathLibrary::MakeHaltonStream(int32 InitialSeed)
  {
  	return { InitialSeed, uint32(FMath::Abs(InitialSeed)) };
  }
  
  void UVoxelMathLibrary::ResetHaltonStream(const FVoxelHaltonStream& Stream)
  {
  	Stream.Seed = Stream.InitialSeed;
  }
  
  float UVoxelMathLibrary::GetHalton1D(const FVoxelHaltonStream& Stream)
  {
  	const float Value = FVoxelUtilities::Halton<2>(Stream.Seed);
  	Stream.Seed++;
  	return Value;
  }
  
  FVector2D UVoxelMathLibrary::GetHalton2D(const FVoxelHaltonStream& Stream)
  {
  	FVector2D Value;
  	Value.X = FVoxelUtilities::Halton<2>(Stream.Seed);
  	Value.Y = FVoxelUtilities::Halton<3>(Stream.Seed);
  	Stream.Seed++;
  	return Value;
  }
  
  FVector UVoxelMathLibrary::GetHalton3D(const FVoxelHaltonStream& Stream)
  {
  	FVector Value;
  	Value.X = FVoxelUtilities::Halton<2>(Stream.Seed);
  	Value.Y = FVoxelUtilities::Halton<3>(Stream.Seed);
  	Value.Z = FVoxelUtilities::Halton<5>(Stream.Seed);
  	Stream.Seed++;
  	return Value;
  }