DistMesh examples: interactive numbl companion
All ten examples from the DistMesh README as runnable numbl scripts
(mip load --install distmesh), plus deploy workflow for GitHub Pages.
14 changed files+259−0
.github/workflows/deploy.ymladded+43−0View file
@@ -0,0 +1,43 @@
1+name: Deploy numbl project to GitHub Pages
2+
3+# Bundles this numbl project with the browser IDE and publishes it to GitHub
4+# Pages on every push to main.
5+#
6+# One-time setup: Settings → Pages → "Build and deployment" → Source →
7+# "GitHub Actions".
8+
9+on:
10+ push:
11+ branches: [main]
12+ workflow_dispatch:
13+
14+permissions:
15+ contents: read
16+ pages: write
17+ id-token: write
18+
19+concurrency:
20+ group: pages
21+ cancel-in-progress: false
22+
23+jobs:
24+ build:
25+ runs-on: ubuntu-latest
26+ steps:
27+ - uses: actions/checkout@v4
28+ - uses: flatironinstitute/numbl/.github/actions/build-site@main
29+ with:
30+ project-dir: .
31+ # Build numbl from the main branch (development version) rather than
32+ # the published npm release
33+ numbl-ref: main
34+
35+ deploy:
36+ needs: build
37+ runs-on: ubuntu-latest
38+ environment:
39+ name: github-pages
40+ url: ${{ steps.deployment.outputs.page_url }}
41+ steps:
42+ - id: deployment
43+ uses: actions/deploy-pages@v4
.gitignoreadded+4−0View file
@@ -0,0 +1,4 @@
1+# Local output from `numbl build-site`
2+/_site/
3+/dist/
4+node_modules/
README.mdadded+58−0View file
@@ -0,0 +1,58 @@
1+# DistMesh examples
2+
3+An interactive companion to
4+[DistMesh](https://github.com/popersson/DistMesh) — Per-Olof Persson and
5+Gilbert Strang's simple mesh generator in MATLAB. Every example from the
6+DistMesh README, runnable in your browser through [numbl](https://numbl.org):
7+pick a script on the left and click **Run**.
8+
9+DistMesh describes a domain by a *signed distance function* (negative inside,
10+positive outside) and grows a well-shaped triangular mesh by Delaunay
11+retriangulation plus force-based smoothing of the node positions.
12+
13+Each script begins with
14+
15+```matlab
16+mip load --install distmesh
17+```
18+
19+which fetches DistMesh on first use.
20+
21+## 2-D meshes (`distmesh2d`)
22+
23+- [`ex01_unit_circle.m`](ex01_unit_circle.m) — uniform mesh on the unit circle.
24+- [`ex02_rectangle_hole.m`](ex02_rectangle_hole.m) — rectangle with a circular
25+ hole, refined at the hole.
26+- [`ex03_polygon.m`](ex03_polygon.m) — a polygon from its vertices.
27+- [`ex04_ellipse.m`](ex04_ellipse.m) — uniform mesh on an ellipse.
28+- [`ex05_square_nonuniform.m`](ex05_square_nonuniform.m) — square with point and
29+ line size sources.
30+- [`ex06_naca_airfoil.m`](ex06_naca_airfoil.m) — NACA0012 airfoil in a circular
31+ far field.
32+
33+## Surface meshes (`distmeshsurface`)
34+
35+- [`ex07_sphere.m`](ex07_sphere.m) — uniform mesh on the unit sphere.
36+- [`ex08_sphere_graded.m`](ex08_sphere_graded.m) — graded mesh on the sphere.
37+- [`ex09_torus.m`](ex09_torus.m) — uniform mesh on a torus.
38+- [`ex10_ellipsoid.m`](ex10_ellipsoid.m) — uniform mesh on an ellipsoid.
39+
40+## Notes
41+
42+All examples animate as the mesh relaxes; drag to rotate the surface meshes.
43+`ex06_naca_airfoil.m` is by far the heaviest and can take up to a minute or so
44+in the browser. The geometries
45+use the helper distance functions `dcircle`, `drectangle`, `dpoly`, `dsphere`,
46+`ddiff`, ... that ship with DistMesh.
47+
48+## Reference
49+
50+P.-O. Persson, G. Strang, *A Simple Mesh Generator in MATLAB*, SIAM Review
51+46(2), 329–345, 2004.
52+
53+## How it's deployed
54+
55+On every push to `main`, the workflow in
56+[`.github/workflows/deploy.yml`](.github/workflows/deploy.yml) bundles these
57+files with the numbl browser IDE and publishes the result to GitHub Pages. Edit
58+`numbl-project.json` to change the title or which file opens first.
ex01_unit_circle.madded+14−0View file
@@ -0,0 +1,14 @@
1+% ex01_unit_circle.m — Uniform mesh on the unit circle.
2+%
3+% The geometry is given by a signed distance function fd(p): negative
4+% inside the domain, positive outside, zero on the boundary. Here
5+% d = r - 1, so the domain is the disk of radius 1. @huniform asks for a
6+% uniform element size.
7+
8+mip load --install distmesh
9+
10+fd=@(p) sqrt(sum(p.^2,2))-1;
11+[p,t]=distmesh2d(fd,@huniform,0.2,[-1,-1;1,1],[]);
12+
13+title('Unit circle');
14+fprintf('mesh: %d nodes, %d triangles\n', size(p,1), size(t,1));
ex02_rectangle_hole.madded+15−0View file
@@ -0,0 +1,15 @@
1+% ex02_rectangle_hole.m — Rectangle with a circular hole.
2+%
3+% ddiff subtracts the circle from the rectangle to form the domain. The
4+% size function fh grows with distance from the circle, so elements are
5+% small at the hole and coarsen outward. The last argument fixes the four
6+% corners so they stay put.
7+
8+mip load --install distmesh
9+
10+fd=@(p) ddiff(drectangle(p,-1,1,-1,1),dcircle(p,0,0,0.5));
11+fh=@(p) 0.05+0.3*dcircle(p,0,0,0.5);
12+[p,t]=distmesh2d(fd,fh,0.05,[-1,-1;1,1],[-1,-1;-1,1;1,-1;1,1]);
13+
14+title('Rectangle with circular hole');
15+fprintf('mesh: %d nodes, %d triangles\n', size(p,1), size(t,1));
ex03_polygon.madded+15−0View file
@@ -0,0 +1,15 @@
1+% ex03_polygon.m — A polygon given by its vertices.
2+%
3+% dpoly is the signed distance to a polygon defined by the vertex list pv
4+% (first vertex repeated at the end to close it). pv is passed both as the
5+% distance-function parameter and as the set of fixed points, so the mesh
6+% boundary follows the polygon edges exactly.
7+
8+mip load --install distmesh
9+
10+pv=[-0.4 -0.5;0.4 -0.2;0.4 -0.7;1.5 -0.4;0.9 0.1;
11+ 1.6 0.8;0.5 0.5;0.2 1;0.1 0.4;-0.7 0.7;-0.4 -0.5];
12+[p,t]=distmesh2d(@dpoly,@huniform,0.1,[-1,-1; 2,1],pv,pv);
13+
14+title('Polygon');
15+fprintf('mesh: %d nodes, %d triangles\n', size(p,1), size(t,1));
ex04_ellipse.madded+13−0View file
@@ -0,0 +1,13 @@
1+% ex04_ellipse.m — Uniform mesh on an ellipse.
2+%
3+% The distance function here is only approximate (x^2/4 + y^2 - 1), but
4+% DistMesh still converges to a good mesh: boundary points are projected
5+% back onto the level set d = 0 at every step.
6+
7+mip load --install distmesh
8+
9+fd=@(p) p(:,1).^2/2^2+p(:,2).^2/1^2-1;
10+[p,t]=distmesh2d(fd,@huniform,0.2,[-2,-1;2,1],[]);
11+
12+title('Ellipse');
13+fprintf('mesh: %d nodes, %d triangles\n', size(p,1), size(t,1));
ex05_square_nonuniform.madded+15−0View file
@@ -0,0 +1,15 @@
1+% ex05_square_nonuniform.m — Unit square with point and line size sources.
2+%
3+% The size function fh refines toward a point (the origin) and a line
4+% segment, capped at 0.15. This shows how to drive local resolution with
5+% a hand-written size function.
6+
7+mip load --install distmesh
8+
9+fd=@(p) drectangle(p,0,1,0,1);
10+fh=@(p) min(min(0.01+0.3*abs(dcircle(p,0,0,0)), ...
11+ 0.025+0.3*abs(dpoly(p,[0.3,0.7; 0.7,0.5]))),0.15);
12+[p,t]=distmesh2d(fd,fh,0.01,[0,0;1,1],[0,0;1,0;0,1;1,1]);
13+
14+title('Square with point and line size sources');
15+fprintf('mesh: %d nodes, %d triangles\n', size(p,1), size(t,1));
ex06_naca_airfoil.madded+25−0View file
@@ -0,0 +1,25 @@
1+% ex06_naca_airfoil.m — NACA0012 airfoil in a circular far field.
2+%
3+% The domain is a large circle with the airfoil removed (ddiff). The size
4+% function refines toward the leading and trailing edges; fixed points
5+% pin the airfoil tip and a few far-field points. This is the heaviest
6+% example — give it a few seconds.
7+
8+mip load --install distmesh
9+
10+hlead=0.01; htrail=0.04; hmax=2; circx=2; circr=4;
11+a=.12/.2*[0.2969,-0.1260,-0.3516,0.2843,-0.1036];
12+
13+fd=@(p) ddiff(dcircle(p,circx,0,circr),(abs(p(:,2))-polyval([a(5:-1:2),0],p(:,1))).^2-a(1)^2*p(:,1));
14+fh=@(p) min(min(hlead+0.3*dcircle(p,0,0,0),htrail+0.3*dcircle(p,1,0,0)),hmax);
15+
16+fixx=1-htrail*cumsum(1.3.^(0:4)');
17+fixy=a(1)*sqrt(fixx)+polyval([a(5:-1:2),0],fixx);
18+fix=[[circx+[-1,1,0,0]*circr; 0,0,circr*[-1,1]]'; 0,0; 1,0; fixx,fixy; fixx,-fixy];
19+box=[circx-circr,-circr; circx+circr,circr];
20+h0=min([hlead,htrail,hmax]);
21+
22+[p,t]=distmesh2d(fd,fh,h0,box,fix);
23+
24+title('NACA0012 airfoil');
25+fprintf('mesh: %d nodes, %d triangles\n', size(p,1), size(t,1));
ex07_sphere.madded+13−0View file
@@ -0,0 +1,13 @@
1+% ex07_sphere.m — Uniform mesh on the unit sphere.
2+%
3+% distmeshsurface meshes the zero level set of a 3-D distance function.
4+% dsphere(p,xc,yc,zc,r) is the signed distance to a sphere; here the unit
5+% sphere centered at the origin. Drag to rotate the result.
6+
7+mip load --install distmesh
8+
9+fd=@(p) dsphere(p,0,0,0,1);
10+[p,t]=distmeshsurface(fd,@huniform,0.2,1.1*[-1,-1,-1;1,1,1]);
11+
12+title('Unit sphere');
13+fprintf('mesh: %d nodes, %d triangles\n', size(p,1), size(t,1));
ex08_sphere_graded.madded+14−0View file
@@ -0,0 +1,14 @@
1+% ex08_sphere_graded.m — Graded mesh on the unit sphere.
2+%
3+% Same sphere as ex07, but the size function grows with distance from the
4+% north pole (0,0,1), so triangles are small near the pole and large near
5+% the south pole.
6+
7+mip load --install distmesh
8+
9+fd=@(p) dsphere(p,0,0,0,1);
10+fh=@(p) 0.05+0.5*dsphere(p,0,0,1,0);
11+[p,t]=distmeshsurface(fd,fh,0.15,1.1*[-1,-1,-1;1,1,1]);
12+
13+title('Graded sphere');
14+fprintf('mesh: %d nodes, %d triangles\n', size(p,1), size(t,1));
ex09_torus.madded+13−0View file
@@ -0,0 +1,13 @@
1+% ex09_torus.m — Uniform mesh on a torus.
2+%
3+% The torus is the zero level set of the quartic distance-like function
4+% below (major radius 0.8, minor radius 0.2). The bounding box is flat in
5+% z because the torus is thin in that direction.
6+
7+mip load --install distmesh
8+
9+fd=@(p) (sum(p.^2,2)+.8^2-.2^2).^2-4*.8^2*(p(:,1).^2+p(:,2).^2);
10+[p,t]=distmeshsurface(fd,@huniform,0.1,[-1.1,-1.1,-.25;1.1,1.1,.25]);
11+
12+title('Torus');
13+fprintf('mesh: %d nodes, %d triangles\n', size(p,1), size(t,1));
ex10_ellipsoid.madded+13−0View file
@@ -0,0 +1,13 @@
1+% ex10_ellipsoid.m — Uniform mesh on an ellipsoid.
2+%
3+% An approximate distance function for the ellipsoid with semi-axes
4+% 2, 1, 1.5. As in the 2-D ellipse, the projection step keeps boundary
5+% nodes on the true surface despite the approximation.
6+
7+mip load --install distmesh
8+
9+fd=@(p) p(:,1).^2/4+p(:,2).^2/1+p(:,3).^2/1.5^2-1;
10+[p,t]=distmeshsurface(fd,@huniform,0.2,[-2.1,-1.1,-1.6; 2.1,1.1,1.6]);
11+
12+title('Ellipsoid');
13+fprintf('mesh: %d nodes, %d triangles\n', size(p,1), size(t,1));
numbl-project.jsonadded+4−0View file
@@ -0,0 +1,4 @@
1+{
2+ "title": "DistMesh examples",
3+ "entry": "README.md"
4+}