// Copyright Epic Games, Inc. All Rights Reserved. #include "Dataflow/GeometryCollectionArrayNodes.h" #include "Dataflow/DataflowCore.h" //#include UE_INLINE_GENERATED_CPP_BY_NAME(GeometryCollectionArrayNodes) namespace UE::Dataflow { void GeometryCollectionArrayNodes() { DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FFloatArrayToIntArrayDataflowNode); DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FBoolArrayToFaceSelectionDataflowNode); DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FFloatArrayToVertexSelectionDataflowNode); DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FFloatArrayNormalizeDataflowNode); DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FVectorArrayNormalizeDataflowNode); DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FUnionIntArraysDataflowNode); DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FRemoveFloatArrayElementDataflowNode); DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FFloatArrayComputeStatisticsDataflowNode); DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FRandomizeFloatArrayDataflowNode); DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FDataflowGetArraySizeNode); DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FDataflowGetArrayElementNode); DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FDataflowMakeManagedArrayCollectionArrayNode); // Deprecated nodes DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FGetFloatArrayElementDataflowNode); DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FGetArrayElementDataflowNode); DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FGetNumArrayElementsDataflowNode); } } void FGetFloatArrayElementDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const { if (Out->IsA(&FloatValue)) { const TArray& InArray = GetValue(Context, &FloatArray); const int32& InIndex = GetValue(Context, &Index); const float OutputValue = InArray.IsValidIndex(InIndex) ? InArray[InIndex] : 0.0f; SetValue(Context, OutputValue, &FloatValue); } } void FFloatArrayToIntArrayDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const { if (Out->IsA>(&IntArray)) { TArray FloatVal = GetValue>(Context, &FloatArray); TArray RetVal; RetVal.SetNumUninitialized(FloatVal.Num()); if (Function == EFloatArrayToIntArrayFunctionEnum::Dataflow_FloatToInt_Function_Floor) { for (int32 i = 0; i < FloatVal.Num(); i++) { RetVal[i] = FMath::FloorToInt32(FloatVal[i]); } } else if (Function == EFloatArrayToIntArrayFunctionEnum::Dataflow_FloatToInt_Function_Ceil) { for (int32 i = 0; i < FloatVal.Num(); i++) { RetVal[i] = FMath::CeilToInt32(FloatVal[i]); } } else if (Function == EFloatArrayToIntArrayFunctionEnum::Dataflow_FloatToInt_Function_Round) { for (int32 i = 0; i < FloatVal.Num(); i++) { RetVal[i] = FMath::RoundToInt32(FloatVal[i]); } } else if (Function == EFloatArrayToIntArrayFunctionEnum::Dataflow_FloatToInt_Function_Truncate) { for (int32 i = 0; i < FloatVal.Num(); i++) { RetVal[i] = int32(FMath::TruncToFloat(FloatVal[i])); } } else if (Function == EFloatArrayToIntArrayFunctionEnum::Dataflow_FloatToInt_NonZeroToIndex) { int32 RetValIndex = 0; for (int32 i = 0; i < FloatVal.Num(); i++) { if (FloatVal[i] != 0.0) { RetVal[RetValIndex] = i; RetValIndex++; } } RetVal.SetNum(RetValIndex); } else if (Function == EFloatArrayToIntArrayFunctionEnum::Dataflow_FloatToInt_ZeroToIndex) { int32 RetValIndex = 0; for (int32 i = 0; i < FloatVal.Num(); i++) { if (FloatVal[i] == 0.0) { RetVal[RetValIndex] = i; RetValIndex++; } } RetVal.SetNum(RetValIndex); } SetValue(Context, MoveTemp(RetVal), &IntArray); } } void FGetArrayElementDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const { if (Out->IsA(&Point)) { const TArray& Array = GetValue>(Context, &Points); if (Array.Num() > 0 && Index >= 0 && Index < Array.Num()) { SetValue(Context, Array[Index], &Point); return; } SetValue(Context, FVector(0.f), &Point); } } void FGetNumArrayElementsDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const { if (Out->IsA(&NumElements)) { if (IsConnected>(&FloatArray)) { SetValue(Context, GetValue>(Context, &FloatArray).Num(), &NumElements); return; } else if (IsConnected>(&IntArray)) { SetValue(Context, GetValue>(Context, &IntArray).Num(), &NumElements); return; } else if (IsConnected>(&Points)) { SetValue(Context, GetValue>(Context, &Points).Num(), &NumElements); return; } else if (IsConnected>(&Vector3fArray)) { SetValue(Context, GetValue>(Context, &Vector3fArray).Num(), &NumElements); return; } SetValue(Context, 0, &NumElements); } } void FBoolArrayToFaceSelectionDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const { if (Out->IsA(&FaceSelection)) { const TArray& InBoolAttributeData = GetValue>(Context, &BoolAttributeData); FDataflowFaceSelection NewFaceSelection; NewFaceSelection.Initialize(InBoolAttributeData.Num(), false); NewFaceSelection.SetFromArray(InBoolAttributeData); SetValue(Context, MoveTemp(NewFaceSelection), &FaceSelection); } } void FFloatArrayToVertexSelectionDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const { if (Out->IsA(&VertexSelection)) { const TArray& InFloatArray = GetValue>(Context, &FloatArray); FDataflowVertexSelection NewVertexSelection; NewVertexSelection.Initialize(InFloatArray.Num(), false); for (int32 Idx = 0; Idx < InFloatArray.Num(); ++Idx) { if (Operation == ECompareOperation1Enum::Dataflow_Compare_Equal) { if (InFloatArray[Idx] == Threshold) { NewVertexSelection.SetSelected(Idx); } } else if (Operation == ECompareOperation1Enum::Dataflow_Compare_Smaller) { if (InFloatArray[Idx] < Threshold) { NewVertexSelection.SetSelected(Idx); } } else if (Operation == ECompareOperation1Enum::Dataflow_Compare_SmallerOrEqual) { if (InFloatArray[Idx] <= Threshold) { NewVertexSelection.SetSelected(Idx); } } else if (Operation == ECompareOperation1Enum::Dataflow_Compare_Greater) { if (InFloatArray[Idx] > Threshold) { NewVertexSelection.SetSelected(Idx); } } else if (Operation == ECompareOperation1Enum::Dataflow_Compare_GreaterOrEqual) { if (InFloatArray[Idx] >= Threshold) { NewVertexSelection.SetSelected(Idx); } } } SetValue(Context, MoveTemp(NewVertexSelection), &VertexSelection); } } void FFloatArrayNormalizeDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const { if (Out->IsA>(&OutFloatArray)) { const TArray& InInFloatArray = GetValue>(Context, &InFloatArray); const FDataflowVertexSelection& InSelection = GetValue(Context, &Selection); const float InMinRange = GetValue(Context, &MinRange); const float InMaxRange = GetValue(Context, &MaxRange); const int32 NumElems = InFloatArray.Num(); TArray NewFloatArray; NewFloatArray.Init(false, NumElems); if (IsConnected(&Selection)) { if (InInFloatArray.Num() == InSelection.Num()) { // Compute Min/Max float MinValue = 1e9, MaxValue = 1e-9; for (int32 Idx = 0; Idx < NumElems; ++Idx) { if (InSelection.IsSelected(Idx)) { if (InInFloatArray[Idx] < MinValue) { MinValue = InInFloatArray[Idx]; } if (InInFloatArray[Idx] > MaxValue) { MaxValue = InInFloatArray[Idx]; } } } for (int32 Idx = 0; Idx < NumElems; ++Idx) { if (InSelection.IsSelected(Idx)) { // Normalize it NewFloatArray[Idx] = (NewFloatArray[Idx] - MinValue) / (MaxValue - MinValue); // Transform it into (MinRange, MaxRange) NewFloatArray[Idx] = InMinRange + NewFloatArray[Idx] * (InMaxRange - InMinRange); } } SetValue(Context, MoveTemp(NewFloatArray), &OutFloatArray); return; } } else { // Compute Min/Max float MinValue = 1e9, MaxValue = 1e-9; for (int32 Idx = 0; Idx < NumElems; ++Idx) { if (InInFloatArray[Idx] < MinValue) { MinValue = InInFloatArray[Idx]; } if (InInFloatArray[Idx] > MaxValue) { MaxValue = InInFloatArray[Idx]; } } for (int32 Idx = 0; Idx < NumElems; ++Idx) { // Normalize it NewFloatArray[Idx] = (NewFloatArray[Idx] - MinValue) / (MaxValue - MinValue); // Transform it into (MinRange, MaxRange) NewFloatArray[Idx] = InMinRange + NewFloatArray[Idx] * (InMaxRange - InMinRange); } SetValue(Context, MoveTemp(NewFloatArray), &OutFloatArray); return; } SetValue(Context, TArray(), &OutFloatArray); } } void FVectorArrayNormalizeDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const { if (Out->IsA>(&OutVectorArray)) { const TArray& InInVectorArray = GetValue>(Context, &InVectorArray); const FDataflowVertexSelection& InSelection = GetValue(Context, &Selection); const float InMagnitude = GetValue(Context, &Magnitude); const int32 NumElems = InInVectorArray.Num(); TArray NewVectorArray; NewVectorArray.Init(FVector(0.f), NumElems); if (IsConnected(&Selection)) { if (InInVectorArray.Num() == InSelection.Num()) { for (int32 Idx = 0; Idx < NumElems; ++Idx) { FVector Vector = InInVectorArray[Idx]; if (InSelection.IsSelected(Idx)) { Vector.Normalize(); Vector *= InMagnitude; NewVectorArray[Idx] = Vector; } } SetValue(Context, MoveTemp(NewVectorArray), &OutVectorArray); return; } } else { for (int32 Idx = 0; Idx < NumElems; ++Idx) { FVector Vector = InInVectorArray[Idx]; Vector.Normalize(); Vector *= InMagnitude; NewVectorArray[Idx] = Vector; } SetValue(Context, MoveTemp(NewVectorArray), &OutVectorArray); return; } SetValue>(Context, TArray(), &OutVectorArray); } } void FUnionIntArraysDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const { if (Out->IsA>(&OutArray)) { TArray Array1 = GetValue>(Context, &InArray1); TArray Array2 = GetValue>(Context, &InArray2); TArray OutputArray; for (int32 i = 0; i < Array1.Num(); i++) { OutputArray.AddUnique(Array1[i]); } for (int32 i = 0; i < Array2.Num(); i++) { OutputArray.AddUnique(Array2[i]); } SetValue(Context, MoveTemp(OutputArray), &OutArray); } } void FRemoveFloatArrayElementDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const { if (Out->IsA(&FloatArray)) { TArray Array = GetValue>(Context, &FloatArray); if (Array.Num() > 0 && Array.IsValidIndex(Index)) { if (bPreserveOrder) { Array.RemoveAt(Index); } else { Array.RemoveAtSwap(Index, EAllowShrinking::No); } SetValue(Context, Array, &FloatArray); return; } SetValue(Context, Array, &FloatArray); } } // ----------------------------------------------------------------------------------------------- static float ComputeMin(const TArray& FloatArray, TArray& IndexArr) { float MinVal = TNumericLimits::Max(); for (int32 Idx = 0; Idx < FloatArray.Num(); ++Idx) { if (FloatArray[Idx] < MinVal) { MinVal = FloatArray[Idx]; } } for (int32 Idx = 0; Idx < FloatArray.Num(); ++Idx) { if (FloatArray[Idx] == MinVal) { IndexArr.Add(Idx); } } return MinVal; } static float ComputeMax(const TArray& FloatArray, TArray& IndexArr) { float MaxVal = TNumericLimits::Min(); for (int32 Idx = 0; Idx < FloatArray.Num(); ++Idx) { if (FloatArray[Idx] > MaxVal) { MaxVal = FloatArray[Idx]; } } for (int32 Idx = 0; Idx < FloatArray.Num(); ++Idx) { if (FloatArray[Idx] == MaxVal) { IndexArr.Add(Idx); } } return MaxVal; } static float ComputeMean(const TArray& FloatArray, TArray& IndexArr) { double SumVal = 0.f; for (int32 Idx = 0; Idx < FloatArray.Num(); ++Idx) { SumVal += FloatArray[Idx]; } return (float)(SumVal / (double)FloatArray.Num()); } static float ComputeMedian(TArray FloatArray, TArray& IndexArr) { FloatArray.Sort(); float MedianVal; int32 NumElems = FloatArray.Num(); if (NumElems % 2 == 0) { MedianVal = (FloatArray[NumElems / 2 - 1] + FloatArray[NumElems / 2]) / 2.f; IndexArr.Add(NumElems / 2 - 1); IndexArr.Add(NumElems / 2); } else { MedianVal = FloatArray[(NumElems - 1) / 2]; IndexArr.Add((NumElems - 1) / 2); } return MedianVal; } static float ComputeMode(const TArray& FloatArray, TArray& IndexArr) { float MaxVal = 0.f; int32 MaxCount = 0; for (int32 Idx1 = 0; Idx1 < FloatArray.Num(); ++Idx1) { int32 Count = 0; for (int32 Idx2 = 0; Idx2 < FloatArray.Num(); ++Idx2) { if (FloatArray[Idx2] == FloatArray[Idx1]) { Count++; } if (Count > MaxCount) { MaxCount = Count; MaxVal = FloatArray[Idx1]; } } } for (int32 Idx = 0; Idx < FloatArray.Num(); ++Idx) { if (FloatArray[Idx] == MaxVal) { IndexArr.Add(Idx); } } return MaxVal; } static float ComputeSum(const TArray& FloatArray, TArray& IndexArr) { double SumVal = 0.f; for (int32 Idx = 0; Idx < FloatArray.Num(); ++Idx) { SumVal += FloatArray[Idx]; } return (float)SumVal; } // ----------------------------------------------------------------------------------------------- void FFloatArrayComputeStatisticsDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const { if (Out->IsA(&Value) || Out->IsA(&Indices)) { const TArray& InFloatArray = GetValue(Context, &FloatArray); const FDataflowTransformSelection& InTransformSelection = GetValue(Context, &TransformSelection); TArray Array; if (IsConnected(&TransformSelection) && InTransformSelection.Num() == InFloatArray.Num()) { for (int32 Idx = 0; Idx < InFloatArray.Num(); ++Idx) { if (InTransformSelection.IsSelected(Idx)) { Array.Add(InFloatArray[Idx]); } } } else { for (int32 Idx = 0; Idx < InFloatArray.Num(); ++Idx) { Array.Add(InFloatArray[Idx]); } } float OutValue; TArray OutIndices; switch (OperationName) { case EStatisticsOperationEnum::Dataflow_EStatisticsOperationEnum_Min: OutValue = ComputeMin(Array, OutIndices); break; case EStatisticsOperationEnum::Dataflow_EStatisticsOperationEnum_Max: OutValue = ComputeMax(Array, OutIndices); break; case EStatisticsOperationEnum::Dataflow_EStatisticsOperationEnum_Mean: OutValue = ComputeMean(Array, OutIndices); break; case EStatisticsOperationEnum::Dataflow_EStatisticsOperationEnum_Median: OutValue = ComputeMedian(Array, OutIndices); break; case EStatisticsOperationEnum::Dataflow_EStatisticsOperationEnum_Mode: OutValue = ComputeMode(Array, OutIndices); break; case EStatisticsOperationEnum::Dataflow_EStatisticsOperationEnum_Sum: OutValue = ComputeSum(Array, OutIndices); break; } SetValue(Context, OutValue, &Value); SetValue(Context, OutIndices, &Indices); } } void FRandomizeFloatArrayDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const { if (Out->IsA(&FloatArray)) { const TArray InFloatArray = GetValue(Context, &FloatArray); const float InRandomRangeMin = GetValue(Context, &RandomRangeMin); const float InRandomRangeMax = GetValue(Context, &RandomRangeMax); const int32 InRandomSeed = GetValue(Context, &RandomSeed); TArray OutFloatArray; FRandomStream RandStream(InRandomSeed); const int32 NumPoints = InFloatArray.Num(); if (NumPoints > 0) { OutFloatArray.Reserve(NumPoints); for (int32 Idx = 0; Idx < NumPoints; ++Idx) { OutFloatArray.Emplace(RandStream.FRandRange(InRandomRangeMin, InRandomRangeMax)); } } SetValue(Context, MoveTemp(OutFloatArray), &FloatArray); } } /////////////////////////////////////////////////////////////////////////////////////////////// FDataflowGetArraySizeNode::FDataflowGetArraySizeNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid) : FDataflowNode(InParam, InGuid) { RegisterInputConnection(&Array); RegisterOutputConnection(&Size); } void FDataflowGetArraySizeNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const { if (Out->IsA(&Size)) { SetArraySizeFromInput(Context, &Array, &Size); } } /////////////////////////////////////////////////////////////////////////////////////////////// FDataflowGetArrayElementNode::FDataflowGetArrayElementNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid) : FDataflowNode(InParam, InGuid) { static FName ArrayElementDependencyGroup("ArrayElement"); RegisterInputConnection(&Array) .SetTypeDependencyGroup(ArrayElementDependencyGroup); RegisterInputConnection(&Index); RegisterOutputConnection(&Array, &Array) .SetTypeDependencyGroup(ArrayElementDependencyGroup); RegisterOutputConnection(&Element) .SetTypeDependencyGroup(ArrayElementDependencyGroup); } FName FDataflowGetArrayElementNode::GetDependentConnectionType(const FDataflowConnection& SourceConnection, const FDataflowConnection& DependentConnection) const { if (SourceConnection.IsA(&Array) && DependentConnection.IsA(&Element)) { return FDataflowArrayTypePolicy::GetElementType(SourceConnection.GetType()); } else if (SourceConnection.IsA(&Element) && DependentConnection.IsA(&Array)) { return FDataflowArrayTypePolicy::GetArrayType(SourceConnection.GetType()); } // default for all the rest return FDataflowNode::GetDependentConnectionType(SourceConnection, DependentConnection); } void FDataflowGetArrayElementNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const { if (Out->IsA(&Array)) { ForwardInput(Context, &Array, &Array); } else if (Out->IsA(&Element)) { const int32 InIndex = GetValue(Context, &Index); SetArrayElementFromInput(Context, &Array, InIndex, &Element); } } /////////////////////////////////////////////////////////////////////////////////////////////// FDataflowMakeManagedArrayCollectionArrayNode::FDataflowMakeManagedArrayCollectionArrayNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid) : FDataflowNode(InParam, InGuid) { static FName ArrayElementDependencyGroup("ArrayElement"); RegisterInputConnection(&Array); RegisterInputConnection(&Element); RegisterOutputConnection(&Array, &Array); } void FDataflowMakeManagedArrayCollectionArrayNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const { if (Out->IsA(&Array)) { if (IsConnected(&Element)) { TArray OutArray = GetValue(Context, &Array); OutArray.Emplace(GetValue(Context, &Element)); SetValue(Context, MoveTemp(OutArray), &Array); return; } SafeForwardInput(Context, &Array, &Array); } }