교차 세그먼트의 양 끝점을 연결하는 경로를 생성한다. FCutWorkingInfo::InsertFaceVertices(), FCutWorkingInfo::InsertEdgeVertices() 를 통해 각 세그먼트들이 처리되었지만 교차 세그먼트의 양 끝에 있는 2개의 세그먼트는 연결된 엣지가 없을 수 있으므로 이를 처리하는 것이다.



의사 코드


for ( int SegIdx = 0; SegIdx < Segments.Num(); SegIdx++ )
{
    FSegmentToElements& Seg = Segments[ SegIdx ];
 
    // 퇴화 케이스 처리 (같은 점)
    if ( Seg.PtOnMeshIdx[ 0 ] == Seg.PtOnMeshIdx[ 1 ] )
    {
        continue;
    }
 
    FPtOnMesh& PtA = IntersectionVerts[ Seg.PtOnMeshIdx[ 0 ] ];
    FPtOnMesh& PtB = IntersectionVerts[ Seg.PtOnMeshIdx[ 1 ] ];
 
    // 유효성 검사
    if ( PtA.Type != EVertexType::Vertex || PtB.Type != EVertexType::Vertex )
    {
        bSuccess = false;
        continue;
    }
 
    // 이미 같은 정점인 경우
    if ( PtA.ElemID == PtB.ElemID )
    {
        continue;
    }
 
    // 이미 엣지로 연결된 경우
    int EID = Mesh->FindEdge( PtA.ElemID, PtB.ElemID );
    if ( EID != FDynamicMesh3::InvalidID )
    {
        // VertexChains에 추가 (2개 정점)
        continue;
    }
 
    // Planar Walk 알고리즘으로 경로 찾기
    FMeshSurfacePath SurfacePath( Mesh );
    int StartTID = Mesh->GetVtxSingleTriangle( PtA.ElemID );
 
    // 절단 평면 법선 계산 (삼각형 법선 × 세그먼트 방향)
    FVector3d WalkPlaneNormal = BaseFaceNormals[ Seg.BaseTID ].Cross( PtB.Pos - PtA.Pos );
 
    if ( Normalize( WalkPlaneNormal ) == 0 )
    {
        // 퇴화 삼각형 처리
        if ( FVector3d::DistSquared( PtA.Pos, PtB.Pos ) > SnapToleranceSq )
        {
            continue;  // 이미 연결된 것으로 간주
        }
        WalkPlaneNormal = GetDegenTriangleEdgeDirection( Mesh, StartTID );
    }
 
    // Planar Walk 실행
    bool bWalkSuccess = SurfacePath.AddViaPlanarWalk
    (
        StartTID, 
        PtA.ElemID, 
        Mesh->GetVertex( PtA.ElemID ),
        -1, 
        PtB.ElemID, 
        Mesh->GetVertex( PtB.ElemID ),
        WalkPlaneNormal, 
        nullptr, 
        false,
        FMathd::ZeroTolerance, 
        SnapToleranceSq, 
        .001
    );
 
    if ( !bWalkSuccess )
    {
        bSuccess = false;
        continue;
    }
 
    // 경로를 메시에 실제로 삽입 (엣지 분할 등)
    TArray< int > EmbeddedPath;
    if ( SurfacePath.EmbedSimplePath( false, EmbeddedPath, false, SnapToleranceSq ) )
    {
        // VertexChains에 경로 추가
        if ( VertexChains )
        {
            VertexChains->Add( EmbeddedPath.Num() );
            VertexChains->Append( EmbeddedPath );
        }
    }
    else
    {
        bSuccess = false;
    }
}
 
return bSuccess;

세그먼트의 양 끝단을 잇기 위해 FMeshSurfacePath를 이용한다.



특수 케이스 처리


퇴화 삼각형
  • 거의 선분이나 점으로 찌그러진 삼각형
  • GetDegenTriangleEdgeDirection()으로 대체 방향 계산

이미 연결된 경우
  • FindEdge()로 확인
  • 이미 엣지가 존재하면 건너뛰기

동일한 정점
  • 세그먼트의 양 끝점이 같은 정점인 경우
  • 퇴화 케이스로 처리

너무 가까운 점들
  • SnapToleranceSq 기반 판단
  • 이미 연결된 것으로 간주


반환값


모든 세그먼트의 연결이 성공하면 true, 하나라도 실패하면 false를 반환한다.


VertexChains (선택적 출력)
  • 각 세그먼트의 연결 경로 정보
  • 형식: [길이, v0, v1, ..., vn]

SegmentToChain (선택적 출력)
  • 각 세그먼트가 VertexChains의 어느 인덱스에 저장되어 있는지 매핑