Commit 27b0922c authored by Jan Kremer's avatar Jan Kremer

Major refactoring. Putting data loading and management in own class.

parent 889a93e3
No preview for this file type
No preview for this file type
This diff is collapsed.
// Fill out your copyright notice in the Description page of Project Settings.
#include "DataComponent.h"
#include "Runtime/Core/Public/Misc/Paths.h"
#include "Runtime/Core/Public/HAL/FileManagerGeneric.h"
#include "HDF5Library.h"
#include "Plot3D.h"
#include "PawnBase.h"
#include "Runtime/Engine/Classes/Engine/World.h"
#include "Runtime/Engine/Classes/Kismet/KismetMathLibrary.h"
#include "Runtime/Core/Public/Async/ParallelFor.h"
UDataComponent::UDataComponent()
{
D3_BrushAlpha = 0;
D3_SpriteAlpha = 255;
D3_BrushOverridesColor = false;
D3_BrushColor = FColor(0, 0, 0, 0);
D3_UseTransparency = true;
D3_SpriteSizeFactor = 50;
}
// Called when the game starts
void UDataComponent::BeginPlay()
{
Super::BeginPlay();
if (!TransferFunction)
{
UE_LOG(LogTemp, Error, TEXT("No transfer function set!"));
FGenericPlatformMisc::RequestExit(false);
}
// Find Files
FString Directory = FPaths::ProjectDir();
Directory += FString("/Resources/");
FString Path = Directory + "*.h5*";
FFileManagerGeneric::Get().FindFiles(FileNames, *Path, true, false);
if (!FileNameToLoadOnStart.IsEmpty())
{
LoadFile(FileNameToLoadOnStart);
LoadStep(GroupNames[0]);
}
}
void UDataComponent::LoadFile(FString FileName)
{
// Load File
LoadedFile = UHDF5Library::LoadFile(FileName, GroupNames);
}
void UDataComponent::LoadStep(FString GroupName)
{
UHDF5Library::LoadGroup(LoadedFile, GroupName, X, Y, Z, U, V, W);
// Prepare Data
Num = X.Num();
if (OverrideMaxPointCount > 0 && OverrideMaxPointCount < Num)
{
Num = OverrideMaxPointCount;
}
IsBrushed = TArray<bool>();
IsBrushed.Init(false, Num);
for (int32 i = 0; i < Num; i++)
{
Length.Emplace(FVector(U[i], V[i], W[i]).Size());
}
int32 MaxIndex, MinIndex;
UKismetMathLibrary::MaxOfFloatArray(Length, MaxIndex, MaxLength);
UKismetMathLibrary::MinOfFloatArray(Length, MinIndex, MinLength);
UKismetMathLibrary::MaxOfFloatArray(X, MaxIndex, MaxX);
UKismetMathLibrary::MinOfFloatArray(X, MinIndex, MinX);
UKismetMathLibrary::MaxOfFloatArray(Y, MaxIndex, MaxY);
UKismetMathLibrary::MinOfFloatArray(Y, MinIndex, MinY);
UKismetMathLibrary::MaxOfFloatArray(Z, MaxIndex, MaxZ);
UKismetMathLibrary::MinOfFloatArray(Z, MinIndex, MinZ);
UKismetMathLibrary::MaxOfFloatArray(U, MaxIndex, MaxU);
UKismetMathLibrary::MinOfFloatArray(U, MinIndex, MinU);
UKismetMathLibrary::MaxOfFloatArray(V, MaxIndex, MaxV);
UKismetMathLibrary::MinOfFloatArray(V, MinIndex, MinV);
UKismetMathLibrary::MaxOfFloatArray(W, MaxIndex, MaxW);
UKismetMathLibrary::MinOfFloatArray(W, MinIndex, MinW);
for (int32 i = 0; i < Num; i++)
{
FColor TempColor = CalculateColorOfPoint(i, MaxLength, MinLength);
PColor.Emplace(FVector(TempColor.R, TempColor.G, TempColor.B));
}
// Spawn Plot3D
FVector Location(-1610.0f, -341.0f, 100.0f);
FRotator Rotation(0.0f, 0.0f, 0.0f);
FActorSpawnParameters SpawnInfo;
APlot3D* Plot3D = GetWorld()->SpawnActor<APlot3D>(Location, Rotation, SpawnInfo);
Cast<APawnBase>(GetOwner())->Plot3D = Plot3D;
Plot3D->Init(this);
}
FColor UDataComponent::CalculateColorOfPoint(int32 Index, float Min, float Max)
{
float NormalizedValue = UKismetMathLibrary::NormalizeToRange(Length[Index], Min, Max);
FVector ColorVec = TransferFunction->GetVectorValue(NormalizedValue);
FColor Color = FColor((uint8)(ColorVec.X * 255), (uint8)(ColorVec.Y * 255), (uint8)(ColorVec.Z * 255));
return Color;
}
void UDataComponent::AddFilter_Planes(FVector NormalRight, FVector LocationRight, bool UseTwoPlanes, FVector NormalLeft, FVector LocationLeft, bool Add, bool Rebuild, bool Invert)
{
TArray<int32> Indexes = TArray<int32>();
Indexes.Init(-1, Num);
APlot3D* Plot3D = Cast<APawnBase>(GetOwner())->Plot3D;
ParallelFor(Num, [this, Invert, &Indexes, LocationRight, LocationLeft, NormalRight, NormalLeft, UseTwoPlanes, Add, Plot3D](int32 CurrIdx)
{
FVector WorldLoc = Plot3D->CalculateWorldLocOfPoint(CurrIdx);
FVector DifferenceRight = WorldLoc - LocationRight;
FVector DifferenceLeft = WorldLoc - LocationLeft;
float DotRight = UKismetMathLibrary::Dot_VectorVector(DifferenceRight, NormalRight);
float DotLeft = UKismetMathLibrary::Dot_VectorVector(DifferenceLeft, NormalLeft);
if (Invert)
{
if (DotRight >= 0.f && (DotLeft >= 0.f || !UseTwoPlanes))
{
Indexes[CurrIdx] = CurrIdx;
}
}
else
{
if (DotRight <= 0.f && (DotLeft <= 0.f || !UseTwoPlanes))
{
Indexes[CurrIdx] = CurrIdx;
}
}
});
BrushPoints(Indexes, Add, Rebuild);
}
void UDataComponent::AddFilter_ValueRange(EAxisType XType, float XMin, float XMax, EAxisType YType, float YMin, float YMax, bool Add, bool Rebuild, bool UseTwoValues)
{
TArray<float> * XArray = nullptr;
TArray<float> * YArray = nullptr;
TArray<int32> Indexes = TArray<int32>();
switch (XType)
{
case EAxisType::X:
XArray = &X;
break;
case EAxisType::Y:
XArray = &Y;
break;
case EAxisType::Z:
XArray = &Z;
break;
case EAxisType::U:
XArray = &U;
break;
case EAxisType::V:
XArray = &V;
break;
case EAxisType::W:
XArray = &W;
break;
case EAxisType::LengthUVW:
XArray = &Length;
break;
default:
break;
}
switch (YType)
{
case EAxisType::X:
YArray = &X;
break;
case EAxisType::Y:
YArray = &Y;
break;
case EAxisType::Z:
YArray = &Z;
break;
case EAxisType::U:
YArray = &U;
break;
case EAxisType::V:
YArray = &V;
break;
case EAxisType::W:
YArray = &W;
break;
case EAxisType::LengthUVW:
YArray = &Length;
break;
default:
break;
}
/*
Indexes.Init(-1, Points.Num());
ParallelFor(Points.Num(), [this, XArray, YArray, XMin, XMax, YMin, YMax, Add, &Indexes](int32 CurrIdx)
{
if ((*XArray)[CurrIdx] >= XMin && (*XArray)[CurrIdx] <= XMax && (*YArray)[CurrIdx] >= YMin && (*YArray)[CurrIdx] <= YMax)
{
Indexes[CurrIdx] = CurrIdx;
}
});*/
for (int i = 0; i < Num; ++i)
{
if ((*XArray)[i] >= XMin && (*XArray)[i] <= XMax && (!UseTwoValues || ((*YArray)[i] >= YMin && (*YArray)[i] <= YMax)))
{
Indexes.Emplace(i);
}
}
BrushPoints(Indexes, Add, Rebuild);
}
void UDataComponent::AddFilter_Box(FTransform Transform, FVector Extent, bool Add, bool Rebuild)
{
TArray<int32> Indexes = TArray<int32>();
/*for (int i = 0; i < Points.Num(); ++i)
{
FVector WorldLoc = CalculateWorldLocOfPoint(&Points[i]);
if (UKismetMathLibrary::IsPointInBoxWithTransform(WorldLoc, Transform, Extent))
{
Indexes.Emplace(i);
}
}*/
APlot3D* Plot3D = Cast<APawnBase>(GetOwner())->Plot3D;
Indexes.Init(-1, Num);
ParallelFor(Num, [this, Transform, Extent, Add, &Indexes, Plot3D](int32 CurrIdx)
{
FVector WorldLoc = Plot3D->CalculateWorldLocOfPoint(CurrIdx);
if (UKismetMathLibrary::IsPointInBoxWithTransform(WorldLoc, Transform, Extent))
{
Indexes[CurrIdx] = CurrIdx;
}
});
BrushPoints(Indexes, Add, Rebuild);
}
void UDataComponent::AddFilter_Sphere(FVector Location, float Radius, bool Add, bool Rebuild)
{
TArray<int32> Indexes = TArray<int32>();
/*for (int i = 0; i < Points.Num(); ++i)
{
FVector WorldLoc = CalculateWorldLocOfPoint(&Points[i]);
if ((Location - WorldLoc).Size() <= Radius)
{
Indexes.Emplace(i);
}
}*/
APlot3D* Plot3D = Cast<APawnBase>(GetOwner())->Plot3D;
Indexes.Init(-1, Num);
ParallelFor(Num, [this, Location, Radius, Add, &Indexes, Plot3D](int32 CurrIdx)
{
FVector WorldLoc = Plot3D->CalculateWorldLocOfPoint(CurrIdx);
if ((Location - WorldLoc).Size() <= Radius)
{
Indexes[CurrIdx] = CurrIdx;
}
});
BrushPoints(Indexes, Add, Rebuild);
}
void UDataComponent::BrushPoints(TArray<int32> BrushPoints, bool Add, bool Rebuild)
{
for (int i = 0; i < BrushPoints.Num(); ++i)
{
BrushPoint(BrushPoints[i], Add);
}
Cast<APawnBase>(GetOwner())->Plot3D->BrushPoints(BrushPoints, Rebuild);
// TODO For all 2D Plots
}
void UDataComponent::BrushPoint(int32 PointIndex, bool Add)
{
if (PointIndex == -1)
{
return;
}
IsBrushed[PointIndex] = Add;
}
// does not use the standard BrushPoints, for performance reasons
void UDataComponent::ResetPoints(bool Rebuild)
{
for (int i = 0; i < Num; ++i)
{
BrushPoint(i, false);
}
Cast<APawnBase>(GetOwner())->Plot3D->ResetPoints(Rebuild);
// TODO For all 2D Plots
}
// does not use the standard BrushPoints, for performance reasons
void UDataComponent::InvertPoints(bool Rebuild)
{
for (int i = 0; i < Num; ++i)
{
BrushPoint(i, !IsBrushed[i]);
}
/*ParallelFor(Points.Num(), [this](int32 CurrIdx)
{
BrushPoint(CurrIdx, Points[CurrIdx].IsEnabled());
});*/
/*ParallelFor(4, [this](int32 CurrIdx)
{
int32 Start = Points.Num() / 4 * CurrIdx;
int32 End = Points.Num() / 4 * (CurrIdx + 1);
for (int i = Start; i < End; ++i)
{
BrushPoint(i, Points[i].IsEnabled());
}
});*/
Cast<APawnBase>(GetOwner())->Plot3D->InvertPoints(Rebuild);
// TODO For all 2D Plots
}
\ No newline at end of file
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "H5Cpp.h"
#include "Runtime/Engine/Classes/Curves/CurveVector.h"
#include "MyObject.h"
#include "DataComponent.generated.h"
using namespace H5;
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class IMMERSIVEANALYTICS_API UDataComponent : public UActorComponent
{
GENERATED_BODY()
public:
UDataComponent();
UFUNCTION(BlueprintCallable, Category = HDF5)
void LoadFile(FString FileName);
UFUNCTION(BlueprintCallable, Category = HDF5)
void LoadStep(FString GroupName);
UPROPERTY(Category = Plot3D, EditAnywhere)
FString FileNameToLoadOnStart;
UPROPERTY(EditAnywhere, Category = Plot3D)
UCurveVector* TransferFunction;
UPROPERTY(Category = Plot3D, EditAnywhere)
int32 OverrideMaxPointCount;
UFUNCTION(BlueprintCallable)
void AddFilter_Planes(FVector Normal, FVector Location, bool UseTwoPlanes, FVector NormalLeft, FVector LocationLeft, bool Add, bool Rebuild, bool Invert);
UFUNCTION(BlueprintCallable)
void AddFilter_ValueRange(EAxisType XType, float XMin, float XMax, EAxisType YType, float YMin, float YMax, bool Add, bool Rebuild, bool UseTwoValues);
UFUNCTION(BlueprintCallable)
void AddFilter_Box(FTransform Transform, FVector Extent, bool Add, bool Rebuild);
UFUNCTION(BlueprintCallable)
void AddFilter_Sphere(FVector Location, float Radius, bool Add, bool Rebuild);
UFUNCTION(BlueprintCallable)
void BrushPoints(TArray<int32> PointIndexes, bool Add, bool Rebuild);
UFUNCTION(BlueprintCallable)
void BrushPoint(int32 PointIndex, bool Add);
UFUNCTION(BlueprintCallable)
void ResetPoints(bool Rebuild);
UFUNCTION(BlueprintCallable)
void InvertPoints(bool Rebuild);
// 3d settings
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Default)
UMaterialInterface* D3_MaterialNontransparent;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Default)
UMaterialInterface* D3_MaterialTransparent;
UPROPERTY(EditAnywhere, Category = Plot3D, BlueprintReadWrite)
FColor D3_BrushColor;
UPROPERTY(EditAnywhere, Category = Plot3D, BlueprintReadWrite)
bool D3_BrushOverridesColor;
UPROPERTY(EditAnywhere, Category = Plot3D, BlueprintReadWrite)
uint8 D3_BrushAlpha;
UPROPERTY(EditAnywhere, Category = Plot3D, BlueprintReadWrite)
uint8 D3_SpriteAlpha;
UPROPERTY(EditAnywhere, Category = Plot3D, BlueprintReadWrite)
bool D3_UseTransparency;
UPROPERTY(EditAnywhere, Category = Plot3D, BlueprintReadWrite)
float D3_SpriteSizeFactor;
protected:
virtual void BeginPlay() override;
private:
H5File LoadedFile;
TArray<FString> GroupNames;
TArray<FString> FileNames;
FColor CalculateColorOfPoint(int32 Index, float Min, float Max);
public:
UPROPERTY(Category = Plot3D, BlueprintReadWrite)
int32 Num;
UPROPERTY(Category = Plot3D, BlueprintReadWrite)
TArray<bool> IsBrushed;
UPROPERTY(Category = Plot3D, BlueprintReadWrite)
TArray<float> X;
UPROPERTY(Category = Plot3D, BlueprintReadWrite)
TArray<float> Y;
UPROPERTY(Category = Plot3D, BlueprintReadWrite)
TArray<float> Z;
UPROPERTY(Category = Plot3D, BlueprintReadWrite)
TArray<FVector> PColor;
UPROPERTY(Category = Plot3D, BlueprintReadWrite)
TArray<float> U;
UPROPERTY(Category = Plot3D, BlueprintReadWrite)
TArray<float> V;
UPROPERTY(Category = Plot3D, BlueprintReadWrite)
TArray<float> W;
UPROPERTY(Category = Plot3D, BlueprintReadWrite)
TArray<float> Length;
UPROPERTY(Category = Plot3D, BlueprintReadOnly)
float MinLength;
UPROPERTY(Category = Plot3D, BlueprintReadOnly)
float MaxLength;
UPROPERTY(Category = Plot3D, BlueprintReadOnly)
float MinX;
UPROPERTY(Category = Plot3D, BlueprintReadOnly)
float MaxX;
UPROPERTY(Category = Plot3D, BlueprintReadOnly)
float MinY;
UPROPERTY(Category = Plot3D, BlueprintReadOnly)
float MaxY;
UPROPERTY(Category = Plot3D, BlueprintReadOnly)
float MinZ;
UPROPERTY(Category = Plot3D, BlueprintReadOnly)
float MaxZ;
UPROPERTY(Category = Plot3D, BlueprintReadOnly)
float MinU;
UPROPERTY(Category = Plot3D, BlueprintReadOnly)
float MaxU;
UPROPERTY(Category = Plot3D, BlueprintReadOnly)
float MinV;
UPROPERTY(Category = Plot3D, BlueprintReadOnly)
float MaxV;
UPROPERTY(Category = Plot3D, BlueprintReadOnly)
float MinW;
UPROPERTY(Category = Plot3D, BlueprintReadOnly)
float MaxW;
};
......@@ -29,6 +29,15 @@ DataSet UHDF5Library::getDatasetByName(Group & group, char * name)
return dataset;
}
Group UHDF5Library::getGroupByName(H5File & file, FString name)
{
char* NameAsCharArray = NULL;
NameAsCharArray = TCHAR_TO_ANSI(*name);
Group group = file.openGroup(NameAsCharArray);
return group;
}
/*
Group UHDF5Library::getGroupByName(H5File & file, FString name)
{
for (int i = 0; i < 1000; ++i)
......@@ -60,9 +69,14 @@ Group UHDF5Library::getGroupByName(H5File & file, FString name)
}
return Group();
}
}*/
bool UHDF5Library::ImportData(FString FileName, TArray<float>& X, TArray<float>& Y, TArray<float>& Z, TArray<float>& U, TArray<float>& V, TArray<float>& W)
{
return false;
}
H5File UHDF5Library::LoadFile(FString FileName, TArray<FString>& GroupNames)
{
/*
* Turn off the auto-printing when failure occurs so that we can
......@@ -89,12 +103,35 @@ bool UHDF5Library::ImportData(FString FileName, TArray<float>& X, TArray<float>&
FString abspath = IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(*relpath);
char* pathAsCharArray = TCHAR_TO_ANSI(*abspath);
H5File file(pathAsCharArray, H5F_ACC_RDONLY);
Group group = getGroupByName(file, "Step#");
H5File File = H5File(pathAsCharArray, H5F_ACC_RDONLY);
Group Root = File.openGroup("/");
/*
* Get dataspace of one dataset to get the dimension. (Dimensions must be equal for all sets.)
*/
GroupNames = TArray<FString>();
for (int i = 0; i < Root.getNumObjs(); i++) {
std::string GroupName;
switch (Root.getObjTypeByIdx((size_t)i))
{
case H5G_GROUP:
GroupName = Root.getObjnameByIdx((size_t)i);
GroupNames.Emplace(FString(GroupName.c_str()));
break;
default:
break;
}
}
return File;
}
bool UHDF5Library::LoadGroup(H5File File, FString GroupName, TArray<float>& X, TArray<float>& Y, TArray<float>& Z, TArray<float>& U, TArray<float>& V, TArray<float>& W)
{
Group group = getGroupByName(File, GroupName);
// Get dataspace of one dataset to get the dimension. (Dimensions must be equal for all sets.)
DataSet dataset = getDatasetByName(group, "X");
DataSpace dataspace = dataset.getSpace();
int rank = dataspace.getSimpleExtentNdims();
......@@ -103,55 +140,34 @@ bool UHDF5Library::ImportData(FString FileName, TArray<float>& X, TArray<float>&
int32 dimension = dims_out[0];
dataspace.selectAll(); // needed?
/*
* Output buffer initialization.
*/
//float data_out[262144]; /* output buffer */
// Output buffer initialization
float* data_out = new float[dimension];
/*
* Read X
*/
// Read datasets
dataset.read(data_out, PredType::NATIVE_FLOAT);
X = TArray<float>(data_out, dims_out[0]);
/*
* Read Y
*/
dataset = getDatasetByName(group, "Y");
dataset.read(data_out, PredType::NATIVE_FLOAT);
Y = TArray<float>(data_out, dims_out[0]);
/*
* Read Z
*/
dataset = getDatasetByName(group, "Z");
dataset.read(data_out, PredType::NATIVE_FLOAT);
Z = TArray<float>(data_out, dims_out[0]);
/*
* Read U
*/
dataset = getDatasetByName(group, "U");
dataset.read(data_out, PredType::NATIVE_FLOAT);
U = TArray<float>(data_out, dims_out[0]);
/*
* Read V
*/
dataset = getDatasetByName(group, "V");
dataset.read(data_out, PredType::NATIVE_FLOAT);
V = TArray<float>(data_out, dims_out[0]);
/*
* Read W
*/
dataset = getDatasetByName(group, "W");
dataset.read(data_out, PredType::NATIVE_FLOAT);
W = TArray<float>(data_out, dims_out[0]);
delete[] data_out;
// success
return true;
}
\ No newline at end of file
}
......@@ -17,9 +17,12 @@ class IMMERSIVEANALYTICS_API UHDF5Library : public UBlueprintFunctionLibrary
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, meta = (DisplayName = "Test HDF5", Keywords = "TEST HDF5"), Category = HDF5)
UFUNCTION(BlueprintCallable, Category = HDF5)
static bool ImportData(FString FileName, TArray<float>& X, TArray<float>& Y, TArray<float>& Z, TArray<float>& U, TArray<float>& V, TArray<float>& W);
static H5File LoadFile(FString FileName, TArray<FString>& GroupNames);
static bool LoadGroup(H5File File, FString GroupName, TArray<float>& X, TArray<float>& Y, TArray<float>& Z, TArray<float>& U, TArray<float>& V, TArray<float>& W);
private:
static DataSet getDatasetByName(Group & group, char * name);
static Group getGroupByName(H5File & file, FString name);
......
......@@ -3,13 +3,16 @@
#include "PawnBase.h"
#include "Runtime/Engine/Classes/Kismet/GameplayStatics.h"
#include "Plot3D.h"
#include "DataComponent.h"
// Sets default values
APawnBase::APawnBase()
{
// Set this pawn to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
Data = CreateDefaultSubobject<UDataComponent>(TEXT("DataComponent"));
Data->bAutoActivate = true;
Data->bAutoRegister = true;
}
// Called when the game starts or when spawned
......@@ -17,10 +20,6 @@ void APawnBase::BeginPlay()
{
Super::BeginPlay();
TArray<AActor*> AllActors;
UGameplayStatics::GetAllActorsWithTag(this, TEXT("Plot3D"), AllActors);
Plot3D = Cast<APlot3D>(AllActors[0]);
}
// Called every frame
......
......@@ -20,6 +20,9 @@ public:
UPROPERTY(EditAnywhere, BlueprintReadOnly)
APlot3D* Plot3D;
UPROPERTY(Category = DataComponent, VisibleAnywhere, BlueprintReadOnly)
class UDataComponent* Data;
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
......
This diff is collapsed.
......@@ -18,154 +18,46 @@ class IMMERSIVEANALYTICS_API APlot3D : public AActor
pub