Dust3D开源项目分析——模型处理部分 | 三角化面片

 2021SC@SDUSC

针对四边面或者N-Gon,执行mesh三角化命令。

头文件,声明执行三角化面片命令的函数。

#ifndef DUST3D_TRIANGULATE_FACES_H
#define DUST3D_TRIANGULATE_FACES_H
#include <QVector3D>
#include <vector>

bool triangulateFacesWithoutKeepVertices(std::vector<QVector3D> &vertices, const std::vector<std::vector<size_t>> &faces, std::vector<std::vector<size_t>> &triangles);

#endif

 cpp文件

三角化方法的具体实现。

#include <QDebug>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Polygon_mesh_processing/triangulate_faces.h>
#include <QVector2D>
#include <QVector3D>
#include "booleanmesh.h"
#include "triangulatefaces.h"
#include "util.h"

typedef CGAL::Exact_predicates_inexact_constructions_kernel InexactKernel;
typedef CGAL::Surface_mesh<InexactKernel::Point_3> InexactMesh;

bool triangulateFacesWithoutKeepVertices(std::vector<QVector3D> &vertices, const std::vector<std::vector<size_t>> &faces, std::vector<std::vector<size_t>> &triangles)
{
    auto cgalMesh = buildCgalMesh<InexactKernel>(vertices, faces);
    bool isSuccessful = CGAL::Polygon_mesh_processing::triangulate_faces(*cgalMesh);
    if (isSuccessful) {
        vertices.clear();
        fetchFromCgalMesh<InexactKernel>(cgalMesh, vertices, triangles);
        delete cgalMesh;
        return true;
    }
    delete cgalMesh;
    
    // fallback to our own imeplementation

    isSuccessful = true;
    std::vector<std::vector<size_t>> rings;
    for (const auto &face: faces) {
        if (face.size() > 3) {
            rings.push_back(face);
        } else {
            triangles.push_back(face);
        }
    }
    for (const auto &ring: rings) {
        std::vector<size_t> fillRing = ring;
        QVector3D direct = polygonNormal(vertices, fillRing);
        while (fillRing.size() > 3) {
            bool newFaceGenerated = false;
            for (decltype(fillRing.size()) i = 0; i < fillRing.size(); ++i) {
                auto j = (i + 1) % fillRing.size();
                auto k = (i + 2) % fillRing.size();
                const auto &enter = vertices[fillRing[i]];
                const auto &cone = vertices[fillRing[j]];
                const auto &leave = vertices[fillRing[k]];
                auto angle = angleInRangle360BetweenTwoVectors(cone - enter, leave - cone, direct);
                if (angle >= 1.0 && angle <= 179.0) {
                    bool isEar = true;
                    for (size_t x = 0; x < fillRing.size() - 3; ++x) {
                        auto h = (i + 3 + x) % fillRing.size();
                        auto fourth = vertices[fillRing[h]];
                        if (pointInTriangle(enter, cone, leave, fourth)) {
                            isEar = false;
                            break;
                        }
                    }
                    if (isEar) {
                        std::vector<size_t> newFace = {
                            fillRing[i],
                            fillRing[j],
                            fillRing[k],
                        };
                        triangles.push_back(newFace);
                        fillRing.erase(fillRing.begin() + j);
                        newFaceGenerated = true;
                        break;
                    }
                }
            }
            if (!newFaceGenerated)
                break;
        }
        if (fillRing.size() == 3) {
            std::vector<size_t> newFace = {
                fillRing[0],
                fillRing[1],
                fillRing[2],
            };
            triangles.push_back(newFace);
        } else {
            qDebug() << "Triangulate failed, ring size:" << fillRing.size();
            isSuccessful = false;
        }
    }
    return isSuccessful;
}

函数有三个传入参数:顶点坐标容器vertices、面片构成顺序容器faces和三角形组成顺序容器triangls。可以看到函数首先遍历faces,将size大于3的标记为环(存入rings),其他的标记为三角形(存入triangles)。对于标记为环的面片需要执行三角化操作。执行完毕后遍历rings,将size等于3的面的三个顶点顺序存入triangles(三角化执行完毕后size不是3就报错,isSuccessful置false),最后返回isSuccessful的值用于确认是否成功三角化。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值