Dust3D项目实训七 | 基于meshcombiner类的网格粘合分析

2021SC@SDUSC

目录

分析概述

模块功能

CGAL分析

cgal库概述

曲面网格生成 [ make_surface_mesh ]

多边形网格处理 [ Polygon_mesh_processing ]

关键代码分析

meshcombiner.h分析

meshcombiner.cpp分析

MeshCombiner::Mesh::Mesh()函数分析

*MeshCombiner::combine()函数分析


分析概述

模块功能

该模块的主要功能为通过各个面和点的信息生成曲面网格,再将不同平面的网格粘合在一起,最终形成可视化曲面网格体

CGAL分析

cgal库概述

CGAL是一个具有强制性依赖项的计算几何算法库。提供计算几何相关的数据结构和算法,例如曲线整理及其应用,网格生成(二维Delaunay网格生成和三维表面和体积网格生成等),几何处理、搜索结构,插值,形状分析,拟合,距离等。

曲面网格生成 [ make_surface_mesh ]

函数make_surface_mesh()是一个曲面网格生成器,它是构建近似于曲面的二维网格的函数。

多边形网格处理 [ Polygon_mesh_processing ]

Polygon_mesh_processing主要实现多边形的网格处理。包括简单对象的基本操作及复杂的几何处理算法。其包含的基本功能有:

  • 网格划分:网格划分算法,包括非三角网格的三角化、光顺的细化、优化、三角网格的各向同性重网格化和平滑算法
  • 协同细化和布尔运算:协同细化三角形网格和用协同细化的闭合三角形网格计算布尔运算的方法
  • 孔填充:可用的孔填充算法,可以结合细化和光顺
  • 谓词:可在已处理的多边形上计算的谓词。网格,其中包括点定位和自交测试
  • 方向:检查或修复polygon soup的方向
  • 组合修复:多边形网格和polygon soups的修复
  • 法向计算:多边形网格的顶点和面的法向计算
  • 切片器:能够计算多边形网格与任意平面的交点的函子(切片器)
  • 连通组件:处理多边形网格的连通组件的方法(提取、标记、移除等)

(参考网址:https://blog.csdn.net/summer_dew/article/details/116134618)

关键代码分析

meshcombiner.h分析

meshcombiner类定义了在网格粘合中使用到的函数和变量,包括网格类,粘合方式以及粘合网格来源等

class MeshCombiner
{
public:
    enum class Method
    {
        Union,  Diff
    };
    
    enum class Source
    {
        None,First,Second
    };

    class Mesh
    {
    public:
        //构造函数
        Mesh() = default;
        Mesh(const std::vector<QVector3D> &vertices, const std::vector<std::vector<size_t>> &faces, bool disableSelfIntersects=false);
        Mesh(const Mesh &other);
        //析构函数
        ~Mesh();
        //范围函数
        void fetch(std::vector<QVector3D> &vertices, std::vector<std::vector<size_t>> &faces) const;
        bool isNull() const;
        bool isCombinable() const;
        
        friend MeshCombiner;
        
    private:
        void *m_privateData = nullptr;
        bool m_isCombinable = false;
        
        void validate();
    };
    //网格粘合
    static Mesh *combine(const Mesh &firstMesh, const Mesh &secondMesh, Method method,
        std::vector<std::pair<Source, size_t>> *combinedVerticesComeFrom=nullptr);
};

#endif

meshcombiner.cpp分析

MeshCombiner::Mesh::Mesh()函数分析

Mesh()函数主要用于生成曲面网格,通过fetchFromCgalMesh<CgalKernel>(cgalMesh, fetchedVertices, fetchedFaces)函数将几何体的平面信息和顶点信息整合运用,生成三维网格以便进行后续的粘合

MeshCombiner::Mesh::Mesh(const std::vector<QVector3D> &vertices, const std::vector<std::vector<size_t>> &faces, bool disableSelfIntersects)
{
    CgalMesh *cgalMesh = nullptr;//生成一个空的网格曲面
    if (!faces.empty()) {//如果平面非空
        //将平面和点构建出曲面网格并赋给cgalMesh
        cgalMesh = buildCgalMesh<CgalKernel>(vertices, faces);
        if (!disableSelfIntersects) {
            if (!CGAL::is_valid_polygon_mesh(*cgalMesh)) {
                //如果不是有效的多边形网格,清空cgalMesh
                qDebug() << "Mesh is not valid polygon";
                delete cgalMesh;
                cgalMesh = nullptr;
            } else {//如果是有效的多边形网格
                if (CGAL::Polygon_mesh_processing::triangulate_faces(*cgalMesh)) {
                    //如果生成的是三角化曲面
                    if (CGAL::Polygon_mesh_processing::does_self_intersect(*cgalMesh)) {
                        //如果生成的曲面自相交
                        qDebug() << "Mesh does_self_intersect";
                        delete cgalMesh;
                        cgalMesh = nullptr;
                    } else {
						std::vector<QVector3D> fetchedVertices;//获取的顶点
						std::vector<std::vector<size_t>> fetchedFaces;//获取的面
						fetchFromCgalMesh<CgalKernel>(cgalMesh, fetchedVertices, fetchedFaces);//构造获取的曲面网格并返回
						if (!isManifold(fetchedFaces)) {
							qDebug() << "Mesh does not self intersect but is not manifold";
							delete cgalMesh;
							cgalMesh = nullptr;
						} else {
							m_isCombinable = true;
						}
                    }
                } else {
                    //如果生成的不是三角化曲面,清空cgalMesh
                    qDebug() << "Mesh triangulate failed";
                    delete cgalMesh;
                    cgalMesh = nullptr;
                }
            }
        }
    }
    m_privateData = cgalMesh;
    validate();
}

*MeshCombiner::combine()函数分析

combine()函数主要用于独立化网格的合并,将不同的独立网格合并为一个完整的曲面网格模型

MeshCombiner::Mesh *MeshCombiner::combine(const Mesh &firstMesh, const Mesh &secondMesh, Method method,std::vector<std::pair<Source, size_t>> *combinedVerticesComeFrom)
{
	if (firstMesh.isNull() || !firstMesh.isCombinable() ||
			secondMesh.isNull() || !secondMesh.isCombinable())
            //假若任意一个网格是空的,返回
		return nullptr;
	
    CgalMesh *resultCgalMesh = nullptr;
    CgalMesh *firstCgalMesh = (CgalMesh *)firstMesh.m_privateData;//第一个网格
    CgalMesh *secondCgalMesh = (CgalMesh *)secondMesh.m_privateData;//计划粘合的第二个网格
    std::map<PositionKey, std::pair<Source, size_t>> verticesSourceMap;//顶点源映射
    
    auto addToSourceMap = [&](CgalMesh *mesh, Source source) {
        //将网格添加到源映射
        size_t vertexIndex = 0;
        for (auto vertexIt = mesh->vertices_begin(); vertexIt != mesh->vertices_end(); vertexIt++) {
            //网格顶点间的合并进行网格的粘合
            auto point = mesh->point(*vertexIt);
            float x = (float)CGAL::to_double(point.x());
            float y = (float)CGAL::to_double(point.y());
            float z = (float)CGAL::to_double(point.z());
            auto insertResult = verticesSourceMap.insert({{x, y, z}, {source, vertexIndex}});
            ++vertexIndex;
        }
    };
    if (nullptr != combinedVerticesComeFrom) {
        //组合顶点来源非空,将网格firstCgalMesh添加到源映射First与Second
        addToSourceMap(firstCgalMesh, Source::First);
        addToSourceMap(secondCgalMesh, Source::Second);
    }
    
    if (Method::Union == method) {

        resultCgalMesh = new CgalMesh;
        try {
            //处理异常
            if (!CGAL::Polygon_mesh_processing::corefine_and_compute_union(*firstCgalMesh, *secondCgalMesh, *resultCgalMesh)) {
                //如果核心与计算不相交
                delete resultCgalMesh;
                resultCgalMesh = nullptr;
            }
        } catch (...) {
            delete resultCgalMesh;
            resultCgalMesh = nullptr;
        }
    } else if (Method::Diff == method) {
        resultCgalMesh = new CgalMesh;
        try {
            //处理异常
            if (!CGAL::Polygon_mesh_processing::corefine_and_compute_difference(*firstCgalMesh, *secondCgalMesh, *resultCgalMesh)) {
                delete resultCgalMesh;
                resultCgalMesh = nullptr;
            }
        } catch (...) {
            delete resultCgalMesh;
            resultCgalMesh = nullptr;
        }
    }

    if (nullptr != combinedVerticesComeFrom) {
        //组合顶点来源非空,清空combinedVerticesComeFrom
        combinedVerticesComeFrom->clear();
        if (nullptr != resultCgalMesh) {
            for (auto vertexIt = resultCgalMesh->vertices_begin(); vertexIt != resultCgalMesh->vertices_end(); vertexIt++) {
                auto point = resultCgalMesh->point(*vertexIt);//每个网格对应vertexIt
                float x = (float)CGAL::to_double(point.x());
                float y = (float)CGAL::to_double(point.y());
                float z = (float)CGAL::to_double(point.z());
                auto findSource = verticesSourceMap.find(PositionKey(x, y, z));
                if (findSource == verticesSourceMap.end()) {
                    combinedVerticesComeFrom->push_back({Source::None, 0});
                } else {
                    combinedVerticesComeFrom->push_back(findSource->second);
                }
            }
        }
    }
    
    if (nullptr == resultCgalMesh)
        return nullptr;
    
    Mesh *mesh = new Mesh;
    mesh->m_privateData = resultCgalMesh;
    {
        std::vector<QVector3D> vertices;
        std::vector<std::vector<size_t>> faces;
        fetchFromCgalMesh<CgalKernel>(resultCgalMesh, vertices, faces);
        mesh->m_isCombinable = isManifold(faces);
    }
    mesh->validate();
    return mesh;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值