CGAL-Triangulation中的单元和面的关系

点集表征空间是最简便也是较为经济的方式,但是很多时候,点集过于粗糙,无法满足人们对空间划分的精度要求,因此以点集为基础对空间进行的剖分工具就显得异常重要。CGAL中的三维三角剖分包(3D Triangulations Packages)是一款非常灵活的空间划分工具包,它以四面体为基本单元,可对提供的点集进行Delaunay三角剖分和正则三角剖分。

CGAL提供的数据结构一方面能够满足对几何体的几何信息和拓扑的描述,另一方面也要照顾算法灵活性和广泛性的需要,要能够满足算法的需要。本文通过一个示例去查看CGAL-Triangulation中的单元和面的关系。

一、数据准备:

给定4个点的点集数据,存放在points的vector容器中。

4
0   0   0   0
1   1   0   0
2   1   1   0
3   0   0   1

二、三角剖分

对点集进行三角剖分,得到如图所示的两个四面体。

//kernel
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
​
#include <CGAL/Delaunay_triangulation_3.h>
#include <CGAL/Delaunay_triangulation_cell_base_with_circumcenter_3.h>
#include <CGAL/Triangulation_vertex_base_with_info_3.h>
​
typedef CGAL::Exact_predicates_exact_constructions_kernel                       Kernel_epec;
typedef CGAL::Triangulation_vertex_base_with_info_3<unsigned, Kernel_epec>      Vb;
typedef CGAL::Delaunay_triangulation_cell_base_with_circumcenter_3<Kernel_epec> Cb;
typedef CGAL::Triangulation_data_structure_3<Vb, Cb>                            Tds;
typedef CGAL::Delaunay_triangulation_3<Kernel_epec, Tds>                        Delaunay;
​
Delaunay T;
T.insert(points.begin(), points.end());

 三、单元统计

CGAL的三角剖分数据结构满足拓扑的完备性,图中显示的两个四面体是作为两个有限单元(finite cell),另外图中外侧的6个边界三角形面与一个无穷远点(通常以坐标(0,0,0)表示)构成了边界上的无限单元(infinite cell),这样全部的单元数为8。具体各个单元的情况如下表所示。

单元节点序号节点坐标x节点坐标y节点坐标z备注
单元:01#单元032面无限元
无穷点000
0100
2000
3001
单元:11#单元有限元
0100
1010
2000
3001
单元:01#单元123面无限元
1010
无穷点000
2000
3001
单元:01#单元021面无限元
0100
2000
1010
无穷点000
单元:02#单元013面无限元
0001
无穷点000
1100
3110
单元:02#单元032面无限元
0001
2010
无穷点000
3110
单元:22#单元有限元
0001
1100
2010
3110
单元:02#单元231面无限元
2010
1100
无穷点000
3110

四、单元(cell)与面(facet)的关系

每个单元有4个关联面,每个面有2个关联单元。面通过单元句柄+对面的顶点号两个数据构成的数据对表示,即(单元句柄、对面顶点号)。

for (Delaunay::Finite_facets::iterator it = this->T.finite_facets_begin();
        it != this->T.finite_facets_end(); ++it)
    {
        //输出表示单元的数据对,it->first是单元句柄,it->second是对面顶点号。
        std::cout << "单元和指示面的节点:";
        std::cout << cells_index[it->first] << "  " << it->second ;
        //如果第i面不是以无限单元表示的,若是则打印提示信息。
        if(this->T.is_infinite(it->first))
        std::cout << "  该面使用无限元表示。" << std::endl;
        
        //对共面的邻居单元的4个顶点遍历,当邻居单元顶点相对的相邻单元==共面的本单元时,输出邻居单元的坐标。
        for (int i = 0; i < 4; ++i)
        {
            //判断的意涵:与当前单元(it->first)的it->second节点的对面共面的
            //相邻单元的节点i的对面的相邻单元==当前单元,此处的i指的是当前单元相邻单元的i节点
            if (cells_index[it->first->neighbor(it->second)->neighbor(i)] == cells_index[it->first])
            {
                std::cout << "表示当前面所使用的单元:" << cells_index[it->first] << std::endl;
                std::cout << "表示当前面所使用单元的邻居单元:" << cells_index[it->first->neighbor(it->second)] << std::endl;
                std::cout << "表示当前面所使用单元的邻居的邻居单元:" << cells_index[it->first->neighbor(it->second)->neighbor(i)] << std::endl;
​
​
                std::cout << "第 " << i << " 点坐标:" << it->first->neighbor(it->second)->vertex(i)->point() << std::endl;
​
            }
        }

输出结果为:

单元和指示面的节点:0  0  该面使用无限元表示。
表示当前面所使用的单元:0
表示当前面所使用单元的邻居单元:1
表示当前面所使用单元的邻居的邻居单元:0
第 0 点坐标:1 0 0
表示当前面所使用的单元:0
表示当前面所使用单元的邻居单元:1
表示当前面所使用单元的邻居的邻居单元:0
第 1 点坐标:0 1 0
表示当前面所使用的单元:0
表示当前面所使用单元的邻居单元:1
表示当前面所使用单元的邻居的邻居单元:0
第 3 点坐标:0 0 1
​
单元和指示面的节点:1  0
表示当前面所使用的单元:1
表示当前面所使用单元的邻居单元:0
表示当前面所使用单元的邻居的邻居单元:1
第 1 点坐标:0 0 0
​
单元和指示面的节点:1  2
表示当前面所使用的单元:1
表示当前面所使用单元的邻居单元:2
表示当前面所使用单元的邻居的邻居单元:1
第 3 点坐标:1 1 0
​
单元和指示面的节点:1  3
表示当前面所使用的单元:1
表示当前面所使用单元的邻居单元:0
表示当前面所使用单元的邻居的邻居单元:1
第 3 点坐标:0 0 0
​
单元和指示面的节点:0  1  该面使用无限元表示。
表示当前面所使用的单元:0
表示当前面所使用单元的邻居单元:2
表示当前面所使用单元的邻居的邻居单元:0
第 0 点坐标:0 0 1
表示当前面所使用的单元:0
表示当前面所使用单元的邻居单元:2
表示当前面所使用单元的邻居的邻居单元:0
第 1 点坐标:1 0 0
表示当前面所使用的单元:0
表示当前面所使用单元的邻居单元:2
表示当前面所使用单元的邻居的邻居单元:0
第 2 点坐标:0 1 0
​
单元和指示面的节点:0  2  该面使用无限元表示。
表示当前面所使用的单元:0
表示当前面所使用单元的邻居单元:2
表示当前面所使用单元的邻居的邻居单元:0
第 0 点坐标:0 0 1
表示当前面所使用的单元:0
表示当前面所使用单元的邻居单元:2
表示当前面所使用单元的邻居的邻居单元:0
第 1 点坐标:1 0 0
表示当前面所使用的单元:0
表示当前面所使用单元的邻居单元:2
表示当前面所使用单元的邻居的邻居单元:0
第 2 点坐标:0 1 0
​
单元和指示面的节点:2  0
表示当前面所使用的单元:2
表示当前面所使用单元的邻居单元:0
表示当前面所使用单元的邻居的邻居单元:2
第 2 点坐标:0 0 0
​
  共有: 7 个面

从上述输出结果可以看出:

1、每个边界三角形面都对应一个无限单元,虽然无限单元的数量可以很多,但单元标识只有一个,那就是0号单元;

2、有限单元从1按顺序编号;

3、无论是内部面还是外部面都有两个关联单元,面既可以用有限元表示,也可以用无限元表示。为满足唯一性要求,只能选择其中一个关联单元+对顶点表示面。

4、用两次neighbor(),可以再次指向原来的面。当取对 i 时,it->first->neighbor(it->second)->neighbor(i)==it->first。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值