Stochastic tiling script
A bit over a year ago, I wrote a post about the mathematics of tiling. In this post, I explore some of those ideas further with an octave script I wrote to draw regular and semi-regular tilings.
The script
%% stochastictiling.m - this is a script to draw regular and semi-regular tilings.
%
% A unit circle based on the vertex arrangement is drawn at a vertex of the tiling, then a new vertex is randomly selected and the reflected unit circle is drawn in the new location. This procedure is repeated out to a specified radius and then restarted from the origin along a new random path to ensure good coverage.
%Input vertex arrangement (e.g. [4 4 4 4] for square tiling) and maximum radius
VArrange = input("Specify vertex arrangement: \n");
RadMax = input("Radius to tile: \n");
%check the vertex arrangement (needs to sum to 360 degrees)
AngleCk = (180 - (360./VArrange));
if sum(AngleCk) != 360
error("Angles do not add up to 360 degrees");
end
%Create unit circle, using Rotation matrix = [ cos theta -sin theta; sin theta cos theta]
tav = length(VArrange); %tav = # tiles around vertex
unitcirc = zeros(2,tav);
unitcirc(:,1) = [1; 0]; %[x; y]
for item = 2:tav
theta = (pi - (2*pi/VArrange(item-1)));
R = [cos(theta) -1*sin(theta); sin(theta) cos(theta)];
unitcirc(:,item) = R * unitcirc(:,(item-1));
end
%disp(unitcirc); %included for testing--comment out later
origunitcircle = unitcirc;
%Set up the axes
fid = figure();
XXYY = RadMax + 1; %axis size
axis([-XXYY XXYY -XXYY XXYY]);
%Draw the tiles stochastically
indexmax = (tav^RadMax)*2;
for index1=1:indexmax
CurrPt = [0; 0]; %start at the origin
CurrRad = 0; %radius will increase as tiles are laid
unitcirc = origunitcircle; %reset the unit circle
while CurrRad <= RadMax
NewPts = zeros(2,tav);
NewPtCounter = 1;
for index2 = 1:tav
%calculate the new coordinates at the end of each vector in the unit circle
NewPts(:,NewPtCounter) = CurrPt + unitcirc(:,index2);
%draw the vectors in the unit circle radiating from the current point
line([CurrPt(1,1) NewPts(1,NewPtCounter)], [CurrPt(2,1) NewPts(2,NewPtCounter)]);
NewPtCounter = NewPtCounter + 1;
end
%Replace current vertex with randomly-selected new one
Stochastic = floor(rand(1)*tav)+1;
PrevPt = CurrPt;
CurrPt = NewPts(:,Stochastic);
%Increase the current radius
CurrRad = CurrRad + 1;
%reflect the unit circle about a line orthogonal to the vector between prev and new vertex
refline = [0 -1; 1 0]*(CurrPt - PrevPt); %reflection line is CurrPt - PrevPt, rotated 90 degrees
rlx = refline(1,1);
rly = refline(2,1);
Rf = [(rlx^2 - rly^2) (2*rlx*rly); (2*rlx*rly) (rly^2 - rlx^2)]; %Reflection matrix
unitcirc = Rf * unitcirc;
end
end
%Save the figure
print(fid,'tiles.png','-dpng');
Explanation
The script starts by asking for a vertex configuration number (explained here), given as a 1-row matrix (e.g. [4 8 8]
for the first image below). The maximum radius to tile is also requested. After checking that the interior angles add up to 360°, a unit circle is created, consisting of vectors along each edge of the tiling pattern out to a distance of 1 from the origin. That unit circle is then drawn at a vertex that is in the tiling pattern, starting at the origin; the ends of the vectors are new vertices. After it is drawn, a new vertex is selected, and the unit circle is reflected and redrawn. This procedure is repeated out to the maximum radius selected, then repeated from the origin multiple times so that the random paths will eventually tile the entire space.
The script makes use of transformation matrices to rotate vectors and to reflect the unit circle:
Rotation:
R = [cos(theta) -1*sin(theta); sin(theta) cos(theta)];
, where theta is the angle to rotate
Reflection:
Rf = [(rlx^2 - rly^2) (2*rlx*rly); (2*rlx*rly) (rly^2 - rlx^2)]
, where rlx and rly are the x and y components, respectively, of the reflection line
Results
Here are three patterns I drew using this script:
I used a image editing program to add the numbers in the vertex configuration around the origin; the vectors between the printed numbers comprise the unit circle used in the script.
Discussion
The script runs very slowly (because it goes through over 1000 iterations for a pattern with 5 tiles around each vertex and a radius of 4). It could probably be improved with further work (e.g. a more methodical approach to avoid traversing the same path multiple times like it does in this stochastic approach).
One of the tilings I tried, 3.3.3.4.4
, did not draw the proper pattern. My assumption is that reflecting the unit circle between vertices is not the correct approach in that case—maybe a certain rotation would work instead, but I don't know for sure. This particular tiling has a different symmetry than the other ones I tried, so that is probably related to it not working from the same script.