Files
2025-05-18 13:04:45 +08:00

120 lines
3.7 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "EdgeSpan.h"
#define UE_API DYNAMICMESH_API
namespace UE
{
namespace Geometry
{
class FDynamicMesh3;
/**
* Weld a pair of group edges. The two input spans must be boundary spans. Their
* position in the world is irrelevant, as the welding will always be done to
* preserve appropriate triangle winding, i.e. so that the newly welded triangles
* are not flipped relative to their neighbor.
*
* User can optionally allow triangle deletion which handles cases
* where the group edges are connected by an edge at the end points.
*/
class FWeldEdgeSequence
{
public:
enum class EWeldResult
{
Ok = 0,
Failed_EdgesNotBoundaryEdges = 10, // Occurs when any edge in either input span isn't a boundary edge.
Failed_CannotSplitEdge = 21, // Occurs when SplitEdge() fails, haven't encountered this and I'm not sure what would cause it
Failed_TriangleDeletionDisabled = 22, // Occurs when bAllowIntermediateTriangleDeletion is false and edge spans are connected by an edge
Failed_CannotDeleteTriangle = 23, // Occurs when bAllowIntermediateTriangleDeletion is true, edge spans are connected, but edge deletion fails
Failed_Other = 100, // Catch all for general failure
};
public:
/**
* Inputs/Outputs
*/
FDynamicMesh3* Mesh;
FEdgeSpan EdgeSpanToDiscard; // This data is junk once Weld() is called
FEdgeSpan EdgeSpanToKeep; // This is the updated edge span which can be used once Weld() is called
// Whether triangle deletion is allowed in order to merge edges which are connected by a different edge
bool bAllowIntermediateTriangleDeletion = false;
// When true, failed calls to MergeEdges() will be handled by moving the edges without merging such
// that the final result appears to be welded but has invisible seam(s) instead of just failing.
bool bAllowFailedMerge = false;
// When vertices are welded, each kept vertex will be placed at Lerp(KeepPos, RemovePos, InterpolationT)
double InterpolationT = 0;
// This is populated with pairs of eids which were not able to be merged.
// Only valid when bAllowFailedMerge is true
TArray<TPair<int, int>> UnmergedEdgePairsOut;
public:
FWeldEdgeSequence(FDynamicMesh3* Mesh, FEdgeSpan SpanDiscard, FEdgeSpan SpanKeep)
: Mesh(Mesh)
, EdgeSpanToDiscard(SpanDiscard)
, EdgeSpanToKeep(SpanKeep)
{
}
virtual ~FWeldEdgeSequence() {}
/**
* Alters the existing mesh by welding two edge sequences, preserving sequence A.
* Conditions the mesh by splitting edges and optionally deleting triangles.
*
* @return EWeldResult::OK on success
*/
UE_API EWeldResult Weld();
/**
* Helper that splits the edges in the shorter span until the spans have the same number
* of edges. Weld() will automatically do this, but this is public in case the user wants
* to equalize spans that get concatenated together before all being welded at once.
*/
static UE_API EWeldResult SplitEdgesToEqualizeSpanLengths(FDynamicMesh3& Mesh, FEdgeSpan& Span1, FEdgeSpan& Span2);
protected:
/**
* Verifies validity of input edges by ensuring they are
* correctly-oriented boundary edges
*
* @return EWeldResult::OK on success
*/
UE_API EWeldResult CheckInput();
/**
* Splits largest edges of the span with fewest vertices so that
* both input spans have an equal number of vertices and edges after
*
* @return EWeldResult::OK on success
*/
UE_API EWeldResult SplitSmallerSpan();
UE_DEPRECATED(5.5, "Side triangles are handled appropriately in WeldEdgeSequence")
UE_API EWeldResult CheckForAndCollapseSideTriangles();
/**
* Welds edge sequence together
*
* @return EWeldResult::OK on success
*/
UE_API EWeldResult WeldEdgeSequence();
};
} // end namespace UE::Geometry
} // end namespace UE
#undef UE_API