# Stretching a mesh

Imagine I want to stretch a mesh with a 'rubberband-type' effect. That is, upon and elastic stretch from both side edges, the mesh centres simply scale as follows

where the points are seeds for updating Voronoi tessellations.

This was done by manually scaling the points, but I would like to get this effect by using an actual vertex model and having a mechanical force stretch the tissue. That is, instead of Voronoi seeds, such force would act on the cell vertices and I would get no cell intercalation (changing neighbours, or changing edges). Any idea or references on how to do this?

• Out of curiosity, how did you manually distribute the points? Mar 22 at 15:44
• (1) Once you have a mesh, you can stretch the mesh coordinates. (2) Is the stretching to preserve the volume/area of the cells? (Is there a physical model, or are you after a geometric effect that need not be physically accurate?) Mar 22 at 17:13
• @user21 initially, Lloyd's relaxation. the stretch was done by a parametrized rescaling Mar 22 at 23:37
• @MichaelE2 there are plenty, mostly energy-based. Look at Farhadifar's vertex model, for example. But I'm looking for something simpler to avoid any kind of cell intercalations (or T1 transitions). So simply readjusting the vertex positions with some force transmission that preserves cell shape to some degree. Mar 22 at 23:39
• One alternative to vertex models could be to consider a spring-based model, where each pair of vertices is connected by a spring with an associated stiffness, but I'm not too sure how to implement that, and whether stretch forces are easily transmissible on that system. Any suggestions are appreciated Mar 22 at 23:47

rescaley[t_] := 1 - t Rescale[#, {-t, t}, {0, 1}] (1 - Rescale[#, {-t, t}, {0, 1}]) &

stretch[t_] := ReplaceAll[{x_Real, y_Real} :>
{t x, Rescale[y, {-1, 1}, {rescaley[t][t x], -rescaley[t][t x]}]}]

SeedRandom[1]
cba = Join @@ CoordinateBoundsArray[{{-1, 1}, {-1, 1}}, Into[15], Center] +
RandomReal[{-.03, .03}, {15^2, 2}];

show[t_] := Show[VoronoiMesh[stretch[t]@cba, {{-3, 3}, {-1, 1}}],
Graphics[{PointSize[Small], Black, Point[stretch[t]@cba]}],
ImageSize -> Large];

Animate[show[t], {t, 1, 3}]


The gif animation above obtained using:

Export["stretchVoronoi.gif", Table[show[t], {t, 1, 3, .05}]]


Update: Using stretch on polygon vertices:

polygons = MeshPrimitives[VoronoiMesh[cba, {{-1, 1}, {-1, 1}}], 2];

show2[t_] := Graphics[{EdgeForm[Gray], LightBlue, stretch[t] /@ polygons,
PointSize[Small], Black, Point[stretch[t]@cba]},
ImageSize -> Large, PlotRange -> {{-3, 3}, {-3/2, 3/2}}];

Animate[show2[t], {t, 1, 3}]


Alternatively, per Michael E2.'s suggestion in comments, create new MeshRegion using stretch on cba and the mesh cells from VoronoiMesh[cba]:

{mc, cells} = Through[{MeshCoordinates, MeshCells[#, 2] &}@
VoronoiMesh[cba, {{-3, 3}, {-1, 1}}]];

show3[t_] := Show[MeshRegion[stretch[t] @ mc, cells],
Graphics[{PointSize[Small], Black, Point[stretch[t]@cba]}],
PlotRange -> {{-3, 3}, {-1, 1}}, ImageSize -> Large];

Animate[show3[t], {t, 1, 3}]


• Great answer! Is it possible to define the stretch function in such a way that, instead of acting on the Voronoi seeds (cell "centres"), it acts on the cell vertices instead? I guess it is only a question of tracking the corresponding edges, but I was just wondering if there is a straightforward way to do it with your code. That way I guarantee no cell intercalation (cells changing neighbours) happens and completely avoid using VoronoiMesh Mar 23 at 13:02
• something like the example in the update?
– kglr
Mar 23 at 13:39
• Yes! That is exactly what I was looking for. Now I just which I could justify that deformation with some physical argument and an ode on the vertex positions. I know about potential-based vertex models and Hookean laws could help. Any suggestion is appreciated, but I understand this might be way beyond the scope of the question. Thank you nonetheless! Mar 23 at 14:32
• Also, where is polygons defined? Mar 23 at 14:35
• @samwolfe, fixed the cut/paste error re polygons.
– kglr
Mar 23 at 14:46

Something like:

nx = 5; ny = 3;
Manipulate[
pts = Flatten[
Table[{x d, 2 y} + 0.5 RandomReal[{-1, 1}, 2], {x, -nx,
nx}, {y, -ny, ny}], 1];
Show[VoronoiMesh[pts], Graphics[Point[pts]],
PlotRange -> {5  nx {-1, 1}, 3 ny {-1, 1}}, ImageSize -> {500, 200},
Axes -> True]
, {{d, 2}, 1, 3}]