Commit ab1bdbd9 authored by Jan Kremer's avatar Jan Kremer
Browse files

Rewrote 3D plot in C++.

parent a666b0f7
No preview for this file type
No preview for this file type
import unreal_engine as ue import unreal_engine as ue
from unreal_engine.enums import EPixelFormat
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import numpy as np import numpy as np
......
No preview for this file type
...@@ -50,4 +50,12 @@ bHQBuffer=False ...@@ -50,4 +50,12 @@ bHQBuffer=False
bHQDistortion=False bHQDistortion=False
bUpdateOnRT=True bUpdateOnRT=True
[WindowsApplication.Accessibility]
StickyKeysHotkey=True
ToggleKeysHotkey=True
FilterKeysHotkey=True
StickyKeysConfirmation=True
ToggleKeysConfirmation=True
FilterKeysConfirmation=True
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
#include "H5Cpp.h" #include "H5Cpp.h"
using namespace H5; using namespace H5;
bool UHDF5Library::TestHDF5(TArray<float>& X, TArray<float>& Y, TArray<float>& Z, TArray<float>& U, TArray<float>& V, TArray<float>& W) bool UHDF5Library::ImportData(TArray<float>& X, TArray<float>& Y, TArray<float>& Z, TArray<float>& U, TArray<float>& V, TArray<float>& W)
{ {
/* /*
* Turn off the auto-printing when failure occurs so that we can * Turn off the auto-printing when failure occurs so that we can
......
...@@ -14,6 +14,7 @@ class IMMERSIVEANALYTICS_API UHDF5Library : public UBlueprintFunctionLibrary ...@@ -14,6 +14,7 @@ class IMMERSIVEANALYTICS_API UHDF5Library : public UBlueprintFunctionLibrary
{ {
GENERATED_BODY() GENERATED_BODY()
UFUNCTION(BlueprintCallable, meta = (DisplayName = "Test HDF5", Keywords = "TEST HDF5"), Category = HDF5) public:
static bool TestHDF5(TArray<float>& X, TArray<float>& Y, TArray<float>& Z, TArray<float>& U, TArray<float>& V, TArray<float>& W); UFUNCTION(BlueprintCallable, Category = HDF5)
static bool ImportData(TArray<float>& X, TArray<float>& Y, TArray<float>& Z, TArray<float>& U, TArray<float>& V, TArray<float>& W);
}; };
// Fill out your copyright notice in the Description page of Project Settings. // Fill out your copyright notice in the Description page of Project Settings.
#include "Plot3D.h" #include "Plot3D.h"
#include "HDF5Library.h"
#include "PointCloudComponent.h"
#include "Runtime/Engine/Classes/Kismet/KismetMathLibrary.h"
// Sets default values // Sets default values
APlot3D::APlot3D() APlot3D::APlot3D()
{ {
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true; PrimaryActorTick.bCanEverTick = true;
USceneComponent* SceneComponent = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent"));
RootComponent = SceneComponent;
SceneComponent->SetMobility(EComponentMobility::Movable);
PointCloudComponent = CreateDefaultSubobject<UPointCloudComponent>(TEXT("PointCloudComponent"));
PointCloudComponent->SetupAttachment(RootComponent);
PointCloudComponent->bCastVolumetricTranslucentShadow = true;
PointCloudComponent->bCastShadowAsTwoSided = true;
} }
// Called when the game starts or when spawned // Called when the game starts or when spawned
...@@ -21,35 +28,78 @@ void APlot3D::BeginPlay() ...@@ -21,35 +28,78 @@ void APlot3D::BeginPlay()
void APlot3D::InitPoints() void APlot3D::InitPoints()
{ {
// Populate the MyPoints array with 1000 randomly positioned, red points TArray<float> X;
for (int32 i = 0; i < 1000; i++) TArray<float> Y;
TArray<float> Z;
UHDF5Library::ImportData(X, Y, Z, U, V, W);
int32 Num;
if (OverridePointCount)
{ {
// See FPointCloudPoint for more constructor versions Num = PointCount;
MyPoints.Emplace(FMath::VRand(), FColor::Red, true); }
else
{
Num = X.Num();
} }
// for (int32 i = 0; i < Num; i++)
{
Length.Emplace(FVector(U[i], V[i], W[i]).Size());
}
int32 MaxIndex, MinIndex;
float Max, Min;
UKismetMathLibrary::MaxOfFloatArray(Length, MaxIndex, Max);
UKismetMathLibrary::MinOfFloatArray(Length, MinIndex, Min);
for (int32 i = 0; i < Num; i++)
{
FColor Color = CalculateColorOfPoint(i, Min, Max);
Points.Emplace(FVector(X[i], Y[i], Z[i]), Color, true);
}
} }
void APlot3D::InitCloud() void APlot3D::InitCloud()
{ {
// Construct an empty Point Cloud asset PointCloud = NewObject<UPointCloud>();
UPointCloud *MyPointCloud = NewObject<UPointCloud>(); PointCloud->Offset = EPointCloudOffset::None;
PointCloud->SetRenderingMethod(EPointCloudRenderMethod::Sprite_Lit_RGB, false);
PointCloud->SpriteMask = EPointCloudSpriteMask::Circle;
//PointCloud->SpriteTexture =
PointCloud->ColorOverride = EPointCloudColorOverride::None;
PointCloud->SpriteSize = FVector2D(0.5, 0.5);
// GetPointCloudComponent()->SetPointCloud(PointCloud);
RebuildCloud();
}
// Assign the generated points to the cloud and automatically rebuild the data FColor APlot3D::CalculateColorOfPoint(int32 Index, float Min, float Max)
MyPointCloud->SetPointCloudData(MyPoints); {
// Alternatively, do not auto-build the data by calling float NormalizedValue = UKismetMathLibrary::NormalizeToRange(Length[Index], Min, Max);
// MyPointCloud->SetPointCloudData(MyPoints, false);
// Get the target Point Cloud Actor check(TransferFunction != nullptr);
//APointCloudActor *MyPointCloudActor = MyActorGettingFunction(); FVector ColorVec = TransferFunction->GetVectorValue(NormalizedValue);
// Assign the constructed Cloud FColor Color = FColor((uint8)(ColorVec.X * 255), (uint8)(ColorVec.Y * 255), (uint8)(ColorVec.Z * 255));
//MyPointCloudActor->GetPointCloudComponent()->SetPointCloud(MyPointCloud);
// return Color;
}
void APlot3D::RebuildCloud()
{
PointCloud->SetPointCloudData(Points, true);
}
FVector APlot3D::CalculateWorldLocOfPoint(FPointCloudPoint * Point)
{
FVector ActorScale = GetActorScale3D() * 100;
FVector Vec = FVector(ActorScale.X * Point->Location.X * -1, ActorScale.Y * Point->Location.Y, ActorScale.Z * Point->Location.Z);
FVector RotatedVec = GetActorRotation().RotateVector(Vec);
FVector SumVec = GetActorLocation() + RotatedVec;
return SumVec;
} }
// Called every frame // Called every frame
...@@ -59,3 +109,167 @@ void APlot3D::Tick(float DeltaTime) ...@@ -59,3 +109,167 @@ void APlot3D::Tick(float DeltaTime)
} }
void APlot3D::BrushPoints(TArray<int32> BrushPoints, bool Add, bool Rebuild)
{
for (int i = 0; i < BrushPoints.Num(); ++i)
{
BrushPoint(BrushPoints[i], Add);
}
if (Rebuild)
{
RebuildCloud();
}
}
void APlot3D::BrushPoint(int32 PointIndex, bool Add)
{
Points[PointIndex].SetEnabled(!Add);
/*
if (Add)
{
Points[PointIndex].Color = FColor();
}
else
{
Points[PointIndex].Color = Points[PointIndex].OriginalColor;
}
*/
}
void APlot3D::ResetPoints(bool Rebuild)
{
for (int i = 0; i < Points.Num(); ++i)
{
BrushPoint(i, false);
}
if (Rebuild)
{
RebuildCloud();
}
}
void APlot3D::InvertPoints(bool Rebuild)
{
for (int i = 0; i < Points.Num(); ++i)
{
BrushPoint(i, Points[i].IsEnabled());
}
if (Rebuild)
{
RebuildCloud();
}
}
void APlot3D::AddFilter_Planes(FVector NormalRight, FVector LocationRight, bool UseTwoPlanes, FVector NormalLeft, FVector LocationLeft, bool Add, bool Rebuild, bool Invert)
{
TArray<int32> Indexes = TArray<int32>();
for (int i = 0; i < Points.Num(); ++i)
{
FVector WorldLoc = CalculateWorldLocOfPoint(&Points[i]);
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.Emplace(i);
}
}
else
{
if (DotRight <= 0.f && (DotLeft <= 0.f || !UseTwoPlanes))
{
Indexes.Emplace(i);
}
}
}
BrushPoints(Indexes, Add, Rebuild);
}
void APlot3D::AddFilter_ValueRange(EAxisType XType, float XMin, float XMax, EAxisType YType, float YMin, float YMax, bool Add, bool Rebuild)
{
float XValue, YValue;
TArray<int32> Indexes = TArray<int32>();
for (int i = 0; i < Points.Num(); ++i)
{
switch (XType)
{
case EAxisType::X:
XValue = Points[i].Location.X;
break;
case EAxisType::Y:
XValue = Points[i].Location.Y;
break;
case EAxisType::Z:
XValue = Points[i].Location.Z;
break;
default:
break;
}
switch (YType)
{
case EAxisType::U:
YValue = U[i];
break;
case EAxisType::V:
YValue = V[i];
break;
case EAxisType::W:
YValue = W[i];
break;
default:
break;
}
if (XValue >= XMin && XValue <= XMax && YValue >= YMin && YValue <= YMax)
{
Indexes.Emplace(i);
}
}
BrushPoints(Indexes, Add, Rebuild);
}
void APlot3D::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);
}
}
BrushPoints(Indexes, Add, Rebuild);
}
void APlot3D::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);
}
}
BrushPoints(Indexes, Add, Rebuild);
}
...@@ -6,8 +6,15 @@ ...@@ -6,8 +6,15 @@
#include "GameFramework/Actor.h" #include "GameFramework/Actor.h"
#include "PointCloud.h" #include "PointCloud.h"
#include "PointCloudActor.h" #include "PointCloudActor.h"
#include "Runtime/Engine/Classes/Curves/CurveVector.h"
#include "Plot3D.generated.h" #include "Plot3D.generated.h"
UENUM(BlueprintType) //"BlueprintType" is essential to include
enum class EAxisType : uint8
{
X,Y,Z,U,V,W,LengthUVW,Count
};
UCLASS() UCLASS()
class IMMERSIVEANALYTICS_API APlot3D : public AActor class IMMERSIVEANALYTICS_API APlot3D : public AActor
{ {
...@@ -24,12 +31,67 @@ protected: ...@@ -24,12 +31,67 @@ protected:
private: private:
void InitPoints(); void InitPoints();
void InitCloud(); void InitCloud();
FColor CalculateColorOfPoint(int32 Index, float Min, float Max);
void RebuildCloud();
FVector CalculateWorldLocOfPoint(FPointCloudPoint* Point);
UPROPERTY(Category = PointCloudActor, VisibleAnywhere, BlueprintReadOnly, meta = (ExposeFunctionCategories = "Rendering,Components|PointCloud", AllowPrivateAccess = "true"))
class UPointCloudComponent* PointCloudComponent;
public: public:
// Called every frame // Called every frame
virtual void Tick(float DeltaTime) override; virtual void Tick(float DeltaTime) override;
UPROPERTY(Category = Plot3D, VisibleAnywhere, BlueprintReadOnly) UPROPERTY(Category = Plot3D, VisibleAnywhere, BlueprintReadOnly)
TArray<FPointCloudPoint> MyPoints; TArray<FPointCloudPoint> Points;
UPROPERTY(Category = Plot3D, VisibleAnywhere, BlueprintReadOnly)
TArray<float> U;
UPROPERTY(Category = Plot3D, VisibleAnywhere, BlueprintReadOnly)
TArray<float> V;
UPROPERTY(Category = Plot3D, VisibleAnywhere, BlueprintReadOnly)
TArray<float> W;
UPROPERTY(Category = Plot3D, VisibleAnywhere, BlueprintReadOnly)
TArray<float> Length;
UPROPERTY(EditDefaultsOnly, Category = Plot3D)
UCurveVector* TransferFunction;
UPROPERTY(Category = Plot3D, VisibleAnywhere, BlueprintReadOnly)
UPointCloud *PointCloud;
UPROPERTY(Category = Plot3D, EditAnywhere)
bool OverridePointCount;
UPROPERTY(Category = Plot3D, EditAnywhere)
int32 PointCount;
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);
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);
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);
class UPointCloudComponent* GetPointCloudComponent() const { return PointCloudComponent; }
}; };
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment