Hi @tamsamantha06,

I attempted practically exactly the same thing about a year ago in Python.

My goal was then to animate Vera Molnár’s artwork.

Here’s my script, if you’re interested:

```
import Rhino.Geometry as rg
from ghpythonlib import treehelpers
import random
import math
def construct_square_grid(plane, size, extendx, extendy, padding=0):
"""Creates a two-dimensional grid of square cells.
Args:
plane (Rhino.Geometry.Plane): Base plane for the grid
size (int|float): Size of the grid cells
extendx (int): Number of grid cells in the base plane x-direction
extendy (int): Number of grid cells in the base plane y-direction
padding (int|float): Optional padding between the grid cells,
by default 0, which means no padding
Returns:
A list of grid cells as polylines.
"""
xform = rg.Transform.PlaneToPlane(rg.Plane.WorldXY, plane)
grid = []
for y in range(extendy):
for x in range(extendx):
pt1 = rg.Point3d(
x * size + padding * x,
y * size + padding * y,
0
)
pt2 = rg.Point3d(
(x + 1) * size + padding * x,
(y + 1) * size + padding * y,
0
)
rectangle = rg.Rectangle3d(rg.Plane.WorldXY, pt1, pt2)
rectangle.Transform(xform)
grid.append(rectangle.ToPolyline())
return grid
def random_vector2d(plane=rg.Plane.WorldXY, scale=1.0):
"""Returns a random, two-dimensional vector that can optionally
be scaled to a desired magnitude. If no scale is provided
a unit vector of magnitude 1.0 is returned."""
theta = random.uniform(0, 2 * math.pi)
x = math.cos(theta)
y = math.sin(theta)
vec = rg.Vector3d(x, y, 0)
vec.Unitize()
if scale != 1.0:
vec *= scale
xform = rg.Transform.PlaneToPlane(rg.Plane.WorldXY, plane)
vec.Transform(xform)
return vec
def distort(polyline_crv, dmin=0, dmax=1):
"""Randomly distorts a polyline curve.
Args:
plane:
polyline_crv (Rhino.Geometry.PolylineCurve): Polyline Curve to distort
dmin (int|float): Optional minimum distortion radius, by default 0.0
dmax (int|float): Optional maximum distortion radius, by default 1.0
Returns:
The distorted polyline curve on success, otherwise the initial curve.
"""
if not isinstance(polyline_crv, rg.PolylineCurve):
return polyline_crv
rc, plane = polyline_crv.TryGetPlane()
if not rc:
return polyline_crv
pline = polyline_crv.ToPolyline()
if pline is None:
return polyline_crv
for i in range(pline.Count-1):
rscale = random.uniform(dmin, dmax)
pline[i] += random_vector2d(plane, rscale)
if polyline_crv.IsClosed:
pline[pline.Count-1] = pline[0]
return pline.ToPolylineCurve()
# ------------------------------------------------------------------------------
if __name__ == "__main__":
if Seed is not None:
random.seed(Seed)
grid = construct_square_grid(Plane, Size, ExtendX, ExtendY, Padding)
transformations = []
for cell in grid:
prev_crv = cell.ToPolylineCurve()
sub_cells = [prev_crv]
for i in range(Count-1):
offset_crv = prev_crv.Offset(Plane, -Padding, 0.01, 0)
if offset_crv is not None:
offset_crv = offset_crv[0]
if not isinstance(offset_crv, rg.PolylineCurve):
break
if not offset_crv.IsClosed or offset_crv.PointCount != 5:
break
prev_crv = offset_crv
if i == Index:
offset_crv = distort(offset_crv, Padding, Padding * 2)
sub_cells.append(offset_crv)
transformations.append(sub_cells)
# Outputs
Curves = treehelpers.list_to_tree(transformations)
```

transformations_2019.gh (11.2 KB)