demo16 of Im2mesh package
demo16 - Add mesh seeds/nodes
Note
I suggest familiarizing yourself with Im2mesh_GUI before learning Im2mesh package. With graphical user interface, Im2mesh_GUI will help you better understand the workflow and parameters of Im2mesh package.
If you are using Im2mesh package in MATLAB, you need to install MATLAB Image Processing Toolbox and Mapping Toolbox because Im2mesh package use a few functions in these toolboxes.
Setup
Before we start, please set folder "Im2mesh_Matlab" as your current folder of MATLAB.
Set default image size.
x = 250; y = 250; width = 250; height = 250;
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'))
Overview
Please take a look at demo14 before starting demo16.
In Im2mesh package, mesh seeds/nodes are defined as markers that you place along the edges of a region. We use mesh seeds to specify target mesh density in a region.
There are two different cases for adding mesh seeds. We will show them in this demo.
- Case 1. The coordniates of the seeds to be added is known.
- Case 2. The coordniates of the seeds to be added is unknown.
We have demostrated how to create polygonal boundary in previous demo. There are two approaches:
- demo01 - create polygonal boundary based on 2d image.
- demo14 - create polygonal boundary from polyshape objects.
In this demo, we'll use polyshape to create polygonal boundary, and then add mesh seeds/nodes to boundary. For boundaries created based on 2d image, the workflow of adding mesh seeds/nodes is the same.
Case 1. Coordniates of the seeds to be added is known
Define polyshape and create boundary
Define a cell array of polyshape objects
vert1 = [ 0 0; 15 0; 15 10; 0 10 ];
vert2 = [15 0] + [ 0 0; 10 0; 10 10; 0 10 ];
vert3 = [15 10] + [ 0 0; 10 0; 10 25; 0 25 ];
ps13 = union( ps1, ps3 );
for i = 1: length(psCell)
We saw 2 phases (or 2 parts) and 3 regions.
Create polygonal boundary from polyshape
% bounds is a nested cell array of polygonal boundary
bounds = polyshape2bound(psCell);
tol_intersect = 1e-6; % distance tolerance for intersect
bounds = addIntersectPnts( bounds, tol_intersect );
% plot boundaries and show all vertices
plotBounds(bounds,false,'ko-')
We can use function xyRange to get the range of x y coordinate in boundary.
[xmin, xmax, ymin, ymax] = xyRange( bounds )
xmin = 0
xmax = 25
ymin = 0
ymax = 35
Add a midpoint to the bottom edge
Suppose we want to add a midpoint to the bottom edge of 'bounds' .
Based on xmin, xmax, ymin, ymax, we know that the midpoint in the bottom edge of 'bounds' would be
We use function addPnt2Bound to add point (xMid,yMid) to boundary.
tol_dist = 1e-2; % distance tolerance
newB = addPnt2Bound( point, bounds, tol_dist );
plotBounds( newB, false, 'ko-' );
We saw that the midpoint of the bottom edge is added to the boundary.
When we generate finite element mesh, the mesh will have this point in the vertices.
Add a point near the bottom edge
The point to be added does not have to lie exactly on the pristine boundary. The point can have some distance away from the pristine boundary. Check the following example.
Here we set distance tolerance 'tol_dist' to 5. If the shortest distance between the point and the pristine boundary is less than 'tol_dist', the point will be added to the boundary. Otherwise, the point will not be added.
tol_dist = 5; % distance tolerance
newB = addPnt2Bound( point, newB, tol_dist );
plotBounds( newB, false, 'ko-' );
Generate mesh
opt.disp = inf; % silence verbosity
[vert,tria,tnum] = bounds2mesh( newB, hmax, grad_limit, opt );
Plot mesh.
plotMeshes(vert,tria,tnum);
Add multiple points
Suppose we want to add multiple points/seeds to the bottom edge of 'bounds' .
Based on xmin, xmax, ymin, ymax, we know that two end point in the bottom edge of 'bounds' would be
We can use function insertMidPnt to add seeds.
points = [ xyLeft; xyRight ];
points = insertMidPnt( points, iters );
plot( points(:,1), points(:,2), 'k.-' );
We use function addPnt2Bound to add points to boundary.
tol_dist = 1e-2; % distance tolerance
newB = addPnt2Bound( points, bounds, tol_dist );
plotBounds( newB, false, 'k.-' );
Generate mesh
opt.disp = inf; % silence verbosity
[vert,tria,tnum] = bounds2mesh( newB, hmax, grad_limit, opt );
Plot mesh.
plotMeshes(vert,tria,tnum);
Add biased seeds
We can use function insertBiasedSeed to add biased seeds (non-uniform distributed).
Note that the 1st input of function insertBiasedSeed should be a 2-by-2 array (two points), and the output result depends on the vertex ordering in the input edge.
points = [ xyLeft; xyRight ];
points = insertBiasedSeed( points, iters, ratio );
plot( points(:,1), points(:,2), 'ko-' );
We can set ratio to negative value to flip direction.
points = [ xyLeft; xyRight ];
points = insertBiasedSeed( points, iters, ratio );
plot( points(:,1), points(:,2), 'ko-' );
We use function addPnt2Bound to add points to boundary.
tol_dist = 1e-2; % distance tolerance
newB = addPnt2Bound( points, bounds, tol_dist );
plotBounds( newB, false, 'ko-' );
Generate mesh
opt.disp = inf; % silence verbosity
[vert,tria,tnum] = bounds2mesh( newB, hmax, grad_limit, opt );
Plot mesh.
plotMeshes(vert,tria,tnum);
Case 2. Coordniates of the seeds to be added is unknown
This case is often for complicated polygonal boundaries, such as boundary extracted from multi-phase image.
In this case, we will need to find the polygonal boundary that we want to add mesh seed. I'll demostrate how to do this.
We will use the same geometry for demostration.
% plot boundaries and show all vertices
plotBounds(bounds,false,'ko-')
Find edges we interested in
Suppose we are interested in the bottom edge and the right edge in the topmost rectangle. Let's find these edges in 'bounds'.
bounds is a nested cell array of polygonal boundaries.
We can plot polygons one by one.
for i = 1: length(bounds)
for j = 1: length(bounds{i})
plot( poly(:,1), poly(:,2) ); axis equal;
title(['bounds\{', num2str(i), '\}\{', num2str(j), '\}']);
The edge we interested in belongs to bounds{2}{2}.
bounds{2}{2}
15 10
25 10
25 35
15 35
15 10
These are x and y coordinates of vetices.
Let's plot it.
figure; hold on; axis equal
plot( poly(:,1), poly(:,2), 'ko-' );
text( poly(i,1), poly(i,2), num2str(i), ...
'HorizontalAlignment', 'left', ...
'VerticalAlignment', 'bottom', ...
'FontSize', 12, 'Color', 'red');
In the figure, the numberings of the 1st and the last vertex overlap.
Method 1. Add seed by inserting midpoint
We can use function insertMidPnt to add seeds.
The edge we interested in is between vertex 1 and vertex 3 in the polygon
Let's extract it.
polyline = poly( index, : );
plot( polyline(:,1), polyline(:,2), 'ko-' ); axis equal
Then, we can add seeds to the interested edges by repeatedly inserting midpoints to edges. We do this by function insertMidPnt.
polyline = insertMidPnt( polyline, iters );
plot( polyline(:,1), polyline(:,2), 'ko-' ); axis equal
Add points to bounday
Use function addPnt2Bound to add the points to the bounday.
tol_dist = 1e-2; % distance tolerance
newB = addPnt2Bound( polyline, bounds, tol_dist );
plotBounds( newB, false, 'ko-' );
Awesome! But we notice that the space between seeds in different edges are different. This is not good.
Method 2. Add uniform seeds
We can use function insertEleSizeSeed to add better uniform seeds.
The edge we interested in is between vertex 1 and vertex 3 in the polygon. Let's extract it.
polyline = poly( index, : );
plot( polyline(:,1), polyline(:,2), 'ko-' ); axis equal
Then, we can add uniform seeds to the interested edges by function insertEleSizeSeed. We can specify the space between seeds.
target_size = 1; % space between seeds
polyline = insertEleSizeSeed( polyline, target_size );
plot( polyline(:,1), polyline(:,2), 'ko-' ); axis equal
Very good! The space between seeds in different edges are the same now.
Add points to bounday
Use function addPnt2Bound to add the points to the bounday.
tol_dist = 1e-2; % distance tolerance
newB = addPnt2Bound( polyline, bounds, tol_dist );
plotBounds( newB, false, 'ko-' );
Generate mesh
opt.disp = inf; % silence verbosity
[vert,tria,tnum] = bounds2mesh( newB, hmax, grad_limit, opt );
Plot mesh.
plotMeshes(vert,tria,tnum);
Awesome!
Add seeds to all boundaries
We can also add uniform seeds to all boundaries, which may be useful in some cases.
target_size = 1; % space between seeds
for j = 1: length(newB{i})
newB{i}{j} = insertEleSizeSeed( newB{i}{j}, target_size );
newB{i}{j} = round( newB{i}{j}, n_digit );
plotBounds( newB, false, 'k.-' );
Generate mesh
opt.disp = inf; % silence verbosity
[vert,tria,tnum] = bounds2mesh( newB, hmax, grad_limit, opt );
Plot mesh.
plotMeshes(vert,tria,tnum);
Method 3. Add biased seeds
The above example is with uniform seeds. How about biased seeds (non-uniform distributed)?
We can use function insertBiasedSeed to do that.
Suppose we are interested in the edge between vertex 1 and vertex 2 in the polygon.
plot( edge(:,1), edge(:,2), 'ko-' ); axis equal
We can use function insertBiasedSeed to insert biased seeds into a single edge. Note that the 1st input of function insertBiasedSeed should be a 2-by-2 array (two points), and the output result depends on the vertex ordering in the input edge.
edge = insertBiasedSeed( edge, iters, ratio );
plot( edge(:,1), edge(:,2), 'ko-' ); axis equal
Let's use function insertMidPnt to make seeds denser.
edge = insertMidPnt( edge, iters );
plot( edge(:,1), edge(:,2), 'ko-' ); axis equal
Add points to bounday
Use function addPnt2Bound to add the points to the bounday.
tol_dist = 1e-2; % distance tolerance
newB = addPnt2Bound( edge, bounds, tol_dist );
plotBounds( newB, false, 'ko-' );
Generate mesh
opt.disp = inf; % silence verbosity
[vert,tria,tnum] = bounds2mesh( newB, hmax, grad_limit, opt );
Plot mesh.
plotMeshes(vert,tria,tnum);
Awesome!
set(groot, 'DefaultFigurePosition', 'factory')