Commit ab1bdbd9 authored by Jan Kremer's avatar Jan Kremer

Rewrote 3D plot in C++.

parent a666b0f7
No preview for this file type
No preview for this file type
import unreal_engine as ue
from unreal_engine.enums import EPixelFormat
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
......
No preview for this file type
......@@ -50,4 +50,12 @@ bHQBuffer=False
bHQDistortion=False
bUpdateOnRT=True
[WindowsApplication.Accessibility]
StickyKeysHotkey=True
ToggleKeysHotkey=True
FilterKeysHotkey=True
StickyKeysConfirmation=True
ToggleKeysConfirmation=True
FilterKeysConfirmation=True
......@@ -6,7 +6,7 @@
#include "H5Cpp.h"
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
......
......@@ -14,6 +14,7 @@ class IMMERSIVEANALYTICS_API UHDF5Library : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
UFUNCTION(BlueprintCallable, meta = (DisplayName = "Test HDF5", Keywords = "TEST HDF5"), Category = HDF5)
static bool TestHDF5(TArray<float>& X, TArray<float>& Y, TArray<float>& Z, TArray<float>& U, TArray<float>& V, TArray<float>& W);
public:
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.
#include "Plot3D.h"
#include "HDF5Library.h"
#include "PointCloudComponent.h"
#include "Runtime/Engine/Classes/Kismet/KismetMathLibrary.h"
// Sets default values
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;
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
......@@ -21,35 +28,78 @@ void APlot3D::BeginPlay()
void APlot3D::InitPoints()
{
// Populate the MyPoints array with 1000 randomly positioned, red points
for (int32 i = 0; i < 1000; i++)
TArray<float> X;
TArray<float> Y;
TArray<float> Z;
UHDF5Library::ImportData(X, Y, Z, U, V, W);
int32 Num;
if (OverridePointCount)
{
Num = PointCount;
}
else
{
// See FPointCloudPoint for more constructor versions
MyPoints.Emplace(FMath::VRand(), FColor::Red, true);
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()
{
// Construct an empty Point Cloud asset
UPointCloud *MyPointCloud = NewObject<UPointCloud>();
PointCloud = 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();
}
FColor APlot3D::CalculateColorOfPoint(int32 Index, float Min, float Max)
{
float NormalizedValue = UKismetMathLibrary::NormalizeToRange(Length[Index], Min, Max);
//
check(TransferFunction != nullptr);
FVector ColorVec = TransferFunction->GetVectorValue(NormalizedValue);
// Assign the generated points to the cloud and automatically rebuild the data
MyPointCloud->SetPointCloudData(MyPoints);
// Alternatively, do not auto-build the data by calling
// MyPointCloud->SetPointCloudData(MyPoints, false);
FColor Color = FColor((uint8)(ColorVec.X * 255), (uint8)(ColorVec.Y * 255), (uint8)(ColorVec.Z * 255));
// Get the target Point Cloud Actor
//APointCloudActor *MyPointCloudActor = MyActorGettingFunction();
return Color;
}
// Assign the constructed Cloud
//MyPointCloudActor->GetPointCloudComponent()->SetPointCloud(MyPointCloud);
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
......@@ -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 @@
#include "GameFramework/Actor.h"
#include "PointCloud.h"
#include "PointCloudActor.h"
#include "Runtime/Engine/Classes/Curves/CurveVector.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()
class IMMERSIVEANALYTICS_API APlot3D : public AActor
{
......@@ -24,12 +31,67 @@ protected:
private:
void InitPoints();
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:
// Called every frame
virtual void Tick(float DeltaTime) override;
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