demo14 of Im2mesh package
demo14 - Edit polygonal boundary before meshing
Initialize
No need to install any MATLAB toolboxes when running this demo.
Before we start, please set folder "Im2mesh_Matlab" as your current folder of MATLAB.
Set default image size (optional).
x = 250; y = 250; width = 300; height = 300;
set(groot, 'DefaultFigurePosition', [x,y,width,height])
% set(groot, 'DefaultFigurePosition', 'factory')
Function bounds2mesh use a mesh generator called MESH2D (developed by Darren Engwirda). We can use the following command to add the folder 'mesh2d-master' to the path of MATLAB.
addpath(genpath('mesh2d-master'))
Convert Image to polyshape
Load Image
im = imread('Circle2.tif');
if size(im,3) == 3; im = rgb2gray( im ); end
imshow( im,'InitialMagnification','fit' );
Get boundries from image
We have demostrate how to do this in example3 of demo01.mlx
bounds = im2mesh( im, opt );
% bounds is the simplified polygonal boundaries
Convert to polyshape
It's tedious to edit boundaries directly. Using polyshape object will make things easier. We have demostrated polyshape in demo12. Please take a look at demo12.
Here, we use function bound2polyshape to convert a cell array of polygonal boundaries 'bounds' to a cell array of polyshape 'psCell'.
psCell = bound2polyshape(bounds);
Plot cell array of polyshape.
for i = 1: length(psCell)
Coordinates of 4 corners
Before we edit polyshape, we want to know about the x y coordinates of 4 corners in in variable psCell.
First, let's get the image size. This is for comparison.
So the height and width of the input image is 88 and 90, respectively. The bottom left corner in the image is [0, 0]. The upper right corner in the image is [90, 88].
We use function xyRange to get the range of x y coordinates in boundary or polyshape.
[xmin,xmax,ymin,ymax] = xyRange( psCell )
xmin = 0.5000
xmax = 90.5000
ymin = 0.5000
ymax = 88.5000
So we can know the location of bottom left corner and upper right corner in the polygonal boundary.
xyBottomLeft = [ xmin, ymin ]
xyUpRight = [ xmax, ymax ]
Compared this with the size of the image, we notice a 0.5 shifting in x y coordinates. I forgot why there is 0.5 shifting in x y coordinates since some code in Im2mesh were written by me many years ago. Probably I want to be consistent with MATLAB built-in function bwboundaries.
Let's plot.
for i = 1: length(psCell)
plot( xy(1), xy(2), 'bo', 'MarkerFaceColor', 'b');
text( xy(1), xy(2), sprintf('(%.2f, %.2f)', xy(1), xy(2)), ...
'VerticalAlignment', 'bottom', 'HorizontalAlignment', 'center' );
plot( xy(1), xy(2), 'bo', 'MarkerFaceColor', 'b');
text( xy(1), xy(2), sprintf('(%.2f, %.2f)', xy(1), xy(2)), ...
'VerticalAlignment', 'bottom', 'HorizontalAlignment', 'center' );
Therefore, based on 4 corners, we can get the mid point of the upper boundary. We will use it later.
% mid point of the upper boundary
Add a block
Create a block
Let's create a block near the left side of psCell.
vertex = [ -30, 0.5; 0.5, 0.5; 0.5, 88.5; -30, 88.5 ];
psBlock = polyshape(vertex);
for i = 1: length(psCell)
Append to the end of psCell
% append to the end of psCell
for i = 1: length(psCell)
Merge geometry
We have assumed the block is a new phase in the geometry.
What if the block and the background are in the same phase? We can merge the block into the background.
First, we plot them one by one so we would know which is which.
for i = 1: length(psCell)
plot( psCell{i} ); axis equal;
title(['psCell\{' num2str(i), '\}']);
We saw that psCell{1} is the background. psCell{3} is the block.
We merge the block into the background.
psCell{1} = union( psCell{1}, psCell{3} );
psCell{3} = []; % delete the block
The length of psCell is 3 although the 3-th element is [].
To avoid error in the following steps, we need to manually delete empty elements in the cell array.
% delete empty elements in cell array
psCell = psCell( ~cellfun('isempty', psCell) );
Plot
for i = 1: length(psCell)
Create interfacial transition zone
We can assume the circles are particles in the composite materials.
We can use Matlab built-in function polybuffer to create interfacial transition zone (ITZ) around particles. ITZ may be useful in the FEA of composite materials.
thickness = 1.5; % unit: pixel
psITZ = polybuffer( psParticle, thickness, 'JointType', 'miter','MiterLimit', 20 );
psITZ = subtract( psITZ, psParticle );
Boolean operation
We use boolean operations to remove overlapped regions between psITZ and psCell.
for i = 1: length(psCell)
psCell{i} = subtract( psCell{i}, psITZ );
% add to the end of psCell
for i = 1: length(psCell)
Add a notch
Let's add a oval-shape notch to the point [xMidUp, yMidUp].
Define a oval. The center of the oval is [xMidUp, yMidUp].
psNotch = polyshape(x1,y1);
plot( psNotch ); axis equal
Add a oval-shape notch (by boolean operation - subtract).
for i = 1: length(psCell)
psCell{i} = subtract( psCell{i}, psNotch );
for i = 1: length(psCell)
Before mesh generation
Add intersect points
We use function polyshape2bound to convert the cell array of polyshape to a cell array of polygonal boundaries, and then use function addIntersectPnts to add intersect points to boundaries.
Note that if we don't add intersect points, mesh generation may fail.
boundsNew = polyshape2bound(psCell);
tol_intersect = 1e-6; % distance tolerance for intersect
boundsNew = addIntersectPnts( boundsNew, tol_intersect );
plotBounds( boundsNew, false, 'ko-' );
Zoom in
plotBounds( boundsNew, false, 'ko-' )
We notice there are a lot of vertices on the notch.
Simplify boundaries
We want to reduce the number of vertices on the notch and on the boundary.
boundsNewCtrlP = getCtrlPnts( boundsNew );
% simplify polyline using Douglas-Peucker algorithm
boundsNewReduced = simplifyBounds( boundsNewCtrlP, tolerance );
plotBounds( boundsNewReduced, false, 'ko-' );
Zoom in
plotBounds( boundsNewReduced, false, 'ko-' );
Wonderful! We saw that the number of vertices on the notch reduced a lot.
Note that you need to adjust the value of tolerance to achieve your desired reduction.
Generate mesh
We use function bounds2mesh to generate mesh.
[vert,tria,tnum] = bounds2mesh( boundsNewReduced, hmax, grad_limit );
Refine triangulation...
-------------------------------------------------------
|ITER.| |CDT1(X)| |CDT2(X)|
-------------------------------------------------------
5 313 504
10 340 712
17 345 1007
Refine triangulation...
-------------------------------------------------------
|ITER.| |CDT1(X)| |CDT2(X)|
-------------------------------------------------------
10 436 504
10 436 504
20 482 2898
25 482 2978
Smooth triangulation...
-------------------------------------------------------
|ITER.| |MOVE(X)| |DTRI(X)|
-------------------------------------------------------
10 70 2956
plotMeshes(vert,tria,tnum);
Zoom in
plotMeshes(vert,tria,tnum);
Wonderful!
We can also use open-source software Gmsh to generate mesh.
We saw that the mesh density in some region is low. It's possible to refine mesh locally. Please refer to demo17 and demo16.
set(groot, 'DefaultFigurePosition', 'factory')