diff --git a/Content/2DDiagramActor.uasset b/Content/2DDiagramActor.uasset index b57d298fb9ee02453e015f7e167cadc33ab778eb..793a9187002829976e7ba13932585ca8142a1ff8 100644 Binary files a/Content/2DDiagramActor.uasset and b/Content/2DDiagramActor.uasset differ diff --git a/Content/BP_PawnBase.uasset b/Content/BP_PawnBase.uasset index 86505dd376d8582f34b57fd540c4a926b85ec8d7..e74a6d2892625d282c7c58f6c58fd6a7b75e5fbe 100644 Binary files a/Content/BP_PawnBase.uasset and b/Content/BP_PawnBase.uasset differ diff --git a/Content/Scripts/new.py b/Content/Scripts/new.py index e32c14b15049b6422cbadffbff37c9413941fbc3..19d95b6dd18a4d4bdb2c35811dd1746ba6bdebe4 100644 --- a/Content/Scripts/new.py +++ b/Content/Scripts/new.py @@ -11,7 +11,7 @@ class Plot: def begin_play(self): self.uobject.get_owner().bind_event('OnRedraw', self.redraw) - def redraw(self, x, y, r, g, b): + def redraw(self, x, y, c): width=1024 height=1024 canvas = app.Canvas(size=(width, height)) @@ -39,9 +39,8 @@ class Plot: program = gloo.Program(vert=vertex, frag=fragment) - N = 4000000 - data = np.c_[x,y] - data2 = np.c_[r,g,b] + data = np.c_[x[0:100000],y[0:100000]] + data2 = np.c_[c] program['a_color'] = data2.astype('float32') program['a_position'] = data.astype('float32') diff --git a/Content/Test.umap b/Content/Test.umap index 9e10c2132c6e5b8676fef46f4c93105e3103d6ef..fc8f46b21ae71e0df0aa2d3c76de10ef357ffadd 100644 Binary files a/Content/Test.umap and b/Content/Test.umap differ diff --git a/Content/Test_BuiltData.uasset b/Content/Test_BuiltData.uasset index 491a1c58cd1923dff517c5a6df723beef42e297b..7ad9c74a1199cacb4f7fab44e1bb6a5215cd52f5 100644 Binary files a/Content/Test_BuiltData.uasset and b/Content/Test_BuiltData.uasset differ diff --git a/Saved/Config/Windows/Engine.ini b/Saved/Config/Windows/Engine.ini index abbdd364bd36a0c9a3a6913af6c125e02179ce57..071c4536ce8a635b84ae9e4debce2cb133db0e92 100644 --- a/Saved/Config/Windows/Engine.ini +++ b/Saved/Config/Windows/Engine.ini @@ -51,11 +51,11 @@ bHQDistortion=False bUpdateOnRT=True [WindowsApplication.Accessibility] -StickyKeysHotkey=True -ToggleKeysHotkey=True -FilterKeysHotkey=True -StickyKeysConfirmation=True -ToggleKeysConfirmation=True -FilterKeysConfirmation=True +StickyKeysHotkey=False +ToggleKeysHotkey=False +FilterKeysHotkey=False +StickyKeysConfirmation=False +ToggleKeysConfirmation=False +FilterKeysConfirmation=False diff --git a/Source/ImmersiveAnalytics/Plot3D.cpp b/Source/ImmersiveAnalytics/Plot3D.cpp index cc46041c6712d07facd51412c6456da32ef3548d..e7b78fe50fbbc3d5f39ca42fa0bc958f4b0cd743 100644 --- a/Source/ImmersiveAnalytics/Plot3D.cpp +++ b/Source/ImmersiveAnalytics/Plot3D.cpp @@ -4,6 +4,7 @@ #include "HDF5Library.h" #include "PointCloudComponent.h" #include "Runtime/Engine/Classes/Kismet/KismetMathLibrary.h" +#include "Runtime/Core/Public/Async/ParallelFor.h" // Sets default values APlot3D::APlot3D() @@ -28,10 +29,6 @@ void APlot3D::BeginPlay() void APlot3D::InitPoints() { - TArray X; - TArray Y; - TArray Z; - UHDF5Library::ImportData(X, Y, Z, U, V, W); int32 Num; @@ -67,9 +64,10 @@ void APlot3D::InitPoints() for (int32 i = 0; i < Num; i++) { - FColor Color = CalculateColorOfPoint(i, MaxLength, MinLength); + FColor TempColor = CalculateColorOfPoint(i, MaxLength, MinLength); - Points.Emplace(FVector(X[i], Y[i], Z[i]), Color, true); + Color.Emplace(FVector(TempColor.R, TempColor.G, TempColor.B)); + Points.Emplace(FVector(X[i], Y[i], Z[i]), TempColor, true); } } @@ -113,7 +111,6 @@ FVector APlot3D::CalculateWorldLocOfPoint(FPointCloudPoint * Point) return SumVec; } -// Called every frame void APlot3D::Tick(float DeltaTime) { Super::Tick(DeltaTime); @@ -135,6 +132,11 @@ void APlot3D::BrushPoints(TArray BrushPoints, bool Add, bool Rebuild) void APlot3D::BrushPoint(int32 PointIndex, bool Add) { + if (PointIndex == -1) + { + return; + } + Points[PointIndex].SetEnabled(!Add); /* @@ -156,6 +158,11 @@ void APlot3D::ResetPoints(bool Rebuild) BrushPoint(i, false); } + /*ParallelFor(Points.Num(), [this](int32 CurrIdx) + { + BrushPoint(CurrIdx, false); + });*/ + if (Rebuild) { RebuildCloud(); @@ -169,6 +176,21 @@ void APlot3D::InvertPoints(bool Rebuild) BrushPoint(i, Points[i].IsEnabled()); } + /*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()); + } + });*/ + if (Rebuild) { RebuildCloud(); @@ -178,10 +200,11 @@ void APlot3D::InvertPoints(bool Rebuild) void APlot3D::AddFilter_Planes(FVector NormalRight, FVector LocationRight, bool UseTwoPlanes, FVector NormalLeft, FVector LocationLeft, bool Add, bool Rebuild, bool Invert) { TArray Indexes = TArray(); + Indexes.Init(-1, Points.Num()); - for (int i = 0; i < Points.Num(); ++i) + ParallelFor(Points.Num(), [this, Invert, &Indexes, LocationRight, LocationLeft, NormalRight, NormalLeft, UseTwoPlanes, Add](int32 CurrIdx) { - FVector WorldLoc = CalculateWorldLocOfPoint(&Points[i]); + FVector WorldLoc = CalculateWorldLocOfPoint(&Points[CurrIdx]); FVector DifferenceRight = WorldLoc - LocationRight; FVector DifferenceLeft = WorldLoc - LocationLeft; float DotRight = UKismetMathLibrary::Dot_VectorVector(DifferenceRight, NormalRight); @@ -191,59 +214,94 @@ void APlot3D::AddFilter_Planes(FVector NormalRight, FVector LocationRight, bool { if (DotRight >= 0.f && (DotLeft >= 0.f || !UseTwoPlanes)) { - Indexes.Emplace(i); + Indexes[CurrIdx] = CurrIdx; } } else { if (DotRight <= 0.f && (DotLeft <= 0.f || !UseTwoPlanes)) { - Indexes.Emplace(i); + Indexes[CurrIdx] = CurrIdx; } } - } + }); 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 * XArray = nullptr; + TArray * YArray = nullptr; TArray Indexes = TArray(); - for (int i = 0; i < Points.Num(); ++i) + switch (XType) { - 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; - } + 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; + } - switch (YType) + /* + 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) { - case EAxisType::U: - YValue = U[i]; - break; - case EAxisType::V: - YValue = V[i]; - break; - case EAxisType::W: - YValue = W[i]; - break; - default: - break; + Indexes[CurrIdx] = CurrIdx; } + });*/ - if (XValue >= XMin && XValue <= XMax && YValue >= YMin && YValue <= YMax) + for (int i = 0; i < Points.Num(); ++i) + { + if ((*XArray)[i] >= XMin && (*XArray)[i] <= XMax && (*YArray)[i] >= YMin && (*YArray)[i] <= YMax) { Indexes.Emplace(i); } @@ -256,14 +314,24 @@ void APlot3D::AddFilter_Box(FTransform Transform, FVector Extent, bool Add, bool { TArray Indexes = TArray(); - for (int i = 0; i < Points.Num(); ++i) + /*for (int i = 0; i < Points.Num(); ++i) { FVector WorldLoc = CalculateWorldLocOfPoint(&Points[i]); if (UKismetMathLibrary::IsPointInBoxWithTransform(WorldLoc, Transform, Extent)) { Indexes.Emplace(i); } - } + }*/ + + Indexes.Init(-1, Points.Num()); + ParallelFor(Points.Num(), [this, Transform, Extent, Add, &Indexes](int32 CurrIdx) + { + FVector WorldLoc = CalculateWorldLocOfPoint(&Points[CurrIdx]); + if (UKismetMathLibrary::IsPointInBoxWithTransform(WorldLoc, Transform, Extent)) + { + Indexes[CurrIdx] = CurrIdx; + } + }); BrushPoints(Indexes, Add, Rebuild); } @@ -272,14 +340,24 @@ void APlot3D::AddFilter_Sphere(FVector Location, float Radius, bool Add, bool Re { TArray Indexes = TArray(); - for (int i = 0; i < Points.Num(); ++i) + /*for (int i = 0; i < Points.Num(); ++i) { FVector WorldLoc = CalculateWorldLocOfPoint(&Points[i]); if ((Location - WorldLoc).Size() <= Radius) { Indexes.Emplace(i); } - } + }*/ + + Indexes.Init(-1, Points.Num()); + ParallelFor(Points.Num(), [this, Location, Radius, Add, &Indexes](int32 CurrIdx) + { + FVector WorldLoc = CalculateWorldLocOfPoint(&Points[CurrIdx]); + if ((Location - WorldLoc).Size() <= Radius) + { + Indexes[CurrIdx] = CurrIdx; + } + }); BrushPoints(Indexes, Add, Rebuild); } diff --git a/Source/ImmersiveAnalytics/Plot3D.h b/Source/ImmersiveAnalytics/Plot3D.h index a3d58999055c9d11389d0eadc73d7d74ed970655..f79f924ea3fcf29e10c391570438f49ffbadf170 100644 --- a/Source/ImmersiveAnalytics/Plot3D.h +++ b/Source/ImmersiveAnalytics/Plot3D.h @@ -45,16 +45,28 @@ public: UPROPERTY(Category = Plot3D, VisibleAnywhere, BlueprintReadOnly) TArray Points; - UPROPERTY(Category = Plot3D, VisibleAnywhere, BlueprintReadOnly) + UPROPERTY(Category = Plot3D, VisibleAnywhere, BlueprintReadWrite) + TArray X; + + UPROPERTY(Category = Plot3D, VisibleAnywhere, BlueprintReadWrite) + TArray Y; + + UPROPERTY(Category = Plot3D, VisibleAnywhere, BlueprintReadWrite) + TArray Z; + + UPROPERTY(Category = Plot3D, VisibleAnywhere, BlueprintReadWrite) + TArray Color; + + UPROPERTY(Category = Plot3D, VisibleAnywhere, BlueprintReadWrite) TArray U; - UPROPERTY(Category = Plot3D, VisibleAnywhere, BlueprintReadOnly) + UPROPERTY(Category = Plot3D, VisibleAnywhere, BlueprintReadWrite) TArray V; - UPROPERTY(Category = Plot3D, VisibleAnywhere, BlueprintReadOnly) + UPROPERTY(Category = Plot3D, VisibleAnywhere, BlueprintReadWrite) TArray W; - UPROPERTY(Category = Plot3D, VisibleAnywhere, BlueprintReadOnly) + UPROPERTY(Category = Plot3D, VisibleAnywhere, BlueprintReadWrite) TArray Length; UPROPERTY(Category = Plot3D, VisibleAnywhere, BlueprintReadOnly) diff --git a/Source/ImmersiveAnalytics/PlotCanvas.cpp b/Source/ImmersiveAnalytics/PlotCanvas.cpp index 4f315e2c7ac10856bef9092fdeebbd70e1bbcd8b..639c45de451eafbeeac6bde2345a2bc450dd1a7e 100644 --- a/Source/ImmersiveAnalytics/PlotCanvas.cpp +++ b/Source/ImmersiveAnalytics/PlotCanvas.cpp @@ -72,6 +72,38 @@ void UPlotCanvas::DrawFromData() UpdateCanvas(); } +void UPlotCanvas::DrawParallelCoordinatesPlot() +{ + APawn* Pawn = UGameplayStatics::GetPlayerPawn(this, 0); + APawnBase* PawnBase = Cast(Pawn); + + for (int i = 0; i < PawnBase->Plot3D->Points.Num(); ++i) + { + int32 x0 = 0; + int32 x1 = canvasWidth * 1 / 5; + int32 x2 = canvasWidth * 2 / 5; + int32 x3 = canvasWidth * 3 / 5; + int32 x4 = canvasWidth * 4 / 5; + int32 x5 = canvasWidth; + int32 y0 = (PawnBase->Plot3D->Points[i].Location.X - PawnBase->Plot3D->MinX) / (PawnBase->Plot3D->MaxX - PawnBase->Plot3D->MinX) * canvasHeight / 4; + int32 y1 = (PawnBase->Plot3D->Points[i].Location.Y - PawnBase->Plot3D->MinY) / (PawnBase->Plot3D->MaxY - PawnBase->Plot3D->MinY) * canvasHeight / 4; + int32 y2 = (PawnBase->Plot3D->Points[i].Location.Z - PawnBase->Plot3D->MinZ) / (PawnBase->Plot3D->MaxZ - PawnBase->Plot3D->MinZ) * canvasHeight / 4; + int32 y3 = (PawnBase->Plot3D->U[i] - PawnBase->Plot3D->MinU) / (PawnBase->Plot3D->MaxU - PawnBase->Plot3D->MinU) * canvasHeight / 4; + int32 y4 = (PawnBase->Plot3D->V[i] - PawnBase->Plot3D->MinV) / (PawnBase->Plot3D->MaxV - PawnBase->Plot3D->MinV) * canvasHeight / 4; + int32 y5 = (PawnBase->Plot3D->W[i] - PawnBase->Plot3D->MinW) / (PawnBase->Plot3D->MaxW - PawnBase->Plot3D->MinW) * canvasHeight / 4; + uint8 r = PawnBase->Plot3D->Points[i].Color.R; + uint8 g = PawnBase->Plot3D->Points[i].Color.G; + uint8 b = PawnBase->Plot3D->Points[i].Color.B; + DrawLine(x0, y0, x1, y1, r, g, b, 255); + DrawLine(x1, y1, x2, y2, r, g, b, 255); + DrawLine(x2, y2, x3, y3, r, g, b, 255); + DrawLine(x3, y3, x4, y4, r, g, b, 255); + DrawLine(x4, y4, x5, y5, r, g, b, 255); + } + + UpdateCanvas(); +} + void UPlotCanvas::DrawDot(const int32 pixelCoordX, const int32 pixelCoordY) { uint8* canvasPixelPtr = canvasPixelData.get(); @@ -88,16 +120,21 @@ void UPlotCanvas::DrawDot(const int32 pixelCoordX, const int32 pixelCoordY) { int32 tx = pixelCoordX + px; int32 ty = pixelCoordY + py; - if (tx >= 0 && tx < canvasWidth && ty >= 0 && ty < canvasHeight) - { - canvasPixelPtr = canvasPixelData.get() + (tx + ty * canvasWidth) * bytesPerPixel; - setPixelColor(canvasPixelPtr, *(canvasBrushPixelPtr + 2), *(canvasBrushPixelPtr + 1), *(canvasBrushPixelPtr), *(canvasBrushPixelPtr + 3)); - } + DrawPixel(tx, ty, *(canvasBrushPixelPtr + 2), *(canvasBrushPixelPtr + 1), *(canvasBrushPixelPtr), *(canvasBrushPixelPtr + 3)); } } } } +void UPlotCanvas::DrawPixel(const int32 x, const int32 y, const uint8 r, const uint8 g, const uint8 b, const uint8 a) +{ + if (x >= 0 && x < canvasWidth && y >= 0 && y < canvasHeight) + { + uint8* canvasPixelPtr = canvasPixelData.get() + (x + y * canvasWidth) * bytesPerPixel; + setPixelColor(canvasPixelPtr, r, g, b, a); + } +} + void UPlotCanvas::ClearCanvas() { uint8* canvasPixelPtr = canvasPixelData.get(); @@ -123,4 +160,49 @@ void UPlotCanvas::setPixelColor(uint8*& pointer, uint8 red, uint8 green, uint8 b *(pointer + 1) = green; //g *(pointer + 2) = red; //r *(pointer + 3) = alpha; //a +} + +void UPlotCanvas::DrawLine(int32 x1, int32 y1, int32 x2, int32 y2, const uint8 r, const uint8 g, const uint8 b, const uint8 a) +{ + // Bresenham's line algorithm + const bool steep = (fabs(y2 - y1) > fabs(x2 - x1)); + if (steep) + { + std::swap(x1, y1); + std::swap(x2, y2); + } + + if (x1 > x2) + { + std::swap(x1, x2); + std::swap(y1, y2); + } + + const float dx = x2 - x1; + const float dy = fabs(y2 - y1); + + float error = dx / 2.0f; + const int ystep = (y1 < y2) ? 1 : -1; + int y = (int)y1; + + const int maxX = (int)x2; + + for (int x = (int)x1; x < maxX; x++) + { + if (steep) + { + DrawPixel(y, x, r, g, b, a); + } + else + { + DrawPixel(x, y, r, g, b, a); + } + + error -= dy; + if (error < 0) + { + y += ystep; + error += dx; + } + } } \ No newline at end of file diff --git a/Source/ImmersiveAnalytics/PlotCanvas.h b/Source/ImmersiveAnalytics/PlotCanvas.h index 764da80548433e00089ffee23b146911e85f750d..5fb7f103de697e4eb1258aad7b76a7504f1f1d3e 100644 --- a/Source/ImmersiveAnalytics/PlotCanvas.h +++ b/Source/ImmersiveAnalytics/PlotCanvas.h @@ -34,9 +34,18 @@ public: UFUNCTION(BlueprintCallable, Category = DrawingTools) void DrawFromData(); + UFUNCTION(BlueprintCallable, Category = DrawingTools) + void DrawParallelCoordinatesPlot(); + UFUNCTION(BlueprintCallable, Category = DrawingTools) void DrawDot(const int32 pixelCoordX, const int32 pixelCoordY); + UFUNCTION(BlueprintCallable, Category = DrawingTools) + void DrawPixel(const int32 x, const int32 y, const uint8 r, const uint8 g, const uint8 b, const uint8 a); + + UFUNCTION(BlueprintCallable) + void DrawLine(int32 x1, int32 y1, int32 x2, int32 y2, const uint8 r, const uint8 g, const uint8 b, const uint8 a); + private: // canvas diff --git a/Source/ImmersiveAnalytics/PlotRenderTarget.cpp b/Source/ImmersiveAnalytics/PlotRenderTarget.cpp index fa5c20d147a180c47253faeecb5f0b596f3ce050..bb7e6003a66ac6c54aa11e2918a9c20e1799fb1b 100644 --- a/Source/ImmersiveAnalytics/PlotRenderTarget.cpp +++ b/Source/ImmersiveAnalytics/PlotRenderTarget.cpp @@ -26,7 +26,7 @@ void UPlotRenderTarget::OnUpdate(UCanvas * Canvas, int32 Width, int32 Height) for (int i = 0; i < PawnBase->Plot3D->Points.Num(); ++i) { FVector2D Location = FVector2D(PawnBase->Plot3D->Points[i].Location.X * 10000 + Width / 2, PawnBase->Plot3D->U[i] * 5 + Height / 2); - FVector2D LocationB = Location + FVector2D(0, 100); + FVector2D LocationB = Location + FVector2D(0, 1); /* * Still not fast enough. Using other way to draw the graph.