耳切法三角网构造代码

/// \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;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
可以参考以下的 C 代码实现: ``` #include <stdio.h> #include <stdlib.h> #define MAX_POLYGON_VERTICES 1000 typedef struct { double x, y; } Point; typedef struct { int a, b, c; } Triangle; int earClipping(Point* polygon, int numVertices, Triangle* triangles) { // 初始化三角剖分结果为空 int numTriangles = 0; // 每次剪掉一个“耳朵”后多边形的边数都会减少,最后只剩下 3 个点 while (numVertices > 3) { // 遍历所有顶点,找到一个“耳朵” for (int i = 0; i < numVertices; i++) { // 确定当前顶点 i 对应的边所在的两个顶点 int iPrev = (i + numVertices - 1) % numVertices; int iNext = (i + 1) % numVertices; // 判断顶点 i 是否是凸顶点 Point pi = polygon[i]; Point piPrev = polygon[iPrev]; Point piNext = polygon[iNext]; double crossProduct = (pi.x - piPrev.x) * (piNext.y - pi.y) - (piNext.x - pi.x) * (pi.y - piPrev.y); if (crossProduct >= 0) { continue; } // 判断顶点 i 是否成为凸耳朵 // 如果顶点 i 成为凸耳朵,需要确定凸耳朵的另外两个顶点 int isEar = 1; for (int j = 0; j < numVertices; j++) { if (j == i || j == iPrev || j == iNext) { continue; } if ((polygon[j].x - pi.x) * (piPrev.y - pi.y) + (piPrev.x - pi.x) * (pi.y - polygon[j].y) >= 0 && (piPrev.x - pi.x) * (piNext.y - pi.y) + (piNext.x - pi.x) * (pi.y - piPrev.y) >= 0 && (piNext.x - pi.x) * (polygon[j].y - pi.y) + (polygon[j].x - pi.x) * (pi.y - piNext.y) >= 0) { isEar = 0; break; } } if (!isEar) { continue; } // 找到一个凸耳朵,将它对应的三角形加入到三角剖分结果中 Triangle triangle = { iPrev, i, iNext }; triangles[numTriangles++] = triangle; // 从多边形中剪掉凸耳朵 i for (int j = i + 1; j < numVertices; j++) { polygon[j - 1] = polygon[j]; } numVertices--; i--; } } // 将多边形剩余的三个顶点构成最后一个三角形 Triangle triangle = { 0, 1, 2 }; triangles[numTriangles++] = triangle; return numTriangles; } int main() { Point polygon[MAX_POLYGON_VERTICES]; int numVertices; // 读取多边形顶点坐标 scanf("%d", &numVertices); for (int i = 0; i < numVertices; i++) { scanf("%lf%lf", &polygon[i].x, &polygon[i].y); } // 进行三角剖分 Triangle triangles[MAX_POLYGON_VERTICES]; int numTriangles = earClipping(polygon, numVertices, triangles); // 输出三角剖分结果 printf("%d\n", numTriangles); for (int i = 0; i < numTriangles; i++) { printf("%d %d %d\n", triangles[i].a, triangles[i].b, triangles[i].c); } return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

宗浩多捞

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

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

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

打赏作者

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

抵扣说明:

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

余额充值