之前转载了一篇博客http://blog.sina.com.cn/s/blog_6163bdeb0102dvay.html,讲Matlab网格划分程序Distmesh,看了看程序,感觉程序写得有很多值得学的地方,所以又自己重新看了一看,加了一些注释,最后再总结一下学到的东西吧。

源代码的地址已经改变,如下http://people.sc.fsu.edu/~jburkardt/m_src/distmesh/distmesh.html。程序给出了20个划分的例子,文件名为p1_demo.m~p20_demo.m,直接运行程序可以看到划分的动画效果,每个例子基本都是设置一些参数,然后调用distmesh_2d函数进行网格划分,最后得到划分的节点p和各三角形t,最后将划分的三角形绘制出来。划分结果如下

p1_demo                                    p14_demo

p5_demo                                      p18_demo

进一步加注释的程序(需要学习的地方用颜色标记):

function [ p, t ] = distmesh_2d ( fd, fh, h0, box, iteration_max, pfix, varargin )
%% DISTMESH_2D is a 2D mesh generator using distance functions.
%  Example:
%    Uniform Mesh on Unit Circle:
%      fd = inline('sqrt(sum(p.^2,2))-1','p');
%      [p,t] = distmesh_2d(fd,@huniform,0.2,[-1,-1;1,1],100,[]);
%    Rectangle with circular hole, refined at circle boundary:
%      fd = inline('ddiff(drectangle(p,-1,1,-1,1),dcircle(p,0,0,0.5))','p');
%      fh = inline('min(4*sqrt(sum(p.^2,2))-1,2)','p');
%      [p,t] = distmesh_2d(fd,fh,0.05,[-1,-1;1,1],500,[-1,-1;-1,1;1,-1;1,1]);
%  Parameters:
%    Input, function FD, signed distance function d(x,y).
%    fd:d=fd(p),p=[x y],fd为给定任一点到边界的有符号距离函数,负号表示在区域内,正号为在区域外
%    Input, function FH, scaled edge length function h(x,y).
%    fh:就是网格大小的函数
%    Input, real H0, the initial edge length.
%    h0:也就是h, 网格的初始大小
%    Input, real BOX(2,2), the bounding box [xmin,ymin; xmax,ymax].
%    box:最大外围矩形范围
%    Input, integer ITERATION_MAX, the maximum number of iterations.
%    The iteration might terminate sooner than this limit, if the program decides
%    that the mesh has converged.
%    iteration_max:允许的最大迭代次数
%    Input, real PFIX(NFIX,2), the fixed node positions.
%    pfix:网格中需要固定的点坐标,也就是一定需要出现在网格中的点
%    Input, VARARGIN, aditional parameters passed to FD and FH.%
%    Output, real P(N,2), the node positions.
%    p:网格点的x,y坐标
%    Output, integer T(NT,3), the triangle indices.
%    t:输出网格任意一个三角形的三个顶点
%  Local parameters:
%    Local, real GEPS, a tolerance for determining whether a point is "almost" inside
%    the region.  Setting GEPS = 0 makes this an exact test.  The program currently
%    sets it to 0.001 * H0, that is, a very small multiple of the desired side length
%    of a triangle.  GEPS is also used to determine whether a triangle falls inside
%    or outside the region.  In this case, the test is a little tighter.  The centroid
%    PMID is required to satisfy FD ( PMID ) <= -GEPS.
%    局部变量geps:容忍度,一个点是否属于区域,也在判断三角形是否属于区域内时使用

dptol = 0.001;              % 收敛精度
ttol = 0.1;                 % 三角形划分精度(百分比)
Fscale = 1.2;               % 放大比例
deltat = 0.2;               % 相当于柔度
geps = 0.001 * h0;          % 容忍度
deps = sqrt ( eps ) * h0;   % 微小变化dx
iteration = 0;              % 迭代次数
triangulation_count = 0;    % 三角形划分次数

%  1. Create the initial point distribution by generating a rectangular mesh
%  in the bounding box.
% 根据初始网格的大小h0,先把能涵盖欲划分区域的最大矩形划分为结构网格。
[ x, y ] = meshgrid ( box(1,1) : h0           : box(2,1), ...
    box(1,2) : h0*sqrt(3)/2 : box(2,2) );
%  Shift the even rows of the mesh to create a "perfect" mesh of equilateral triangles.
%  Store the X and Y coordinates together as our first estimate of "P", the mesh points
%  we want.
% 然后把偶数行的点整体向右平移半格,得到正三角形划分
x(2:2:end,:) = x(2:2:end,:) + h0 / 2;
p = [ x(:), y(:) ];
%  2. Remove mesh points that are outside the region,
%  then satisfy the density constraint.
%  Keep only points inside (or almost inside) the region, that is, FD(P) < GEPS.
% 根据fd的函数定义,移除边界外的点
p = p( feval_r( fd, p, varargin{:} ) <= geps, : ); % 1
%  Set R0, the relative probability to keep a point, based on the mesh density function.
r0 = 1 ./ feval_r( fh, p, varargin{:} ).^2;
%  Apply the rejection method to thin out points according to the density.
% 根据网格密度函数fh,每个点上产生一个0-1随机数,判断是否小于r0/max(r0)大于的话,该点被删除
p = [ pfix; p(rand(size(p,1),1) < r0 ./ max ( r0 ),: ) ];
[ nfix, dummy ] = size ( pfix );
%  Especially when the user has included fixed points, we may have a few
%  duplicates.  Get rid of any you spot.
% 当指定了某些点要保留的时候,把保留的点加入,删除重复的点。
p = unique ( p, 'rows' ); % 2

N = size ( p, 1 );

%  If ITERATION_MAX is 0, we're almost done.
%  For just this case, do the triangulation, then exit.
%  Setting ITERATION_MAX to 0 means that we can see the initial mesh
%  before any of the improvements have been made.
% 如果最大迭代次数为负,则直接结束
if ( iteration_max <= 0 )
    t = delaunayn ( p ); % 3
    triangulation_count = triangulation_count + 1;
    return
end
pold = inf; % 第一次迭代前设置旧的点的坐标为无穷
while ( iteration < iteration_max )
    iteration = iteration + 1;
    if ( mod ( iteration, 10 ) == 0 )
        fprintf ( 1, '  %d iterations,', iteration );
        fprintf ( 1, '  %d triangulations.\n', triangulation_count );
    end
   
    %  3. Retriangulation by the Delaunay algorithm.
    %  Was there large enough movement to retriangulate?
    %  If so, save the current positions, get the list of
    %  Delaunay triangles, compute the centroids, and keep
    %  the interior triangles (whose centroids are within the region).
    %
    % 先判断上次移动后的点和旧的点之间的移动距离,如果小于某个阀值,停止迭代
    if ( ttol < max ( sqrt ( sum ( ( p - pold ).^2, 2 ) ) / h0 ) )
        pold = p;               % 如果还可以移动,保存当前的节点
        t = delaunayn ( p );    % 利用delauny算法,生成三角形网格
        triangulation_count = triangulation_count + 1;          % 划分次数加1
        pmid = ( p(t(:,1),:) + p(t(:,2),:) + p(t(:,3),:) ) / 3; % 计算三角形的重心
        t = t( feval_r( fd, pmid, varargin{:} ) <= -geps, : );   % 移除重心在区域外的三角形
       
        %  4. Describe each bar by a unique pair of nodes.
        % 生成网格的边的集合,也就是相邻点之间连接的线段
        bars = [ t(:,[1,2]); t(:,[1,3]); t(:,[2,3]) ];
        bars = unique ( sort ( bars, 2 ), 'rows' );
       
        %  5. Graphical output of the current mesh
        trimesh ( t, p(:,1), p(:,2), zeros(N,1) )               % 绘制划分的三角形% 3
        view(2), axis equal, axis off, drawnow
    end
   
    %  6. Move mesh points based on bar lengths L and forces F
    %  Make a list of the bar vectors and lengths.
    %  Set L0 to the desired lengths, F to the scalar bar forces,
    %  and FVEC to the x, y components of the bar forces.
    %  At the fixed positions, reset the force to 0.
    barvec = p(bars(:,1),:) - p(bars(:,2),:);   % 生成bar的矢量
    L = sqrt ( sum ( barvec.^2, 2 ) );          % 计算bar的长度
    % 根据每个bar的中点坐标,计算需要的三角形边的边长(这个在fh函数里控制)
    hbars = feval_r( fh, (p(bars(:,1),:)+p(bars(:,2),:))/2, varargin{:} );
    % 计算需要的bar的长度,已经乘上了两个scale参数 Fscale, sqrt ( sum(L.^2) / sum(hbars.^2) );
    % 具体可参考他们的paper
    L0 = hbars * Fscale * sqrt ( sum(L.^2) / sum(hbars.^2) );
    % 计算每个bar上力
    F = max ( L0 - L, 0 );
    % bar上力的分量,x,y方向
    Fvec = F ./ L * [1,1] .* barvec;
    % 计算Ftot, 每个节点上力的残量
    Ftot = full ( sparse(bars(:,[1,1,2,2]),ones(size(F))*[1,2,1,2],[Fvec,-Fvec],N,2) );
    % 对于固定点,力的残量为零
    Ftot(1:size(pfix,1),:) = 0;
    % 根据每个节点上的受力,移动该点
    p = p + deltat * Ftot;
   
    %  7. Bring outside points back to the boundary
    %  Use the numerical gradient of FD to project points back to the boundary.
    d = feval_r( fd, p, varargin{:} ); % 计算点到边界距离
    ix = d > 0;
    % 计算移动梯度,相对边界
    dgradx = ( feval_r(fd,[p(ix,1)+deps,p(ix,2)],varargin{:}) - d(ix) ) / deps; % 4
    dgrady = ( feval_r(fd,[p(ix,1),p(ix,2)+deps],varargin{:}) - d(ix) ) / deps;
    % 将这些移动到边界外的投射回边界上
    p(ix,:) = p(ix,:) - [ d(ix) .* dgradx, d(ix) .* dgrady ];
    %  I needed the following modification to force the fixed points to stay.
    %  Otherwise, they can drift outside the region and be lost.
    % 修正,以免一些点移到区域外而丢失
    p(1:nfix,1:2) = pfix;
    N = size ( p, 1 );
   
    %  8. Termination criterion: All interior nodes move less than dptol (scaled)
    if ( max ( sqrt ( sum ( deltat * Ftot ( d < -geps,:).^2, 2 ) ) / h0 ) < dptol )
        break;
    end
end
end

值得学习的地方:

1.feval_r(fd, p, varargin{:})

这相当于是回调函数的用法,将某些完成特定功能的函数作为输入参数传递进来,需要实现某些功能时则调用此函数,这样当想改变特定功能时,直接改变传进来的函数句柄就可以了。而且完成特定功能的函数的额外参数可以由varargin传入。

2.unique ( p, 'rows' );

unique函数属于时间序列分析中的功能,最近借了一本书正好看到,时间序列有一些列处理方法函数,可以很方便的处理作为时间序列的向量。

3.delaunayn 、trimesh

这是涉及三角形划分的matlab功能,感觉挺使用的。一方面,有限元方法需要网格划分,有这些函数,如虎添翼,另外在matlab实现三维的类似OpenGL的显示、操作等,使用patch最方便了,而patch最方便的使用方法是传入点和面,而如何构造点和面呢,这里给出了很好的答案。

4.deps = sqrt ( eps ) * h0;   % 微小变化dx

dgradx = ( feval_r(fd,[p(ix,1)+deps,p(ix,2)],varargin{:}) - d(ix) ) / deps;

这个相当于是求函数微分、梯度,本来matlab函数传入的量是离散的,感觉顶多求差分,突然发现这种想法太简单了,函数的定义域是连续的,连续的就可以求微分,这里提供了一种很好方法。

这也提供了一种很好的提示,以前一直拿c、c++的编程思想用matlab,现在发现使用matlab的更有效率的方法是使用数学函数的思想,matlab的函数不是c、c++中响应函数的那个函数,而是定义在实数域上的数学函数,用来处理各种数学问题。也可能是之前理解c、c++中的函数就应该用这种思想吧!

此程序中就实现了各种数学意义上的计算,如求点到线的距离、求梯度、算分量等,看了这个程序,才感觉matlab确实是数学的语言工具。

Matlab网格划分的更多相关文章

  1. Cesium原理篇:2最长的一帧之网格划分

    上一篇我们从宏观上介绍了Cesium的渲染过程,本章延续上一章的内容,详细介绍一下Cesium网格划分的一些细节,包括如下几个方面: 流程 Tile四叉树的构建 LOD 流程 首先,通过上篇的类关系描 ...

  2. cesium原理篇(二)--网格划分【转】

    转自:http://www.cnblogs.com/fuckgiser/p/5772077.html 上一篇我们从宏观上介绍了Cesium的渲染过程,本章延续上一章的内容,详细介绍一下Cesium网格 ...

  3. 【小白的CFD之旅】21 网格划分软件的选择

    但是怎样才能获得流体计算网格呢?“工欲善其事必先利其器”,画网格该用什么器呢?小白决定找黄师姐请教一番. 小白找到黄师姐的时候,黄师姐正在电脑上忙着. “黄师姐,我发现网格划分软件有好多种,究竟哪种才 ...

  4. [转载]workbench分网---mapped face meshing面映射网格划分

    原文地址:face meshing面映射网格划分">workbench分网---mapped face meshing面映射网格划分作者:一丝尘埃 face meshing面映射网格划 ...

  5. meshing-球体网格划分

    原视频下载地址:https://yunpan.cn/cqwvgQQ2xy3G6  访问密码 a54b

  6. meshing-圆锥网格划分

    原视频下载地址: https://pan.baidu.com/s/1boSjGXh 密码: 9zis

  7. MATLAB代码

    clear;clc%%%%%%%%%%%%方程里的参量%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%alpha=0.5;beta=0.5;%%% ...

  8. Fluent动网格【10】:区域运动案例

    本案例主要描述如何在Fluent中处理包含了公转和自转的复合运动.涉及到的内容包括: 多区域模型创建 滑移网格设置 区域运动UDF宏DEFINE_ZONE_MOTION 案例描述 案例几何如图所示. ...

  9. 【小白的CFD之旅】19 来自计算网格的困惑

    经过一年的忙碌,终于又到了寒假时间,小白又满状态复活了. 这一年小白学了很多的课程,但是一年下来,小白却感觉脑袋里没留下什么东西,貌似什么东西都在考完试的那一刹那全还回给老师了.这一年学习之余,小白仍 ...

随机推荐

  1. MVC client validation after PartialView loaded via Ajax MVC3中 弹出 Dialog时候 提交的时候 使用 Jquery 不验证 form表单 的解决办法

    I came across this scenario whereby my main View uses Ajax posts to retrieve PartialViews and delive ...

  2. PTA 5-12 排序 (25分)

    给定NN个(长整型范围内的)整数,要求输出从小到大排序后的结果. 本题旨在测试各种不同的排序算法在各种数据情况下的表现.各组测试数据特点如下: 数据1:只有1个元素: 数据2:11个不相同的整数,测试 ...

  3. iOS 静态库和动态库

    这两个东西都是编译好的二进制文件.就是用法不同而已.为什么要分为动态和静态两种库呢?先看下图:

  4. BAPI

    MM模块 1. BAPI_MATERIAL_SAVEDATA 创建物料主数据 注意参数EXTENSIONIN的使用,可以创建自定义字段 例如:WA_BAPI_TE_MARA-MATERIAL = IT ...

  5. Android解析Json速度最快的库:json-smart

    场景描写叙述: 本文仅验证了在安卓环境下使用Json的Key作为反序列化条件的解析速度.结论是解析速度最快的不是阿里的fastjson,也不是Google的Gson,而是json-smart. And ...

  6. [Webpack 2] Use Karma for Unit Testing with Webpack

    When writing tests run by Karma for an application that’s bundled with webpack, it’s easiest to inte ...

  7. 导入cocos2d-x samples android官方示例

    导了一晚上samples android示例,查了一晚上资料,费了很大的劲,终于成功导入并运行成功,分享一下经验: 1.下载eclipse与ADT跟android SDK,相信大家都会装了吧. 2.下 ...

  8. java.sql.SQLException: Lock wait timeout exceeded --转

    org.springframework.dao.CannotAcquireLockException 的解决> 直接上 bug 的详细信息: 2012-03-12 15:20:31 XmlBea ...

  9. 宽字节SQL注入

    1.联想lelink站 例1, 联想lelink站user参数存在宽字节SQL注入 提交,user=wctest%df’ and 1=2%23 结果,出现了”運”字,如图:

  10. 关于Bufferedreader的功能扩写

    package cn.hncu.pattern.decorator.v1; import java.io.FileReader;import java.io.IOException; public c ...