⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 quadtree.m

📁 一个功能强大的非结构网格划分程序,可实现网格的自动剖分,及局部加密与质量控制
💻 M
📖 第 1 页 / 共 2 页
字号:
function [p,t,h] = quadtree(edgexy,hdata,dhmax,wbar)

%  QUADTREE: 2D quadtree decomposition.
%
% A quadtree decomposition of the linear geometry input is performed. The 
% bounding box is recursively subdivided until the dimension of each box 
% matches the local geometry feature size. The geometry feature size is 
% based on the minimum distance between linear geometry segments.
%
% A size function is obtained at the quadtree vertices based on the minimum
% neighbouring box dimension at each vertex. This size function is gradient
% limited to produce a smooth function.
%
% The quadtree is triangulated for use as a background mesh to store the
% size function.
%
%   edgexy  : [x1,y1,x2,y2] edge endpoints
%   hdata   : User defined size function structure
%   dhmax   : Maximum allowalble relative gradient in the size function
%
%   p       : Background mesh nodes
%   t       : Background mesh triangles
%   h       : Size function value at p

%   Darren Engwirda : 2007
%   Email           : d_engwirda@hotmail.com
%   Last updated    : 08/07/2007 with MATLAB 7.0

%% LOCAL FEATURE SIZE
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
waitbar(0,wbar,'Estimating local geometric feature size');

% Get size function data
[hmax,edgeh,fun,args] = gethdata(hdata);

% Insert test points along the boundaries at which the LFS can be
% approximated.
wm = 0.5*(edgexy(:,[1,2])+edgexy(:,[3,4]));                                % Use the edge midpoints as a first pass
len = sqrt(sum((edgexy(:,[3,4])-edgexy(:,[1,2])).^2,2));                   % Edge length
L = 2*dist2poly(wm,edgexy,len);                                            % Estimate the LFS at these points by calculating
                                                                           % the distance to the closest edge segment                           
% In cases where edges are separated by less than their length
% we will need to add more points to capture the LFS in these
% regions. This allows us to pick up "long and skinny" geometry
% features
r = 2*len./L;                                                              % Compare L (LFS approximation at wm) to the edge lengths
r = round((r-2)/2);                                                        % Amount of points that need to be added
add = find(r);                                                             % at each edge
if ~isempty(add)
   num = 2*sum(r(add));                                                    % Total number of points to added
   start = size(wm,1)+1;
   wm = [wm; zeros(num,2)];                                                % Alloc space
   next = start;
   for j = 1:length(add)                                                   % Loop through edges to be subdivided
      cw = add(j);                                                         % Current edge
      num = r(cw);
      tmp = (1:num)'/(num+1);                                              % Subdivision increments
      num = next+2*num-1;

      x1 = edgexy(cw,1); x2 = edgexy(cw,3); xm = wm(cw,1);                 % Edge values
      y1 = edgexy(cw,2); y2 = edgexy(cw,4); ym = wm(cw,2);

      wm(next:num,:) = [x1+tmp*(xm-x1), y1+tmp*(ym-y1)                     % Add to list
                        xm+tmp*(x2-xm), ym+tmp*(y2-ym)];
      next = num+1;
   end
   L = [L; dist2poly(wm(start:next-1,:),edgexy)];                          % Estimate LFS at the new points
end

% Compute the required size along the edges for any boundary layer size
% functions and add additional points where necessary.
if ~isempty(edgeh)
   h0 = edgeh(:,2);
   i = edgeh(:,1);
   for j = 1:length(i)
      if L(i(j))>h0
         cw = i(j);
         r = 2*len(cw)/h0(j);
         r = round((r-2)/2);                                               % Number of points to be added
         tmp = (1:r)'/(r+1);

         x1 = edgexy(cw,1); x2 = edgexy(cw,3); xm = wm(cw,1);              % Edge values
         y1 = edgexy(cw,2); y2 = edgexy(cw,4); ym = wm(cw,2);

         wm = [wm; x1+tmp*(xm-x1), y1+tmp*(ym-y1);                         % Add to list
                   xm+tmp*(x2-xm), ym+tmp*(y2-ym)];

         L(cw) = h0(j);                                                    % Update LFS
         L = [L; h0(j)*ones(2*r,1)];
      end
   end
end

% To speed the point location in the quadtree decomposition
% sort the LFS points based on y-value
[i,i] = sort(wm(:,2));
wm = wm(i,:);
L = L(i);
nw = size(wm,1);

%% UNBALANCED QUADTREE DECOMPOSITION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
waitbar(0.4,wbar,'Quadtree decomposition');

xymin = min([edgexy(:,[1,2]); edgexy(:,[3,4])]);                           % Bounding box
xymax = max([edgexy(:,[1,2]); edgexy(:,[3,4])]);

dim = max(xymax-xymin);                                                    % Bbox dimensions
xm = 0.5*(xymin(1)+xymax(1));
ym = 0.5*(xymin(2)+xymax(2));

p = [xm-0.5*dim, ym-0.5*dim                                                % Initial nodes
     xm+0.5*dim, ym-0.5*dim
     xm+0.5*dim, ym+0.5*dim
     xm-0.5*dim, ym+0.5*dim];
b = [1,2,3,4];                                                             % Initial boxes
h = userhfun(p(:,1),p(:,2),fun,args,hmax,xymin,xymax);

pblock = 5*nw;                                                             % Alloc memory in blocks
bblock = pblock;

np = 4;
nb = 1;
test = true;
while true                                                           
   
   vec = find(test(1:nb));                                                 % Boxes to be checked at this step
   if isempty(vec)
      break
   end

   N = np;
   for k = 1:length(vec)                                                   % Loop through boxes to be checked for subdivision
      
      m  = vec(k);                                                         % Current box
      n1 = b(m,1);  n2 = b(m,2);
      n3 = b(m,3);  n4 = b(m,4);
      x1 = p(n1,1); y1 = p(n1,2);
      x2 = p(n2,1); y4 = p(n4,2);

      % Binary search to find first wm with y>=ymin for current box
      if wm(1,2)>=y1
         start = 1;
      elseif wm(nw,2)<=y1
         start = nw;
      else
         lower = 1;
         upper = nw;
         for i = 1:nw
            start = round(0.5*(lower+upper));
            if wm(start,2)<y1
               lower = start;
            elseif wm(start-1,2)<y1
               break;
            else
               upper = start;
            end
         end
      end

      LFS = 4*min([h(n1),h(n2),h(n3),h(n4),2*hmax/4]);
      for i = start:nw                                                     % Loop through points (acending y-value order)
         if wm(i,2)<=y4                                                    % Check box bounds and current min
            if wm(i,2)>=y1 && wm(i,1)>=x1 && wm(i,1)<=x2 && L(i)<LFS
               LFS = L(i);                                                 % New min found - reset
            end
         else                                                              % Due to the sorting
            break;
         end
      end

      if (x2-x1)>LFS                                                       % Split current box
         if (np+5)>=size(p,1)                                              % Alloc memory on demand
            p = [p; zeros(pblock,2)];
            pblock = 2*pblock;
         end
         if (nb+3)>=size(b,1)
            b = [b; zeros(bblock,4)];
            test = [test; true(bblock,1)];
            bblock = 2*bblock;
         end

         xm = x1+0.5*(x2-x1);                                              % Current midpoints
         ym = y1+0.5*(y4-y1);

         p(np+1,:) = [xm,ym];                                              % New nodes
         p(np+2,:) = [xm,y1];
         p(np+3,:) = [x2,ym];
         p(np+4,:) = [xm,y4];
         p(np+5,:) = [x1,ym];

         b(m,:)    = [n1,np+2,np+1,np+5];                                  % New boxes
         b(nb+1,:) = [np+2,n2,np+3,np+1];
         b(nb+2,:) = [np+1,np+3,n3,np+4];
         b(nb+3,:) = [np+5,np+1,np+4,n4];

         nb = nb+3;
         np = np+5;
      else
         test(m) = false;
      end
   end

   h = [h; userhfun(p(N+1:np,1),p(N+1:np,2),fun,args,hmax,xymin,xymax)];
end
p = p(1:np,:);
b = b(1:nb,:);

[p,i,j] = unique(p,'rows');                                                % Delete replicated nodes
h = h(i);
b = reshape(j(b),size(b));

%% FORM SIZE FUNCTION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
waitbar(0.6,wbar,'Forming element size function')

E = [b(:,[1,2]); b(:,[2,3]); b(:,[3,4]); b(:,[4,1])];                      % Edges
L = sqrt(sum((p(E(:,1),:)-p(E(:,2),:)).^2,2));                             % Edge length

nE = size(E,1);
for k = 1:nE                                                               % Initial h - minimum neighbouring edge length
   if L(k)<h(E(k,1))
      h(E(k,1)) = L(k); 
   end             
   if L(k)<h(E(k,2))
      h(E(k,2)) = L(k); 
   end
end

% Gradient limiting
tol = 1e-4;
while true                                                                 % Loop over the edges of the background mesh ensuring
   h_old = h;                                                              % that dh satisfies the dhmax tolerance
   for k = 1:nE                                                            % Loop over edges
      n1 = E(k,1);
      n2 = E(k,2);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -