耳切法三角网构造代码

/// \brief 判断点是否在三角形内
/// \param Point 目标点
/// \param A/B/C 组成三角形的三个顶点
/// \return 判别结果
static bool IsPointInTriangle(const FVector& Point, const FVector& A, const FVector& B, const FVector& C)
{
    // 使用叉积检查点是否在三角形内部
    FVector AB = B - A;
    FVector BC = C - B;
    FVector CA = A - C;

    FVector AP = Point - A;
    FVector BP = Point - B;
    FVector CP = Point - C;

    FVector Cross1 = FVector::CrossProduct(AB, AP);
    FVector Cross2 = FVector::CrossProduct(BC, BP);
    FVector Cross3 = FVector::CrossProduct(CA, CP);

    // 如果点在三角形内,那么所有的叉积应该指向相同的方向
    return (Cross1.Z > 0 && Cross2.Z > 0 && Cross3.Z > 0) || (Cross1.Z < 0 && Cross2.Z < 0 && Cross3.Z < 0);
}

/// \brief 判别三角形是否是耳朵
/// \param Vertices 逆时针顺序的顶点数组
/// \param i0/i1/i2 三个点的索引
/// \return 判别结果
static bool IsEar(const TArray<FVector>& Vertices, int32 i0, int32 i1, int32 i2)
{
    const FVector& v0 = Vertices[i0];
    const FVector& v1 = Vertices[i1];
    const FVector& v2 = Vertices[i2];

    // Step 1: 检查三角形是否为凸形(目前假设顶点逆时针顺序)
    // 使用叉积检查方向,如果结果为正,则该三角形为凸形
    FVector Edge1 = v1 - v0;
    FVector Edge2 = v2 - v1;
    if (FVector::CrossProduct(Edge1, Edge2).Z <= 0)
    {
        return false;  // 凹形或共线,不是耳朵
    }

    // Step 2: 检查三角形内部是否包含多边形的其他顶点
    for (int32 i = 0; i < Vertices.Num(); i++)
    {
        if (i == i0 || i == i1 || i == i2)
            continue;

        if (IsPointInTriangle(Vertices[i], v0, v1, v2))
        {
            return false;  // 该三角形包含其他顶点,不是耳朵
        }
    }

    return true;  // 满足条件,返回 true,表示这是一个耳朵
}

/// \brief 三角剖分,根据EarCutting算法,对传入的顶点数组进行组网
/// \param Vertices 简单多边形的顶点组
/// \param OutIndeces 三角网的索引数组输出
/// \return 算法执行成功与否(false可能是传入多边形不属于简单多边形,或者数量不够)
static bool TriangulatePolygon(const TArray<FVector>& Vertices, TArray<int32>& OutIndices)
{
    if (Vertices.Num() < 3)
        return false;

    // 复制顶点列表用于操作
    TArray<int32> VerticesIndices;
    for (int32 i = 0; i < Vertices.Num(); i++)
    {
        VerticesIndices.Add(i);
    }

    // 耳切法:找到每个顶点形成的耳朵,并逐步移除
    while (VerticesIndices.Num() >= 3)
    {
        bool bFoundEar = false;

        for (int32 i = 0; i < VerticesIndices.Num(); i++)
        {
            int32 i0 = VerticesIndices[i];
            int32 i1 = VerticesIndices[(i + 1) % VerticesIndices.Num()];
            int32 i2 = VerticesIndices[(i + 2) % VerticesIndices.Num()];

            FVector v0 = Vertices[i0];
            FVector v1 = Vertices[i1];
            FVector v2 = Vertices[i2];

            if (IsEar(Vertices, i0, i1, i2))
            {
                // 添加三角形
                OutIndices.Add(i0);
                OutIndices.Add(i1);
                OutIndices.Add(i2);

                // 移除耳朵(中间那个凸出去的单个点)
                VerticesIndices.RemoveAt((i + 1) % VerticesIndices.Num());

                bFoundEar = true;
                break;
            }
        }

        // 如果未找到耳朵,可能是非简单多边形或者别的原因
        if (!bFoundEar)
        {
            return false;
        }
    }

    return true;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宗浩多捞

您的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值