What you want is the 2D alpha shape to try to get close to the outline you seek. Of course, it's no longer a Delaunay triangulation since you're deleting certain polygons from the DelaunayMesh
. We'll adopt my answer from this post. Here it is for a 2D point set:
alphaShapes2D[points_, crit_] :=
Module[{alphacriteria, del = Quiet @ DelaunayMesh @ points, tetras,
tetcoords, tetradii, selectExternalFaces},
alphacriteria[tetrahedra_, radii_, rmax_] :=
Pick[tetrahedra, UnitStep @ Subtract[rmax, radii], 1];
selectExternalFaces[facets_] := MeshRegion[points, facets];
If[Head[del] === EmptyRegion, del, tetras = MeshCells[del, 2];
tetcoords = MeshPrimitives[del, 2][[All, 1]];
tetradii = Quiet @ Thread[Circumsphere[tetcoords]][[All, 2]];
selectExternalFaces @ alphacriteria[tetras, tetradii, crit]]]
Let's see how well it performs:
reg = alphaShapes2D[data2D, 1.1];
MeshRegion[reg, MeshCellStyle -> {{0, All} -> Red}]
Looks better but doesn't get rid of some stubborn triangles. Maybe there are better ways to do this but I don't know about them.
Update
I am just updating the code to boost it's performance. (The code is already fast but it never hurts to squeeze out some more speed). The idea is to replace the built-in CircumSphere
with a Listable
and Compiled
version, we'll call it circumRadius2D
. Here is the code:
circumRadius2D = Compile[{{v, _Real, 2}},
With[{a = Norm[v[[1]] - v[[2]]], b = Norm[v[[1]] - v[[3]]], c = Norm[v[[2]] - v[[3]]]},
(a b c) / Sqrt[(a + b + c) (b + c - a) (c + a - b) (a + b - c)]
], RuntimeOptions -> "Speed", RuntimeAttributes -> {Listable}, Parallelization -> True
]
And here is the updated concave hull (alpha shapes) code:
alphaShapes2DC[points_, crit_] :=
Module[{alphacriteria, del = Quiet @ DelaunayMesh @ points, tris,
tricoords, triradii, getExternalFaces},
alphacriteria[triangle_, radius_, rmax_] :=
Pick[triangle, UnitStep @ Subtract[rmax, radius], 1];
getExternalFaces[facets_] := MeshRegion[points, facets];
If[Head[del] === EmptyRegion, del, tris = MeshCells[del, 2];
tricoords = MeshPrimitives[del, 2][[All, 1]];
triradii = circumRadius2D @ tricoords;
getExternalFaces @ alphacriteria[tris, triradii, crit]]]
This updated code is more than 3 times faster than the old version. Note that I have not compiled to C
. Let's put it to test with Jason's data:
reg = alphaShapes2DC[pnts, .33];
MeshRegion[reg, MeshCellStyle -> {{0, All} -> Red}]