Files
UnrealEngine/Engine/Plugins/Experimental/GeometryCollectionPlugin/Source/GeometryCollectionNodes/Private/Dataflow/GeometryCollectionSelectionNodes.cpp
2025-05-18 13:04:45 +08:00

1847 lines
68 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Dataflow/GeometryCollectionSelectionNodes.h"
#include "Dataflow/DataflowCore.h"
#if WITH_EDITOR
#include "Dataflow/DataflowRenderingViewMode.h"
#endif
#include "Dataflow/DataflowDebugDrawInterface.h"
#include "Engine/StaticMesh.h"
#include "GeometryCollection/GeometryCollectionObject.h"
#include "GeometryCollection/ManagedArrayCollection.h"
#include "GeometryCollection/GeometryCollection.h"
#include "GeometryCollection/GeometryCollectionEngineUtility.h"
#include "GeometryCollection/GeometryCollectionEngineConversion.h"
#include "Logging/LogMacros.h"
#include "Templates/SharedPointer.h"
#include "UObject/UnrealTypePrivate.h"
#include "DynamicMeshToMeshDescription.h"
#include "MeshDescriptionToDynamicMesh.h"
#include "StaticMeshAttributes.h"
#include "DynamicMeshEditor.h"
#include "Operations/MeshBoolean.h"
#include "EngineGlobals.h"
#include "GeometryCollection/GeometryCollectionAlgo.h"
#include "GeometryCollection/GeometryCollectionClusteringUtility.h"
#include "GeometryCollection/GeometryCollectionConvexUtility.h"
#include "Voronoi/Voronoi.h"
#include "PlanarCut.h"
#include "GeometryCollection/GeometryCollectionProximityUtility.h"
#include "FractureEngineClustering.h"
#include "FractureEngineSelection.h"
#include "GeometryCollection/Facades/CollectionTransformSelectionFacade.h"
#include "GeometryCollection/Facades/CollectionHierarchyFacade.h"
#include "Internationalization/Regex.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(GeometryCollectionSelectionNodes)
namespace UE::Dataflow
{
void GeometryCollectionSelectionNodes()
{
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionTransformSelectionAllDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionTransformSelectionInfoDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionTransformSelectionNoneDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionTransformSelectionRandomDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionTransformSelectionRootDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionTransformSelectionCustomDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionTransformSelectionCustomDataflowNode_v2);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionTransformSelectionFromIndexArrayDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionTransformSelectionParentDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionTransformSelectionByPercentageDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionTransformSelectionChildrenDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionTransformSelectionSiblingsDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionTransformSelectionLevelDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionTransformSelectionTargetLevelDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionTransformSelectionContactDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionTransformSelectionLeafDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionTransformSelectionClusterDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionTransformSelectionClusterDataflowNode_v2);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionTransformSelectionBySizeDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionTransformSelectionByVolumeDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionTransformSelectionInBoxDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionTransformSelectionInSphereDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionTransformSelectionByFloatAttrDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FSelectFloatArrayIndicesInRangeDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionTransformSelectionByIntAttrDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionVertexSelectionCustomDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionFaceSelectionCustomDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionSelectionConvertDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionVertexSelectionByPercentageDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionVertexSelectionSetOperationDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionSelectionByAttrDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FGeometrySelectionToVertexSelectionDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionSelectInternalFacesDataflowNode);
// generic input nodes
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionSelectionSetOperationDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionSelectionInvertDataflowNode);
// deprecated
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionTransformSelectionInvertDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionFaceSelectionInvertDataflowNode);
DATAFLOW_NODE_REGISTER_CREATION_FACTORY(FCollectionTransformSelectionSetOperationDataflowNode);
}
}
void FCollectionTransformSelectionAllDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FDataflowTransformSelection>(&TransformSelection))
{
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
GeometryCollection::Facades::FCollectionTransformSelectionFacade TransformSelectionFacade(InCollection);
const TArray<int32>& SelectionArr = TransformSelectionFacade.SelectAll();
FDataflowTransformSelection NewTransformSelection;
NewTransformSelection.Initialize(InCollection.NumElements(FGeometryCollection::TransformGroup), false);
NewTransformSelection.SetFromArray(SelectionArr);
SetValue(Context, MoveTemp(NewTransformSelection), &TransformSelection);
}
else if (Out->IsA<FManagedArrayCollection>(&Collection))
{
SafeForwardInput(Context, &Collection, &Collection);
}
}
void FCollectionTransformSelectionSetOperationDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FDataflowTransformSelection>(&TransformSelection))
{
const FDataflowTransformSelection& InTransformSelectionA = GetValue<FDataflowTransformSelection>(Context, &TransformSelectionA);
const FDataflowTransformSelection& InTransformSelectionB = GetValue<FDataflowTransformSelection>(Context, &TransformSelectionB);
FDataflowTransformSelection NewTransformSelection;
if (InTransformSelectionA.Num() == InTransformSelectionB.Num())
{
if (Operation == ESetOperationEnum::Dataflow_SetOperation_AND)
{
InTransformSelectionA.AND(InTransformSelectionB, NewTransformSelection);
}
else if (Operation == ESetOperationEnum::Dataflow_SetOperation_OR)
{
InTransformSelectionA.OR(InTransformSelectionB, NewTransformSelection);
}
else if (Operation == ESetOperationEnum::Dataflow_SetOperation_XOR)
{
InTransformSelectionA.XOR(InTransformSelectionB, NewTransformSelection);
}
else if (Operation == ESetOperationEnum::Dataflow_SetOperation_Subtract)
{
InTransformSelectionA.Subtract(InTransformSelectionB, NewTransformSelection);
}
}
else
{
// ERROR: INPUT TRANSFORMSELECTIONS HAVE DIFFERENT NUMBER OF ELEMENTS
FString ErrorStr = "Input TransformSelections have different number of elements.";
UE_LOG(LogTemp, Error, TEXT("[Dataflow ERROR] %s"), *ErrorStr);
}
SetValue(Context, MoveTemp(NewTransformSelection), &TransformSelection);
}
}
namespace {
struct BoneInfo {
int32 BoneIndex;
int32 Level;
};
}
static void ExpandRecursive(const int32 BoneIndex, int32 Level, const TManagedArray<TSet<int32>>& Children, TArray<BoneInfo>& BoneHierarchy)
{
BoneHierarchy.Add({ BoneIndex, Level });
TSet<int32> ChildrenSet = Children[BoneIndex];
if (ChildrenSet.Num() > 0)
{
for (auto& Child : ChildrenSet)
{
ExpandRecursive(Child, Level + 1, Children, BoneHierarchy);
}
}
}
static void BuildHierarchicalOutput(const TManagedArray<int32>& Parents,
const TManagedArray<TSet<int32>>& Children,
const TManagedArray<FString>& BoneNames,
const FDataflowTransformSelection& TransformSelection,
FString& OutputStr)
{
TArray<BoneInfo> BoneHierarchy;
int32 NumElements = Parents.Num();
for (int32 Index = 0; Index < NumElements; ++Index)
{
if (Parents[Index] == FGeometryCollection::Invalid)
{
ExpandRecursive(Index, 0, Children, BoneHierarchy);
}
}
// Get level max
int32 LevelMax = -1;
int32 BoneNameLengthMax = -1;
for (int32 Idx = 0; Idx < BoneHierarchy.Num(); ++Idx)
{
if (BoneHierarchy[Idx].Level > LevelMax)
{
LevelMax = BoneHierarchy[Idx].Level;
}
int32 BoneNameLength = BoneNames[Idx].Len();
if (BoneNameLength > BoneNameLengthMax)
{
BoneNameLengthMax = BoneNameLength;
}
}
const int32 BoneIndexWidth = 2 + LevelMax * 2 + 6;
const int32 BoneNameWidth = BoneNameLengthMax + 2;
const int32 SelectedWidth = 10;
for (int32 Idx = 0; Idx < BoneHierarchy.Num(); ++Idx)
{
FString BoneIndexStr, BoneNameStr;
BoneIndexStr.Reserve(BoneIndexWidth);
BoneNameStr.Reserve(BoneNameWidth);
if (BoneHierarchy[Idx].Level == 0)
{
BoneIndexStr.Appendf(TEXT("[%d]"), BoneHierarchy[Idx].BoneIndex);
}
else
{
BoneIndexStr.Appendf(TEXT(" |"));
for (int32 Idx1 = 0; Idx1 < BoneHierarchy[Idx].Level; ++Idx1)
{
BoneIndexStr.Appendf(TEXT("--"));
}
BoneIndexStr.Appendf(TEXT("[%d]"), BoneHierarchy[Idx].BoneIndex);
}
BoneIndexStr = BoneIndexStr.RightPad(BoneIndexWidth);
BoneNameStr.Appendf(TEXT("%s"), *BoneNames[Idx]);
BoneNameStr = BoneNameStr.RightPad(BoneNameWidth);
OutputStr.Appendf(TEXT("%s%s%s\n\n"), *BoneIndexStr, *BoneNameStr, (TransformSelection.IsSelected(BoneHierarchy[Idx].BoneIndex) ? TEXT("Selected") : TEXT("---")));
}
}
void FCollectionTransformSelectionInfoDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FString>(&String))
{
const FDataflowTransformSelection& InTransformSelection = GetValue<FDataflowTransformSelection>(Context, &TransformSelection);
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
FString OutputStr;
OutputStr.Appendf(TEXT("\n----------------------------------------\n"));
OutputStr.Appendf(TEXT("Number of Elements: %d\n"), InTransformSelection.Num());
// Hierarchical display
if (InCollection.HasGroup(FGeometryCollection::TransformGroup) &&
InCollection.HasAttribute("Parent", FGeometryCollection::TransformGroup) &&
InCollection.HasAttribute("Children", FGeometryCollection::TransformGroup) &&
InCollection.HasAttribute("BoneName", FGeometryCollection::TransformGroup))
{
if (InTransformSelection.Num() == InCollection.NumElements(FGeometryCollection::TransformGroup))
{
const TManagedArray<int32>& Parents = InCollection.GetAttribute<int32>("Parent", FGeometryCollection::TransformGroup);
const TManagedArray<TSet<int32>>& Children = InCollection.GetAttribute<TSet<int32>>("Children", FGeometryCollection::TransformGroup);
const TManagedArray<FString>& BoneNames = InCollection.GetAttribute<FString>("BoneName", FGeometryCollection::TransformGroup);
BuildHierarchicalOutput(Parents, Children, BoneNames, InTransformSelection, OutputStr);
}
else
{
// ERROR: TransformSelection doesn't match the Collection
FString ErrorStr = "TransformSelection doesn't match the Collection.";
UE_LOG(LogTemp, Error, TEXT("[Dataflow ERROR] %s"), *ErrorStr);
}
}
else
// Simple display
{
for (int32 Idx = 0; Idx < InTransformSelection.Num(); ++Idx)
{
OutputStr.Appendf(TEXT("%4d: %s\n"), Idx, (InTransformSelection.IsSelected(Idx) ? TEXT("Selected") : TEXT("---")));
}
}
OutputStr.Appendf(TEXT("----------------------------------------\n"));
SetValue(Context, MoveTemp(OutputStr), &String);
}
}
void FCollectionTransformSelectionNoneDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FDataflowTransformSelection>(&TransformSelection))
{
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
GeometryCollection::Facades::FCollectionTransformSelectionFacade TransformSelectionFacade(InCollection);
const TArray<int32>& SelectionArr = TransformSelectionFacade.SelectNone();
FDataflowTransformSelection NewTransformSelection;
NewTransformSelection.Initialize(InCollection.NumElements(FGeometryCollection::TransformGroup), false);
NewTransformSelection.SetFromArray(SelectionArr);
SetValue(Context, MoveTemp(NewTransformSelection), &TransformSelection);
}
else if (Out->IsA<FManagedArrayCollection>(&Collection))
{
SafeForwardInput(Context, &Collection, &Collection);
}
}
void FCollectionTransformSelectionInvertDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FDataflowTransformSelection>(&TransformSelection))
{
FDataflowTransformSelection InTransformSelection = GetValue<FDataflowTransformSelection>(Context, &TransformSelection);
InTransformSelection.Invert();
SetValue(Context, MoveTemp(InTransformSelection), &TransformSelection);
}
}
void FCollectionTransformSelectionRandomDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FDataflowTransformSelection>(&TransformSelection))
{
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
float RandomSeedVal = GetValue<float>(Context, &RandomSeed);
float RandomThresholdVal = GetValue<float>(Context, &RandomThreshold);
GeometryCollection::Facades::FCollectionTransformSelectionFacade TransformSelectionFacade(InCollection);
const TArray<int32>& SelectionArr = TransformSelectionFacade.SelectRandom(bDeterministic, RandomSeedVal, RandomThresholdVal);
FDataflowTransformSelection NewTransformSelection;
NewTransformSelection.Initialize(InCollection.NumElements(FGeometryCollection::TransformGroup), false);
NewTransformSelection.SetFromArray(SelectionArr);
SetValue(Context, MoveTemp(NewTransformSelection), &TransformSelection);
}
else if (Out->IsA<FManagedArrayCollection>(&Collection))
{
SafeForwardInput(Context, &Collection, &Collection);
}
}
void FCollectionTransformSelectionRootDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FDataflowTransformSelection>(&TransformSelection))
{
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
GeometryCollection::Facades::FCollectionTransformSelectionFacade TransformSelectionFacade(InCollection);
const TArray<int32>& SelectionArr = TransformSelectionFacade.SelectRootBones();
FDataflowTransformSelection NewTransformSelection;
NewTransformSelection.Initialize(InCollection.NumElements(FGeometryCollection::TransformGroup), false);
NewTransformSelection.SetFromArray(SelectionArr);
SetValue(Context, MoveTemp(NewTransformSelection), &TransformSelection);
}
else if (Out->IsA<FManagedArrayCollection>(&Collection))
{
SafeForwardInput(Context, &Collection, &Collection);
}
}
void FCollectionTransformSelectionCustomDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FDataflowTransformSelection>(&TransformSelection))
{
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
if (InCollection.HasGroup(FGeometryCollection::TransformGroup))
{
const int32 NumTransforms = InCollection.NumElements(FGeometryCollection::TransformGroup);
FDataflowTransformSelection NewTransformSelection;
NewTransformSelection.Initialize(NumTransforms, false);
const FString InBoneIndices = GetValue<FString>(Context, &BoneIndicies);
TArray<FString> Indices;
InBoneIndices.ParseIntoArray(Indices, TEXT(" "), true);
for (FString IndexStr : Indices)
{
if (IndexStr.IsNumeric())
{
int32 Index = FCString::Atoi(*IndexStr);
if (Index >= 0 && Index < NumTransforms)
{
NewTransformSelection.SetSelected(Index);
}
else
{
// ERROR: INVALID INDEX
FString ErrorStr = "Invalid specified index found.";
UE_LOG(LogTemp, Error, TEXT("[Dataflow ERROR] %s"), *ErrorStr);
}
}
}
SetValue(Context, MoveTemp(NewTransformSelection), &TransformSelection);
}
else
{
SetValue(Context, FDataflowTransformSelection(), &TransformSelection);
}
}
else if (Out->IsA<FManagedArrayCollection>(&Collection))
{
SafeForwardInput(Context, &Collection, &Collection);
}
}
namespace UE::Dataflow::Private
{
const static uint32 Error_InvalidChars = 1;
const static uint32 Error_InvalidFormatInSegment = 2;
/* e.g. "0, 2, 5-10, 12-15". If left empty, all will be used */
static bool ParseIndicesStr(const FString& InFramesString, TArray<int32>& OutIndices, uint32& OutErrorCode)
{
static const FRegexPattern AllowedCharsPattern(TEXT("^[-,0-9\\s]+$"));
if (!FRegexMatcher(AllowedCharsPattern, InFramesString).FindNext())
{
// Input contains invalid characters
OutErrorCode = Error_InvalidChars;
return false;
}
static const FRegexPattern SingleNumberPattern(TEXT("^\\s*(\\d+)\\s*$"));
static const FRegexPattern RangePattern(TEXT("^\\s*(\\d+)\\s*-\\s*(\\d+)\\s*$"));
TArray<FString> Segments;
InFramesString.ParseIntoArray(Segments, TEXT(","), true);
for (const FString& Segment : Segments)
{
bool bSegmentValid = false;
FRegexMatcher SingleNumberMatcher(SingleNumberPattern, Segment);
if (SingleNumberMatcher.FindNext())
{
const int32 SingleNumber = FCString::Atoi(*SingleNumberMatcher.GetCaptureGroup(1));
OutIndices.Add(SingleNumber);
bSegmentValid = true;
}
else
{
FRegexMatcher RangeMatcher(RangePattern, Segment);
if (RangeMatcher.FindNext())
{
const int32 RangeStart = FCString::Atoi(*RangeMatcher.GetCaptureGroup(1));
const int32 RangeEnd = FCString::Atoi(*RangeMatcher.GetCaptureGroup(2));
for (int32 i = RangeStart; i <= RangeEnd; ++i)
{
OutIndices.Add(i);
}
bSegmentValid = true;
}
}
if (!bSegmentValid)
{
// Invalid format in segment
OutErrorCode = Error_InvalidFormatInSegment;
return false;
}
}
return true;
}
}
FCollectionTransformSelectionCustomDataflowNode_v2::FCollectionTransformSelectionCustomDataflowNode_v2(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid)
: FDataflowNode(InParam, InGuid)
{
RegisterInputConnection(&Collection);
RegisterInputConnection(&BoneIndices);
RegisterOutputConnection(&Collection, &Collection);
RegisterOutputConnection(&TransformSelection);
}
void FCollectionTransformSelectionCustomDataflowNode_v2::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA(&TransformSelection))
{
const FManagedArrayCollection& InCollection = GetValue(Context, &Collection);
if (InCollection.HasGroup(FGeometryCollection::TransformGroup))
{
const int32 NumTransforms = InCollection.NumElements(FGeometryCollection::TransformGroup);
FDataflowTransformSelection NewTransformSelection;
NewTransformSelection.Initialize(NumTransforms, false);
const FString InBoneIndices = GetValue(Context, &BoneIndices);
TArray<int32> Indices;
uint32 ErrorCode = 0;
if (UE::Dataflow::Private::ParseIndicesStr(InBoneIndices, Indices, ErrorCode))
{
NewTransformSelection.SetSelected(Indices);
}
else
{
if (ErrorCode == UE::Dataflow::Private::Error_InvalidChars)
{
// Handle Error
}
else if (ErrorCode == UE::Dataflow::Private::Error_InvalidFormatInSegment)
{
// Handle Error
}
}
SetValue(Context, MoveTemp(NewTransformSelection), &TransformSelection);
}
else
{
SetValue(Context, FDataflowTransformSelection(), &TransformSelection);
}
}
else if (Out->IsA(&Collection))
{
SafeForwardInput(Context, &Collection, &Collection);
}
}
void FCollectionTransformSelectionFromIndexArrayDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA(&TransformSelection))
{
const FManagedArrayCollection& InCollection = GetValue(Context, &Collection);
if (InCollection.HasGroup(FGeometryCollection::TransformGroup))
{
const int32 NumTransforms = InCollection.NumElements(FGeometryCollection::TransformGroup);
const TArray<int32>& InBoneIndices = GetValue(Context, &BoneIndices);
FDataflowTransformSelection NewTransformSelection;
NewTransformSelection.Initialize(NumTransforms, false);
for (int32 SelectedIdx : InBoneIndices)
{
if (SelectedIdx >= 0 && SelectedIdx < NumTransforms)
{
NewTransformSelection.SetSelected(SelectedIdx);
}
else
{
UE_LOG(LogChaos, Error, TEXT("[Dataflow ERROR] Invalid selection index %d is outside valid bone index range [0, %d)"), SelectedIdx, NumTransforms);
}
}
SetValue(Context, MoveTemp(NewTransformSelection), &TransformSelection);
}
else
{
SetValue(Context, FDataflowTransformSelection(), &TransformSelection);
}
}
else if (Out->IsA(&Collection))
{
SafeForwardInput(Context, &Collection, &Collection);
}
}
void FCollectionTransformSelectionParentDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FDataflowTransformSelection>(&TransformSelection))
{
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
FDataflowTransformSelection InTransformSelection = GetValue<FDataflowTransformSelection>(Context, &TransformSelection);
GeometryCollection::Facades::FCollectionTransformSelectionFacade TransformSelectionFacade(InCollection);
TArray<int32> SelectionArr = InTransformSelection.AsArray();
TransformSelectionFacade.SelectParent(SelectionArr);
InTransformSelection.SetFromArray(SelectionArr);
SetValue(Context, MoveTemp(InTransformSelection), &TransformSelection);
}
else if (Out->IsA<FManagedArrayCollection>(&Collection))
{
SafeForwardInput(Context, &Collection, &Collection);
}
}
void FCollectionTransformSelectionByPercentageDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FDataflowTransformSelection>(&TransformSelection))
{
FDataflowTransformSelection InTransformSelection = GetValue<FDataflowTransformSelection>(Context, &TransformSelection);
int32 InPercentage = GetValue<int32>(Context, &Percentage);
float InRandomSeed = GetValue<float>(Context, &RandomSeed);
TArray<int32> SelectionArr = InTransformSelection.AsArray();
GeometryCollection::Facades::FCollectionTransformSelectionFacade::SelectByPercentage(SelectionArr, InPercentage, bDeterministic, InRandomSeed);
InTransformSelection.SetFromArray(SelectionArr);
SetValue(Context, MoveTemp(InTransformSelection), &TransformSelection);
}
}
void FCollectionTransformSelectionChildrenDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FDataflowTransformSelection>(&TransformSelection))
{
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
FDataflowTransformSelection InTransformSelection = GetValue<FDataflowTransformSelection>(Context, &TransformSelection);
GeometryCollection::Facades::FCollectionTransformSelectionFacade TransformSelectionFacade(InCollection);
TArray<int32> SelectionArr = InTransformSelection.AsArray();
TransformSelectionFacade.SelectChildren(SelectionArr);
InTransformSelection.SetFromArray(SelectionArr);
SetValue(Context, MoveTemp(InTransformSelection), &TransformSelection);
}
else if (Out->IsA<FManagedArrayCollection>(&Collection))
{
SafeForwardInput(Context, &Collection, &Collection);
}
}
void FCollectionTransformSelectionSiblingsDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FDataflowTransformSelection>(&TransformSelection))
{
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
FDataflowTransformSelection InTransformSelection = GetValue<FDataflowTransformSelection>(Context, &TransformSelection);
GeometryCollection::Facades::FCollectionTransformSelectionFacade TransformSelectionFacade(InCollection);
TArray<int32> SelectionArr = InTransformSelection.AsArray();
TransformSelectionFacade.SelectSiblings(SelectionArr);
InTransformSelection.SetFromArray(SelectionArr);
SetValue(Context, MoveTemp(InTransformSelection), &TransformSelection);
}
else if (Out->IsA<FManagedArrayCollection>(&Collection))
{
SafeForwardInput(Context, &Collection, &Collection);
}
}
void FCollectionTransformSelectionLevelDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA(&TransformSelection) || Out->IsA(&Collection))
{
FManagedArrayCollection OutCollection = GetValue(Context, &Collection);
FDataflowTransformSelection InTransformSelection = GetValue(Context, &TransformSelection);
// make sure there's a level attribute
Chaos::Facades::FCollectionHierarchyFacade HierarchyFacade(OutCollection);
if (!HierarchyFacade.HasLevelAttribute())
{
HierarchyFacade.GenerateLevelAttribute();
}
GeometryCollection::Facades::FCollectionTransformSelectionFacade TransformSelectionFacade(OutCollection);
TArray<int32> SelectionArr = InTransformSelection.AsArray();
TransformSelectionFacade.SelectLevel(SelectionArr);
InTransformSelection.SetFromArray(SelectionArr);
SetValue(Context, MoveTemp(InTransformSelection), &TransformSelection);
SetValue(Context, MoveTemp(OutCollection), &Collection);
}
}
void FCollectionTransformSelectionTargetLevelDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA(&TransformSelection) || Out->IsA(&Collection))
{
FManagedArrayCollection OutCollection = GetValue(Context, &Collection);
// make sure there's a level attribute
Chaos::Facades::FCollectionHierarchyFacade HierarchyFacade(OutCollection);
if (!HierarchyFacade.HasLevelAttribute())
{
HierarchyFacade.GenerateLevelAttribute();
}
GeometryCollection::Facades::FCollectionTransformSelectionFacade TransformSelectionFacade(OutCollection);
const int32 InTargetLevel = GetValue(Context, &TargetLevel);
const TArray<int32> AllAtLevel = TransformSelectionFacade.GetBonesExactlyAtLevel(InTargetLevel, bSkipEmbedded);
FDataflowTransformSelection NewTransformSelection;
NewTransformSelection.Initialize(OutCollection.NumElements(FGeometryCollection::TransformGroup), false);
NewTransformSelection.SetFromArray(AllAtLevel);
SetValue(Context, MoveTemp(NewTransformSelection), &TransformSelection);
SetValue(Context, MoveTemp(OutCollection), &Collection);
}
}
void FCollectionTransformSelectionContactDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FDataflowTransformSelection>(&TransformSelection))
{
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
FDataflowTransformSelection InTransformSelection = GetValue<FDataflowTransformSelection>(Context, &TransformSelection);
GeometryCollection::Facades::FCollectionTransformSelectionFacade TransformSelectionFacade(InCollection);
TArray<int32> SelectionArr = InTransformSelection.AsArray();
TransformSelectionFacade.SelectContact(SelectionArr, bAllowContactInParentLevels);
InTransformSelection.SetFromArray(SelectionArr);
SetValue(Context, MoveTemp(InTransformSelection), &TransformSelection);
}
else if (Out->IsA<FManagedArrayCollection>(&Collection))
{
SafeForwardInput(Context, &Collection, &Collection);
}
}
void FCollectionTransformSelectionLeafDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FDataflowTransformSelection>(&TransformSelection))
{
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
GeometryCollection::Facades::FCollectionTransformSelectionFacade TransformSelectionFacade(InCollection);
const TArray<int32>& SelectionArr = TransformSelectionFacade.SelectLeaf();
FDataflowTransformSelection NewTransformSelection;
NewTransformSelection.Initialize(InCollection.NumElements(FGeometryCollection::TransformGroup), false);
NewTransformSelection.SetFromArray(SelectionArr);
SetValue(Context, MoveTemp(NewTransformSelection), &TransformSelection);
}
else if (Out->IsA<FManagedArrayCollection>(&Collection))
{
SafeForwardInput(Context, &Collection, &Collection);
}
}
void FCollectionTransformSelectionClusterDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA(&TransformSelection))
{
const FManagedArrayCollection& InCollection = GetValue(Context, &Collection);
GeometryCollection::Facades::FCollectionTransformSelectionFacade TransformSelectionFacade(InCollection);
// this node used to use SelectCluster() but this was buggy and woudl select the leaves instead
// for this reason this node is now deprecated and we need to keep it doing what it sued to : SelectLeaf()
// version 2 of the node properly use the right way
const TArray<int32>& SelectionArr = TransformSelectionFacade.SelectLeaf(); // used to be buggy SelectCluster() - see comment above
FDataflowTransformSelection NewTransformSelection;
NewTransformSelection.Initialize(InCollection.NumElements(FGeometryCollection::TransformGroup), false);
NewTransformSelection.SetFromArray(SelectionArr);
SetValue(Context, MoveTemp(NewTransformSelection), &TransformSelection);
}
else if (Out->IsA(&Collection))
{
SafeForwardInput(Context, &Collection, &Collection);
}
}
void FCollectionTransformSelectionClusterDataflowNode_v2::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA(&TransformSelection))
{
const FManagedArrayCollection& InCollection = GetValue(Context, &Collection);
GeometryCollection::Facades::FCollectionTransformSelectionFacade TransformSelectionFacade(InCollection);
const TArray<int32>& SelectionArr = TransformSelectionFacade.SelectCluster();
FDataflowTransformSelection NewTransformSelection;
NewTransformSelection.Initialize(InCollection.NumElements(FGeometryCollection::TransformGroup), false);
NewTransformSelection.SetFromArray(SelectionArr);
SetValue(Context, MoveTemp(NewTransformSelection), &TransformSelection);
}
else if (Out->IsA(&Collection))
{
SafeForwardInput(Context, &Collection, &Collection);
}
}
void FCollectionTransformSelectionBySizeDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FDataflowTransformSelection>(&TransformSelection))
{
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
float InSizeMin = GetValue<float>(Context, &SizeMin);
float InSizeMax = GetValue<float>(Context, &SizeMax);
bool bInsideRange = RangeSetting == ERangeSettingEnum::Dataflow_RangeSetting_InsideRange;
GeometryCollection::Facades::FCollectionTransformSelectionFacade TransformSelectionFacade(InCollection);
const TArray<int32>& SelectionArr = TransformSelectionFacade.SelectBySize(InSizeMin, InSizeMax, bInclusive, bInsideRange, bUseRelativeSize);
FDataflowTransformSelection NewTransformSelection;
NewTransformSelection.Initialize(InCollection.NumElements(FGeometryCollection::TransformGroup), false);
NewTransformSelection.SetFromArray(SelectionArr);
SetValue(Context, MoveTemp(NewTransformSelection), &TransformSelection);
}
else if (Out->IsA<FManagedArrayCollection>(&Collection))
{
SafeForwardInput(Context, &Collection, &Collection);
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////
void FCollectionTransformSelectionByVolumeDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FDataflowTransformSelection>(&TransformSelection))
{
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
float InVolumeMin = GetValue<float>(Context, &VolumeMin);
float InVolumeMax = GetValue<float>(Context, &VolumeMax);
bool bInsideRange = RangeSetting == ERangeSettingEnum::Dataflow_RangeSetting_InsideRange;
GeometryCollection::Facades::FCollectionTransformSelectionFacade TransformSelectionFacade(InCollection);
const TArray<int32>& SelectionArr = TransformSelectionFacade.SelectByVolume(InVolumeMin, InVolumeMax, bInclusive, bInsideRange);
FDataflowTransformSelection NewTransformSelection;
NewTransformSelection.Initialize(InCollection.NumElements(FGeometryCollection::TransformGroup), false);
NewTransformSelection.SetFromArray(SelectionArr);
SetValue(Context, MoveTemp(NewTransformSelection), &TransformSelection);
}
else if (Out->IsA<FManagedArrayCollection>(&Collection))
{
SafeForwardInput(Context, &Collection, &Collection);
}
}
void FCollectionTransformSelectionInBoxDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FDataflowTransformSelection>(&TransformSelection))
{
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
const FBox& InBox = GetValue<FBox>(Context, &Box);
const FTransform& InTransform = GetValue<FTransform>(Context, &Transform);
GeometryCollection::Facades::FCollectionTransformSelectionFacade TransformSelectionFacade(InCollection);
TArray<int32> SelectionArr;
if (Type == ESelectSubjectTypeEnum::Dataflow_SelectSubjectType_Vertices)
{
SelectionArr = TransformSelectionFacade.SelectVerticesInBox(InBox, InTransform, bAllVerticesMustContainedInBox);
}
else if (Type == ESelectSubjectTypeEnum::Dataflow_SelectSubjectType_BoundingBox)
{
SelectionArr = TransformSelectionFacade.SelectBoundingBoxInBox(InBox, InTransform);
}
else if (Type == ESelectSubjectTypeEnum::Dataflow_SelectSubjectType_Centroid)
{
SelectionArr = TransformSelectionFacade.SelectCentroidInBox(InBox, InTransform);
}
FDataflowTransformSelection NewTransformSelection;
NewTransformSelection.Initialize(InCollection.NumElements(FGeometryCollection::TransformGroup), false);
NewTransformSelection.SetFromArray(SelectionArr);
SetValue(Context, MoveTemp(NewTransformSelection), &TransformSelection);
}
else if (Out->IsA<FManagedArrayCollection>(&Collection))
{
SafeForwardInput(Context, &Collection, &Collection);
}
}
#if WITH_EDITOR
bool FCollectionTransformSelectionInBoxDataflowNode::CanDebugDrawViewMode(const FName& ViewModeName) const
{
return ViewModeName == UE::Dataflow::FDataflowConstruction3DViewMode::Name;
}
void FCollectionTransformSelectionInBoxDataflowNode::DebugDraw(UE::Dataflow::FContext& Context, IDataflowDebugDrawInterface& DataflowRenderingInterface, const FDebugDrawParameters& DebugDrawParameters) const
{
if ((DebugDrawParameters.bNodeIsSelected || DebugDrawParameters.bNodeIsPinned))
{
const FBox& InBox = GetValue<FBox>(Context, &Box);
const FTransform& InTransform = GetValue<FTransform>(Context, &Transform);
DataflowRenderingInterface.SetLineWidth(1.0);
DataflowRenderingInterface.SetWireframe(true);
DataflowRenderingInterface.SetWorldPriority();
DataflowRenderingInterface.SetColor(FLinearColor::Red);
const FVector TransformedCenter = InBox.GetCenter() + InTransform.GetTranslation();
const FVector ScaledExtent = InBox.GetExtent() * InTransform.GetScale3D();
DataflowRenderingInterface.DrawBox(ScaledExtent, InTransform.GetRotation(), TransformedCenter, 1.0);
}
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////////
void FCollectionTransformSelectionInSphereDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FDataflowTransformSelection>(&TransformSelection))
{
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
const FSphere& InSphere = GetValue<FSphere>(Context, &Sphere);
const FTransform& InTransform = GetValue<FTransform>(Context, &Transform);
GeometryCollection::Facades::FCollectionTransformSelectionFacade TransformSelectionFacade(InCollection);
TArray<int32> SelectionArr;
if (Type == ESelectSubjectTypeEnum::Dataflow_SelectSubjectType_Vertices)
{
SelectionArr = TransformSelectionFacade.SelectVerticesInSphere(InSphere, InTransform, bAllVerticesMustContainedInSphere);
}
else if (Type == ESelectSubjectTypeEnum::Dataflow_SelectSubjectType_BoundingBox)
{
SelectionArr = TransformSelectionFacade.SelectBoundingBoxInSphere(InSphere, InTransform);
}
else if (Type == ESelectSubjectTypeEnum::Dataflow_SelectSubjectType_Centroid)
{
SelectionArr = TransformSelectionFacade.SelectCentroidInSphere(InSphere, InTransform);
}
FDataflowTransformSelection NewTransformSelection;
NewTransformSelection.Initialize(InCollection.NumElements(FGeometryCollection::TransformGroup), false);
NewTransformSelection.SetFromArray(SelectionArr);
SetValue(Context, MoveTemp(NewTransformSelection), &TransformSelection);
}
else if (Out->IsA<FManagedArrayCollection>(&Collection))
{
SafeForwardInput(Context, &Collection, &Collection);
}
}
#if WITH_EDITOR
bool FCollectionTransformSelectionInSphereDataflowNode::CanDebugDrawViewMode(const FName& ViewModeName) const
{
return ViewModeName == UE::Dataflow::FDataflowConstruction3DViewMode::Name;
}
void FCollectionTransformSelectionInSphereDataflowNode::DebugDraw(UE::Dataflow::FContext& Context, IDataflowDebugDrawInterface& DataflowRenderingInterface, const FDebugDrawParameters& DebugDrawParameters) const
{
if ((DebugDrawParameters.bNodeIsSelected || DebugDrawParameters.bNodeIsPinned))
{
const FSphere& InSphere = GetValue<FSphere>(Context, &Sphere);
const FTransform& InTransform = GetValue<FTransform>(Context, &Transform);
DataflowRenderingInterface.SetLineWidth(1.0);
DataflowRenderingInterface.SetWireframe(true);
DataflowRenderingInterface.SetWorldPriority();
DataflowRenderingInterface.SetColor(FLinearColor::Red);
const FVector TransformedCenter = InSphere.Center + InTransform.GetTranslation();
const double ScaledRadius = InSphere.W * InTransform.GetScale3D().GetMax();
DataflowRenderingInterface.DrawSphere(TransformedCenter, ScaledRadius);
}
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////////
void FCollectionTransformSelectionByFloatAttrDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FDataflowTransformSelection>(&TransformSelection))
{
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
float InMin = GetValue<float>(Context, &Min);
float InMax = GetValue<float>(Context, &Max);
bool bInsideRange = RangeSetting == ERangeSettingEnum::Dataflow_RangeSetting_InsideRange;
GeometryCollection::Facades::FCollectionTransformSelectionFacade TransformSelectionFacade(InCollection);
const TArray<int32>& SelectionArr = TransformSelectionFacade.SelectByFloatAttribute(GroupName, AttrName, InMin, InMax, bInclusive, bInsideRange);
FDataflowTransformSelection NewTransformSelection;
NewTransformSelection.Initialize(InCollection.NumElements(FGeometryCollection::TransformGroup), false);
NewTransformSelection.SetFromArray(SelectionArr);
SetValue(Context, MoveTemp(NewTransformSelection), &TransformSelection);
}
else if (Out->IsA<FManagedArrayCollection>(&Collection))
{
SafeForwardInput(Context, &Collection, &Collection);
}
}
void FSelectFloatArrayIndicesInRangeDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA(&Indices))
{
const TArray<float>& InValues = GetValue(Context, &Values);
float InMin = GetValue(Context, &Min);
float InMax = GetValue(Context, &Max);
bool bInsideRange = RangeSetting == ERangeSettingEnum::Dataflow_RangeSetting_InsideRange;
TArray<int32> OutIndices;
for (int32 Idx = 0; Idx < InValues.Num(); ++Idx)
{
const float FloatValue = InValues[Idx];
if (bInsideRange && FloatValue > Min && FloatValue < Max)
{
OutIndices.Add(Idx);
}
else if (!bInsideRange && (FloatValue < Min || FloatValue > Max))
{
OutIndices.Add(Idx);
}
else if (bInclusive && (FloatValue == Min || FloatValue == Max))
{
OutIndices.Add(Idx);
}
}
SetValue(Context, MoveTemp(OutIndices), &Indices);
}
}
void FCollectionTransformSelectionByIntAttrDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FDataflowTransformSelection>(&TransformSelection))
{
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
int32 InMin = GetValue<int32>(Context, &Min);
int32 InMax = GetValue<int32>(Context, &Max);
bool bInsideRange = RangeSetting == ERangeSettingEnum::Dataflow_RangeSetting_InsideRange;
GeometryCollection::Facades::FCollectionTransformSelectionFacade TransformSelectionFacade(InCollection);
const TArray<int32>& SelectionArr = TransformSelectionFacade.SelectByIntAttribute(GroupName, AttrName, InMin, InMax, bInclusive, bInsideRange);
FDataflowTransformSelection NewTransformSelection;
NewTransformSelection.Initialize(InCollection.NumElements(FGeometryCollection::TransformGroup), false);
NewTransformSelection.SetFromArray(SelectionArr);
SetValue(Context, MoveTemp(NewTransformSelection), &TransformSelection);
}
else if (Out->IsA<FManagedArrayCollection>(&Collection))
{
SafeForwardInput(Context, &Collection, &Collection);
}
}
void FCollectionVertexSelectionCustomDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FDataflowVertexSelection>(&VertexSelection))
{
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
if (InCollection.HasGroup(FGeometryCollection::VerticesGroup))
{
const int32 NumVertices = InCollection.NumElements(FGeometryCollection::VerticesGroup);
FDataflowVertexSelection NewVertexSelection;
NewVertexSelection.Initialize(NumVertices, false);
const FString InVertexIndices = GetValue<FString>(Context, &VertexIndicies);
TArray<FString> Indices;
InVertexIndices.ParseIntoArray(Indices, TEXT(" "), true);
for (FString IndexStr : Indices)
{
if (IndexStr.IsNumeric())
{
int32 Index = FCString::Atoi(*IndexStr);
if (Index >= 0 && Index < NumVertices)
{
NewVertexSelection.SetSelected(Index);
}
else
{
// ERROR: INVALID INDEX
FString ErrorStr = "Invalid specified index found.";
UE_LOG(LogTemp, Error, TEXT("[Dataflow ERROR] %s"), *ErrorStr);
}
}
}
SetValue(Context, MoveTemp(NewVertexSelection), &VertexSelection);
}
else
{
SetValue(Context, FDataflowVertexSelection(), &VertexSelection);
}
}
else if (Out->IsA<FManagedArrayCollection>(&Collection))
{
SafeForwardInput(Context, &Collection, &Collection);
}
}
void FCollectionFaceSelectionCustomDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FDataflowFaceSelection>(&FaceSelection))
{
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
if (InCollection.HasGroup(FGeometryCollection::FacesGroup))
{
const int32 NumFaces = InCollection.NumElements(FGeometryCollection::FacesGroup);
FDataflowFaceSelection NewFaceSelection;
NewFaceSelection.Initialize(NumFaces, false);
const FString InFaceIndices = GetValue<FString>(Context, &FaceIndicies);
TArray<FString> Indices;
InFaceIndices.ParseIntoArray(Indices, TEXT(" "), true);
for (FString& IndexStr : Indices)
{
if (IndexStr.IsNumeric())
{
const int32 Index = FCString::Atoi(*IndexStr);
if (Index >= 0 && Index < NumFaces)
{
NewFaceSelection.SetSelected(Index);
}
else
{
// ERROR: INVALID INDEX
UE_LOG(LogTemp, Error, TEXT("[Dataflow ERROR] Invalid specified index found."));
}
}
}
SetValue(Context, MoveTemp(NewFaceSelection), &FaceSelection);
}
else
{
SetValue(Context, FDataflowFaceSelection(), &FaceSelection);
}
}
else if (Out->IsA<FManagedArrayCollection>(&Collection))
{
SafeForwardInput(Context, &Collection, &Collection);
}
}
void FCollectionSelectionConvertDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA(&TransformSelection))
{
if (IsConnected(&VertexSelection))
{
const FManagedArrayCollection& InCollection = GetValue(Context, &Collection);
const FDataflowVertexSelection& InVertexSelection = GetValue(Context, &VertexSelection);
GeometryCollection::Facades::FCollectionTransformSelectionFacade TransformSelectionFacade(InCollection);
const TArray<int32>& SelectionArr = TransformSelectionFacade.ConvertVertexSelectionToTransformSelection(InVertexSelection.AsArray(), bAllElementsMustBeSelected);
FDataflowTransformSelection NewTransformSelection;
NewTransformSelection.Initialize(InCollection.NumElements(FGeometryCollection::TransformGroup), false);
NewTransformSelection.SetFromArray(SelectionArr);
SetValue(Context, MoveTemp(NewTransformSelection), &TransformSelection);
}
else if (IsConnected(&FaceSelection))
{
const FManagedArrayCollection& InCollection = GetValue(Context, &Collection);
const FDataflowFaceSelection& InFaceSelection = GetValue(Context, &FaceSelection);
GeometryCollection::Facades::FCollectionTransformSelectionFacade TransformSelectionFacade(InCollection);
const TArray<int32>& SelectionArr = TransformSelectionFacade.ConvertFaceSelectionToTransformSelection(InFaceSelection.AsArray(), bAllElementsMustBeSelected);
FDataflowTransformSelection NewTransformSelection;
NewTransformSelection.Initialize(InCollection.NumElements(FGeometryCollection::TransformGroup), false);
NewTransformSelection.SetFromArray(SelectionArr);
SetValue(Context, MoveTemp(NewTransformSelection), &TransformSelection);
}
else
{
// Passthrough
SafeForwardInput(Context, &TransformSelection, &TransformSelection);
}
}
else if (Out->IsA(&FaceSelection))
{
if (IsConnected(&VertexSelection))
{
const FManagedArrayCollection& InCollection = GetValue(Context, &Collection);
const FDataflowVertexSelection& InVertexSelection = GetValue(Context, &VertexSelection);
GeometryCollection::Facades::FCollectionTransformSelectionFacade TransformSelectionFacade(InCollection);
const TArray<int32>& SelectionArr = TransformSelectionFacade.ConvertVertexSelectionToFaceSelection(InVertexSelection.AsArray(), bAllElementsMustBeSelected);
FDataflowFaceSelection NewFaceSelection;
NewFaceSelection.Initialize(InCollection.NumElements(FGeometryCollection::FacesGroup), false);
NewFaceSelection.SetFromArray(SelectionArr);
SetValue(Context, MoveTemp(NewFaceSelection), &FaceSelection);
}
else if (IsConnected(&TransformSelection))
{
const FManagedArrayCollection& InCollection = GetValue(Context, &Collection);
const FDataflowTransformSelection& InTransformSelection = GetValue(Context, &TransformSelection);
GeometryCollection::Facades::FCollectionTransformSelectionFacade TransformSelectionFacade(InCollection);
const TArray<int32>& SelectionArr = TransformSelectionFacade.ConvertTransformSelectionToFaceSelection(InTransformSelection.AsArray());
FDataflowFaceSelection NewFaceSelection;
NewFaceSelection.Initialize(InCollection.NumElements(FGeometryCollection::FacesGroup), false);
NewFaceSelection.SetFromArray(SelectionArr);
SetValue(Context, MoveTemp(NewFaceSelection), &FaceSelection);
}
else
{
// Passthrough
SafeForwardInput(Context, &FaceSelection, &FaceSelection);
}
}
else if (Out->IsA(&VertexSelection))
{
if (IsConnected(&FaceSelection))
{
const FManagedArrayCollection& InCollection = GetValue(Context, &Collection);
const FDataflowFaceSelection& InFaceSelection = GetValue(Context, &FaceSelection);
GeometryCollection::Facades::FCollectionTransformSelectionFacade TransformSelectionFacade(InCollection);
const TArray<int32>& SelectionArr = TransformSelectionFacade.ConvertFaceSelectionToVertexSelection(InFaceSelection.AsArray());
FDataflowVertexSelection NewVertexSelection;
NewVertexSelection.Initialize(InCollection.NumElements(FGeometryCollection::VerticesGroup), false);
NewVertexSelection.SetFromArray(SelectionArr);
SetValue(Context, MoveTemp(NewVertexSelection), &VertexSelection);
}
else if (IsConnected(&TransformSelection))
{
const FManagedArrayCollection& InCollection = GetValue(Context, &Collection);
const FDataflowTransformSelection& InTransformSelection = GetValue(Context, &TransformSelection);
GeometryCollection::Facades::FCollectionTransformSelectionFacade TransformSelectionFacade(InCollection);
const TArray<int32>& SelectionArr = TransformSelectionFacade.ConvertTransformSelectionToVertexSelection(InTransformSelection.AsArray());
FDataflowVertexSelection NewVertexSelection;
NewVertexSelection.Initialize(InCollection.NumElements(FGeometryCollection::VerticesGroup), false);
NewVertexSelection.SetFromArray(SelectionArr);
SetValue(Context, MoveTemp(NewVertexSelection), &VertexSelection);
}
else
{
// Passthrough
SafeForwardInput(Context, &VertexSelection, &VertexSelection);
}
}
else if (Out->IsA(&Collection))
{
SafeForwardInput(Context, &Collection, &Collection);
}
}
void FCollectionFaceSelectionInvertDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FDataflowFaceSelection>(&FaceSelection))
{
FDataflowFaceSelection InFaceSelection = GetValue<FDataflowFaceSelection>(Context, &FaceSelection);
InFaceSelection.Invert();
SetValue<FDataflowFaceSelection>(Context, MoveTemp(InFaceSelection), &FaceSelection);
}
}
void FCollectionVertexSelectionByPercentageDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FDataflowVertexSelection>(&VertexSelection))
{
FDataflowVertexSelection InVertexSelection = GetValue<FDataflowVertexSelection>(Context, &VertexSelection);
int32 InPercentage = GetValue<int32>(Context, &Percentage);
float InRandomSeed = GetValue<float>(Context, &RandomSeed);
TArray<int32> SelectionArr = InVertexSelection.AsArray();
GeometryCollection::Facades::FCollectionTransformSelectionFacade::SelectByPercentage(SelectionArr, InPercentage, bDeterministic, InRandomSeed);
InVertexSelection.SetFromArray(SelectionArr);
SetValue(Context, MoveTemp(InVertexSelection), &VertexSelection);
}
}
void FCollectionVertexSelectionSetOperationDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FDataflowVertexSelection>(&VertexSelection))
{
const FDataflowVertexSelection& InVertexSelectionA = GetValue<FDataflowVertexSelection>(Context, &VertexSelectionA);
const FDataflowVertexSelection& InVertexSelectionB = GetValue<FDataflowVertexSelection>(Context, &VertexSelectionB);
FDataflowVertexSelection NewVertexSelection;
if (InVertexSelectionA.Num() == InVertexSelectionB.Num())
{
if (Operation == ESetOperationEnum::Dataflow_SetOperation_AND)
{
InVertexSelectionA.AND(InVertexSelectionB, NewVertexSelection);
}
else if (Operation == ESetOperationEnum::Dataflow_SetOperation_OR)
{
InVertexSelectionA.OR(InVertexSelectionB, NewVertexSelection);
}
else if (Operation == ESetOperationEnum::Dataflow_SetOperation_XOR)
{
InVertexSelectionA.XOR(InVertexSelectionB, NewVertexSelection);
}
else if (Operation == ESetOperationEnum::Dataflow_SetOperation_Subtract)
{
InVertexSelectionA.Subtract(InVertexSelectionB, NewVertexSelection);
}
}
else
{
// ERROR: INPUT TRANSFORMSELECTIONS HAVE DIFFERENT NUMBER OF ELEMENTS
FString ErrorStr = "Input VertexSelections have different number of elements.";
UE_LOG(LogTemp, Error, TEXT("[Dataflow ERROR] %s"), *ErrorStr);
}
SetValue(Context, MoveTemp(NewVertexSelection), &VertexSelection);
}
}
static void CreateSelectionFromAttr(const FManagedArrayCollection& InCollection,
const FName InGroup,
const FName InAttribute,
const FString InValue,
const ESelectionByAttrOperation InOperation,
FDataflowSelection& OutSelection)
{
const FManagedArrayCollection::EArrayType ArrayType = InCollection.GetAttributeType(InAttribute, InGroup);
const int32 NumElements = InCollection.NumElements(InGroup);
const bool bIsMinOrMaxOperation = (InOperation == ESelectionByAttrOperation::Maximum) || (InOperation == ESelectionByAttrOperation::Minimum);
if (ArrayType == FManagedArrayCollection::EArrayType::FFloatType)
{
const TManagedArray<float>* const Array = InCollection.FindAttributeTyped<float>(InAttribute, InGroup);
if (InValue.IsNumeric() || bIsMinOrMaxOperation)
{
if (InOperation == ESelectionByAttrOperation::Maximum)
{
float MaxValue = TNumericLimits<float>::Lowest();
int32 MaxIndex = INDEX_NONE;
for (int32 Idx = 0; Idx < NumElements; ++Idx)
{
const float ValueAtIdx = (*Array)[Idx];
if (ValueAtIdx >= MaxValue)
{
MaxValue = ValueAtIdx;
MaxIndex = Idx;
}
}
if (MaxIndex != INDEX_NONE)
{
OutSelection.SetSelected(MaxIndex);
}
}
else if (InOperation == ESelectionByAttrOperation::Minimum)
{
float MinValue = TNumericLimits<float>::Max();
int32 MinIndex = INDEX_NONE;
for (int32 Idx = 0; Idx < NumElements; ++Idx)
{
const float ValueAtIdx = (*Array)[Idx];
if (ValueAtIdx <= MinValue)
{
MinValue = ValueAtIdx;
MinIndex = Idx;
}
}
if (MinIndex != INDEX_NONE)
{
OutSelection.SetSelected(MinIndex);
}
}
else
{
float FloatValue = FCString::Atof(*InValue);
for (int32 Idx = 0; Idx < NumElements; ++Idx)
{
if ((InOperation == ESelectionByAttrOperation::Equal && (*Array)[Idx] == FloatValue) ||
(InOperation == ESelectionByAttrOperation::NotEqual && (*Array)[Idx] != FloatValue) ||
(InOperation == ESelectionByAttrOperation::Greater && (*Array)[Idx] > FloatValue) ||
(InOperation == ESelectionByAttrOperation::GreaterOrEqual && (*Array)[Idx] >= FloatValue) ||
(InOperation == ESelectionByAttrOperation::Smaller && (*Array)[Idx] < FloatValue) ||
(InOperation == ESelectionByAttrOperation::SmallerOrEqual && (*Array)[Idx] <= FloatValue))
{
OutSelection.SetSelected(Idx);
}
}
}
}
else
{
// Error: Invalid Value specified
return;
}
}
else if (ArrayType == FManagedArrayCollection::EArrayType::FInt32Type)
{
const TManagedArray<int32>* const Array = InCollection.FindAttributeTyped<int32>(InAttribute, InGroup);
if (InValue.IsNumeric() || bIsMinOrMaxOperation)
{
if (InOperation == ESelectionByAttrOperation::Maximum)
{
int32 MaxValue = TNumericLimits<int32>::Lowest();
int32 MaxIndex = INDEX_NONE;
for (int32 Idx = 0; Idx < NumElements; ++Idx)
{
const int32 ValueAtIdx = (*Array)[Idx];
if (ValueAtIdx >= MaxValue)
{
MaxValue = ValueAtIdx;
MaxIndex = Idx;
}
}
if (MaxIndex != INDEX_NONE)
{
OutSelection.SetSelected(MaxIndex);
}
}
else if (InOperation == ESelectionByAttrOperation::Minimum)
{
int32 MinValue = TNumericLimits<int32>::Max();
int32 MinIndex = INDEX_NONE;
for (int32 Idx = 0; Idx < NumElements; ++Idx)
{
const int32 ValueAtIdx = (*Array)[Idx];
if (ValueAtIdx <= MinValue)
{
MinValue = ValueAtIdx;
MinIndex = Idx;
}
}
if (MinIndex != INDEX_NONE)
{
OutSelection.SetSelected(MinIndex);
}
}
else
{
float IntValue = FCString::Atoi(*InValue);
for (int32 Idx = 0; Idx < NumElements; ++Idx)
{
if ((InOperation == ESelectionByAttrOperation::Equal && (*Array)[Idx] == IntValue) ||
(InOperation == ESelectionByAttrOperation::NotEqual && (*Array)[Idx] != IntValue) ||
(InOperation == ESelectionByAttrOperation::Greater && (*Array)[Idx] > IntValue) ||
(InOperation == ESelectionByAttrOperation::GreaterOrEqual && (*Array)[Idx] >= IntValue) ||
(InOperation == ESelectionByAttrOperation::Smaller && (*Array)[Idx] < IntValue) ||
(InOperation == ESelectionByAttrOperation::SmallerOrEqual && (*Array)[Idx] <= IntValue))
{
OutSelection.SetSelected(Idx);
}
}
}
}
else
{
// Error: Invalid Value specified
return;
}
}
else if (ArrayType == FManagedArrayCollection::EArrayType::FStringType)
{
const TManagedArray<FString>* const Array = InCollection.FindAttributeTyped<FString>(InAttribute, InGroup);
for (int32 Idx = 0; Idx < NumElements; ++Idx)
{
if ((InOperation == ESelectionByAttrOperation::Equal && (*Array)[Idx] == InValue) ||
(InOperation == ESelectionByAttrOperation::NotEqual && !((*Array)[Idx] == InValue)))
{
OutSelection.SetSelected(Idx);
}
}
}
else if (ArrayType == FManagedArrayCollection::EArrayType::FBoolType)
{
const TManagedArray<bool>* const Array = InCollection.FindAttributeTyped<bool>(InAttribute, InGroup);
bool BoolValue = false;
if (InValue.IsNumeric())
{
float FloatValue = FCString::Atof(*InValue);
if (FloatValue > 0.f)
{
BoolValue = true;
}
}
else
{
if (InValue == FString("true") || InValue == FString("True"))
{
BoolValue = true;
}
}
for (int32 Idx = 0; Idx < NumElements; ++Idx)
{
if ((InOperation == ESelectionByAttrOperation::Equal && (*Array)[Idx] == BoolValue) ||
(InOperation == ESelectionByAttrOperation::NotEqual && !((*Array)[Idx] == BoolValue)))
{
OutSelection.SetSelected(Idx);
}
}
}
}
void FCollectionSelectionByAttrDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA(&VertexSelection) ||
Out->IsA(&FaceSelection) ||
Out->IsA(&TransformSelection) ||
Out->IsA(&GeometrySelection) ||
Out->IsA(&MaterialSelection))
{
const FManagedArrayCollection& InCollection = GetValue(Context, &Collection);
FCollectionAttributeKey InAttributeKey = GetValue(Context, &AttributeKey);
FName GroupName = UE::Dataflow::Private::GetAttributeFromEnumAsName(Group);
FName AttributeName = FName(Attribute);
if (IsConnected(&AttributeKey))
{
GroupName = FName(InAttributeKey.Group);
AttributeName = FName(InAttributeKey.Attribute);
}
if (InCollection.HasGroup(GroupName))
{
if (InCollection.HasAttribute(AttributeName, GroupName))
{
const int32 NumFaces = InCollection.NumElements(GroupName);
FDataflowSelection NewGenericSelection;
NewGenericSelection.Initialize(NumFaces, false);
CreateSelectionFromAttr(InCollection,
GroupName,
AttributeName,
Value,
Operation,
NewGenericSelection);
using namespace UE::Dataflow::Private;
FDataflowVertexSelection OutVertexSelection;
if (GroupName == UE::Dataflow::Private::GetAttributeFromEnumAsName(ESelectionByAttrGroup::Vertices))
{
OutVertexSelection.Initialize(NewGenericSelection);
}
SetValue(Context, MoveTemp(OutVertexSelection), &VertexSelection);
FDataflowFaceSelection OutFaceSelection;
if (GroupName == UE::Dataflow::Private::GetAttributeFromEnumAsName(ESelectionByAttrGroup::Faces))
{
OutFaceSelection.Initialize(NewGenericSelection);
}
SetValue(Context, MoveTemp(OutFaceSelection), &FaceSelection);
FDataflowTransformSelection OutTransformSelection;
if (GroupName == UE::Dataflow::Private::GetAttributeFromEnumAsName(ESelectionByAttrGroup::Transform))
{
OutTransformSelection.Initialize(NewGenericSelection);
}
SetValue(Context, MoveTemp(OutTransformSelection), &TransformSelection);
FDataflowGeometrySelection OutGeometrySelection;
if (GroupName == UE::Dataflow::Private::GetAttributeFromEnumAsName(ESelectionByAttrGroup::Geometry))
{
OutGeometrySelection.Initialize(NewGenericSelection);
}
SetValue(Context, MoveTemp(OutGeometrySelection), &GeometrySelection);
FDataflowMaterialSelection OutMaterialSelection;
if (GroupName == UE::Dataflow::Private::GetAttributeFromEnumAsName(ESelectionByAttrGroup::Material))
{
OutMaterialSelection.Initialize(NewGenericSelection);
}
SetValue(Context, MoveTemp(OutMaterialSelection), &MaterialSelection);
return;
}
}
SetValue(Context, FDataflowVertexSelection(), &VertexSelection);
SetValue(Context, FDataflowFaceSelection(), &FaceSelection);
SetValue(Context, FDataflowTransformSelection(), &TransformSelection);
SetValue(Context, FDataflowGeometrySelection(), &GeometrySelection);
SetValue(Context, FDataflowMaterialSelection(), &MaterialSelection);
}
else if (Out->IsA<FManagedArrayCollection>(&Collection))
{
SafeForwardInput(Context, &Collection, &Collection);
}
}
void FGeometrySelectionToVertexSelectionDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA<FDataflowVertexSelection>(&VertexSelection))
{
const FManagedArrayCollection& InCollection = GetValue<FManagedArrayCollection>(Context, &Collection);
const int32 NumVertices = InCollection.NumElements(FGeometryCollection::VerticesGroup);
const int32 NumGeometries = InCollection.NumElements(FGeometryCollection::GeometryGroup);
FDataflowVertexSelection InVertexSelection;
InVertexSelection.Initialize(NumVertices, false);
const TManagedArray<int32>* VertexStart = InCollection.FindAttributeTyped<int32>("VertexStart", FGeometryCollection::GeometryGroup);
const TManagedArray<int32>* VertexCount = InCollection.FindAttributeTyped<int32>("VertexCount", FGeometryCollection::GeometryGroup);
TArray<int32> InGeometryIndexArray;
if (IsConnected(&GeometrySelection))
{
InGeometryIndexArray = GetValue<FDataflowGeometrySelection>(Context, &GeometrySelection).AsArray();
}
else
{
TArray<FString> Indices;
GeometryIndices.ParseIntoArray(Indices, TEXT(" "), true);
for (FString IndexStr : Indices)
{
if (IndexStr.IsNumeric())
{
int32 Index = FCString::Atoi(*IndexStr);
if (Index >= 0 && Index < NumGeometries)
{
InGeometryIndexArray.Add(Index);
}
else
{
// ERROR: INVALID INDEX
FString ErrorStr = "Invalid geometry index found.";
UE_LOG(LogTemp, Error, TEXT("[Dataflow ERROR] %s"), *ErrorStr);
}
}
}
}
if (VertexStart && VertexCount)
{
TArray<int32> VertexIndices;
for (int32 GeometryIdx : InGeometryIndexArray)
{
if (ensure(VertexStart->IsValidIndex(GeometryIdx)))
{
const int32 Start = (*VertexStart)[GeometryIdx];
const int32 Count = (*VertexCount)[GeometryIdx];
for (int32 VertexIdx = Start; VertexIdx < Start + Count; ++VertexIdx)
{
VertexIndices.Add(VertexIdx);
}
}
}
InVertexSelection.SetFromArray(VertexIndices);
}
SetValue(Context, MoveTemp(InVertexSelection), &VertexSelection);
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FCollectionSelectionSetOperationDataflowNode::FCollectionSelectionSetOperationDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid)
: FDataflowNode(InParam, InGuid)
{
static const FName TypeDependencyGroup("Main");
RegisterInputConnection(&SelectionA)
.SetTypeDependencyGroup(TypeDependencyGroup);
RegisterInputConnection(&SelectionB)
.SetTypeDependencyGroup(TypeDependencyGroup);
RegisterOutputConnection(&Selection, &SelectionA)
.SetTypeDependencyGroup(TypeDependencyGroup);
}
void FCollectionSelectionSetOperationDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA(&Selection))
{
const FDataflowSelection& InSelectionA = GetValue(Context, &SelectionA);
const FDataflowSelection& InSelectionB = GetValue(Context, &SelectionB);
ensure(FindInput(&SelectionA)->GetType() == FindInput(&SelectionB)->GetType());
ensure(FindOutput(&Selection)->GetType() == FindInput(&SelectionA)->GetType());
FDataflowSelection OutSelection;
if (InSelectionA.Num() == InSelectionB.Num())
{
switch (Operation)
{
case ESetOperationEnum::Dataflow_SetOperation_AND:
InSelectionA.AND(InSelectionB, OutSelection);
break;
case ESetOperationEnum::Dataflow_SetOperation_OR:
InSelectionA.OR(InSelectionB, OutSelection);
break;
case ESetOperationEnum::Dataflow_SetOperation_XOR:
InSelectionA.XOR(InSelectionB, OutSelection);
break;
case ESetOperationEnum::Dataflow_SetOperation_Subtract:
InSelectionA.Subtract(InSelectionB, OutSelection);
break;
}
}
else
{
UE_LOG(LogTemp, Error, TEXT("Dataflow: CollectionSelectionSetOperationDataflowNode : Input Selections have different number of elements."));
}
SetValue(Context, MoveTemp(OutSelection), &Selection);
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FCollectionSelectionInvertDataflowNode::FCollectionSelectionInvertDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid)
: FDataflowNode(InParam, InGuid)
{
static const FName TypeDependencyGroup("Main");
RegisterInputConnection(&Selection)
.SetTypeDependencyGroup(TypeDependencyGroup);
RegisterOutputConnection(&Selection, &Selection)
.SetTypeDependencyGroup(TypeDependencyGroup);
}
void FCollectionSelectionInvertDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
if (Out->IsA(&Selection))
{
ensure(FindOutput(&Selection)->GetType() == FindInput(&Selection)->GetType());
FDataflowSelection InSelection = GetValue(Context, &Selection);
InSelection.Invert();
SetValue(Context, MoveTemp(InSelection), &Selection);
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FCollectionSelectInternalFacesDataflowNode::FCollectionSelectInternalFacesDataflowNode(const UE::Dataflow::FNodeParameters& InParam, FGuid InGuid)
: FDataflowNode(InParam, InGuid)
{
RegisterInputConnection(&Collection);
RegisterInputConnection(&TransformSelection);
RegisterOutputConnection(&Collection, &Collection);
RegisterOutputConnection(&FaceSelection);
}
void FCollectionSelectInternalFacesDataflowNode::Evaluate(UE::Dataflow::FContext& Context, const FDataflowOutput* Out) const
{
static const FName InternalAttributeName(TEXT("Internal"));
if (Out->IsA(&Collection))
{
SafeForwardInput(Context, &Collection, &Collection);
}
else if (Out->IsA(&FaceSelection))
{
const FManagedArrayCollection& InCollection = GetValue(Context, &Collection);
const FDataflowTransformSelection& InTransformSelection = GetValue(Context, &TransformSelection);
struct FFaceRange
{
int32 Start;
int32 Count;
};
const TManagedArray<int32>* TransformIndexFromGeometry = InCollection.FindAttribute<int32>("TransformIndex", FGeometryCollection::GeometryGroup);
const TManagedArray<int32>* FaceStart = InCollection.FindAttribute<int32>("FaceStart", FGeometryCollection::GeometryGroup);
const TManagedArray<int32>* FaceCount = InCollection.FindAttribute<int32>("FaceCount", FGeometryCollection::GeometryGroup);
const TManagedArray<bool>* InternalFaces = InCollection.FindAttribute<bool>(InternalAttributeName, FGeometryCollection::FacesGroup);
const int32 TotalNumFaces = InCollection.NumElements(FGeometryCollection::FacesGroup);
FDataflowFaceSelection OutFaceSelection;
OutFaceSelection.Initialize(TotalNumFaces, false);
if (TransformIndexFromGeometry && FaceStart && FaceCount && InternalFaces)
{
TArray<FFaceRange> FaceRanges;
if (IsConnected(&TransformSelection))
{
for (int32 GeoIdx = 0; GeoIdx < TransformIndexFromGeometry->Num(); ++GeoIdx)
{
const int32 TransformIndex = (*TransformIndexFromGeometry)[GeoIdx];
if (InTransformSelection.IsSelected(TransformIndex))
{
FaceRanges.Emplace(
FFaceRange {
.Start=(*FaceStart)[GeoIdx],
.Count=(*FaceCount)[GeoIdx]
});
}
}
}
else
{
FaceRanges.Emplace(
FFaceRange{
.Start = 0,
.Count = TotalNumFaces
});
}
for (const FFaceRange& FaceRange : FaceRanges)
{
for (int32 Idx = 0; Idx < FaceRange.Count; ++Idx)
{
const int32 FaceIndex = (FaceRange.Start + Idx);
if ((*InternalFaces)[FaceIndex])
{
OutFaceSelection.SetSelected(FaceRange.Start + Idx);
}
}
}
}
SetValue(Context, OutFaceSelection, &FaceSelection);
}
}