MATLAB实现三角剖分(Delaunay)算法

三角剖分定义

        【定义】三角剖分:假设V是二维实数域上的有限点集,边e是由点集中的点作为端点构成的封闭线段,E为e的集合。那么该点集V的一个三角剖分T = (V,E)是一个平面图G,该平面图满足条件:

        1、除了端点,平面图中的边不包含点集中的任何点。

        2、没有相交边。// 边和边没有交叉点。

        3、平面图中所有的面都是三角面,且所有三角面的合集是散点集V的凸包。

        // 凸包的概念:用不严谨的话来讲,给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边型,它能包含点集中所有的点。



Delaunay三角剖分的定义

         在实际中运用的最多的三角剖分是Delaunay三角剖分,它是一种特殊的三角剖分。先从Delaunay边说起:

        【定义】Delaunay边:假设E中的一条边e (两个端点为a,b),e若满足下列条件,则称之为Delaunay边:存在一个圆经过a,b两点,圆内(注意是圆内,圆上最多三点共圆)不含点集V中任何其他的点,这一特性又称空圆特性。

        【定义】Delaunay三角剖分:如果点集V的一个三角剖分T只包含Delaunay边,那么该三角剖分称为Delaunay三角剖分。



Delaunay三角剖分的准则

        要满足Delaunay三角剖分的定义,必须符合两个重要的准则:

        1、空圆特性:Delaunay三角网是唯一的(任意四点不能共圆),在Delaunay三角形网中任一三角形的外接圆范围内不会有其它点存在。如下图所示:


        2、最大化最小角特性:在散点集可能形成的三角剖分中,Delaunay三角剖分所形成的三角形的最小角最大。从这个意义上讲,Delaunay三角网是"最接近于规则化的"三角网。具体的说是在两个相邻的三角形构成凸四边形的对角线,在相互交换后,两个内角的最小角不再增大。如下图所示:



Delaunay三角剖分的特性

        以下是Delaunay剖分所具备的优异特性:

        1、最接近:以最接近的三点形成三角形,且各线段(三角行的边)皆不相交。

        2、唯一性:不论从区域何处开始构建,最终都将得到一致的结果。

        3、最优性:任意两个相邻三角形构成的凸四边形的对角线如果可以互换,那么两个三角形六个内角中最小角度不会变化。

        4、最规则:如果将三角网中的每个三角形的最小角进行升序排列,则Delaunay三角网的排列得到的数值最大。

        5、区域性:新增、删除、移动某一个顶点只会影响邻近的三角形。

        6、具有凸边形的外壳:三角网最外层的边界形成一个凸多边形的外壳。



局部最优化处理

        理论上为了构造Delaunay三角网,Lawson提出的局部优化过程LOP(Local Optimization Procedure),一般三角网经过LOP处理,即可确保为Delaunay三角网,其基本做法如下所示:

        1、将两个具有共同边的三角形合成一个多边形。

        2、以最大空圆准则作检查,看其第四个顶点是否在三角形的外接圆内。

        3、如果在,修正对角线即将对角线对调,即完成局部优化过程的处理。

        LOP处理过程如下图所示:




Delaunay剖分的算法

        Delaunay剖分是一种三角剖分的标准,实现它有多种算法。最常用的是逐点插入法。

        Lawson算法的基本步骤是:

        1、构造一个超级三角形,包含所有散点,放入三角形链表。

        2、将点集中的散点依次插入,在三角形链表中找出其外接圆包含插入点的三角形(称为该点的影响三角形),删除影响三角形的公共边,将插入点同影响三角形的全部顶点连接起来,从而完成一个点在Delaunay三角形链表中的插入。

        3、根据优化准则对局部新形成的三角形进行优化。将形成的三角形放入Delaunay三角形链表。

        4、循环执行上述第2步,直到所有散点插入完毕。

        这一算法的关键的第2步图示如下:




伪代码表述

input: 顶点列表(vertices)                   // vertices为外部生成的随机或乱序顶点列表
output:已确定的三角形列表(triangles)
    初始化顶点列表
    创建索引列表(indices = new Array(vertices.length))     // indices数组中的值为0,1,2,3,......,vertices.length-1
    基于vertices中的顶点x坐标对indices进行sort    // sort后的indices值顺序为顶点坐标x从小到大排序(也可对y坐标,本例中针对x坐标)
    确定超级三角形
    将超级三角形保存至未确定三角形列表(temp triangles)
    将超级三角形push到triangles列表
    遍历基于indices顺序的vertices中每一个点       // 基于indices后,则顶点则是由x从小到大出现
      初始化边缓存数组(edge buffer)
      遍历temp triangles中的每一个三角形
        计算该三角形的圆心和半径
        如果该点在外接圆的右侧
          则该三角形为Delaunay三角形,保存到triangles
          并在temp里去除掉
          跳过
        如果该点在外接圆外(即也不是外接圆右侧)
          则该三角形为不确定                     //后面会在问题中讨论
          跳过
        如果该点在外接圆内
          则该三角形不为Delaunay三角形
          将三边保存至edge buffer
          在temp中去除掉该三角形
      对edge buffer进行去重
      将edge buffer中的边与当前的点进行组合成若干三角形并保存至temp triangles中
    将triangles与temp triangles进行合并
    除去与超级三角形有关的三角形
end


MATLAB实现

clc;
clear;
close all;

rand('state', 0);
node = 8;
x = rand(1,node);
y = rand(1,node);
% delaunay是MATLAB中三角剖分的函数,返回的TRI是三角形的矩阵
% TRI的每一行表示三角形的三个点
TRI = delaunay(x,y);

% 绘图
figure; 
xmin = min(x(:)); xmax = max(x(:));
ymin = min(y(:)); ymax = max(y(:));
xl = xmax - xmin; yl = ymax - ymin;
axis([xmin-xl*0.1, xmax+xl*0.1,...
    ymin-yl*0.1, ymax+yl*0.1]);
hold on;

n = size(TRI, 1);
for i = 1 : n
    t1 = TRI(i, :);
    for j = 1 : length(t1)-1
        xt = [x(t1(j)) x(t1(j+1))];
        yt = [y(t1(j)) y(t1(j+1))];
        plot(xt, yt, 'k-', 'LineWidth', 2);
        pause(0.1);
    end
    xt = [x(t1(end)) x(t1(1))];
    yt = [y(t1(end)) y(t1(1))];
    plot(xt, yt, 'k-', 'LineWidth', 2);
    pause(0.1);
end

W = zeros(node);
for i = 1 : n
    for j = 1 : length(TRI(i, :))-1
        W(TRI(i, j), TRI(i, j+1)) = 1;
        W(TRI(i, j+1), TRI(i, j)) = 1;
    end
    W(TRI(i, end), TRI(i, 1)) = 1;
    W(TRI(i, 1), TRI(i, end)) = 1;
end
for i = 1 : node
    for j = 1 : node
        if ~W(i, j)
            W(i, j) = 10000;
        end
    end
end


利用delaunay函数划分网格欢迎指点探讨-DelaunayWithGrid.m 本帖最后由 liuf412044725 于 2013-6-8 17:47 编辑 近期论坛上有不少讨论delaunay函数的帖子。似乎主要有以下问题: 1、delaunay函数各参数的意义 2、知道几何边界时,用delaunay函数划分三角形网格由于区域内部没有点,质量很差,怎么改进 3、怎样避免产生过于狭长的delaunay 三角形 4、 凹多边形的情况怎么处理 第1个问题,看看帮助应该能解决。第2个问题,delaunay本来是用来对离散点进行三角剖分,内部没有点时并不合适。除非特别处理。第3个问题,估计是利用delaunay和meshgrid来划网格,边界附近会产生狭长的delaunay 三角形,这个也可以做特别处理。第4个问题,可以用在划分好网格后删掉域外的三角形即可。 由于我也经常使用delaunay来处理背景积分问题,因此仔细琢磨了一下用delaunay来划分已知边界的几何区域的可行方案,在此和大家分享一下,也是抛砖引玉,希望大家有更好的方法。 方案一:先对区域delaunay剖分,删掉域外的三角形,然后将剩下的三角形的边细分,得到新的离散点,然后再次delaunay剖分,然后再次细分边,这样循环下去,直到达到一定的尺寸为止 方案二:利用delaunay和meshgrid函数。将边界细分得到相比原区域边界更加密集边界点,用meshgrid得到包含整个区域的点,将域内的点和边界点一起delaunay 剖分。 讨论: 方案一对于一开始就有很小边界段的情况情况较差,容易出现狭长单元(比如边界有圆弧的话属于这种情况)。还有就是前一步的边界轮廓很清楚,看着别扭。方案二中间的网格能搞保证形状较好。对于边界附近的内部点,容易导致边界单元畸变,可以将离边界太近的点进行删除,这样得到的形状比较好 综合来说,方案二较好,尤其是当删掉离边界太近的内部点。贴出程序,望大家多多指点,共同进步。 P.S. 当然,matlab自身也有很好的网格划分函数,在pdetool中有用到,不过关于几何描述那块比较难以理解(我不是很理解)。另外matlab语言写的划分网格的程序很多,网上可以找到不少很优秀的。这里仅限于简单的使用delaunay来划分。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值