{"id":146,"date":"2013-09-21T09:56:33","date_gmt":"2013-09-21T16:56:33","guid":{"rendered":"http:\/\/www.imaginary-institute.com\/blog\/?p=146"},"modified":"2013-09-21T11:10:07","modified_gmt":"2013-09-21T18:10:07","slug":"146","status":"publish","type":"post","link":"https:\/\/www.imaginary-institute.com\/blog\/2013\/09\/21\/146\/","title":{"rendered":"Spinning Hexes"},"content":{"rendered":"<p><a href=\"http:\/\/www.imaginary-institute.com\/blog\/wp-content\/uploads\/2013\/09\/rotatingHexTiles-300.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-147 alignleft\" alt=\"rotatingHexTiles-300\" src=\"http:\/\/www.imaginary-institute.com\/blog\/wp-content\/uploads\/2013\/09\/rotatingHexTiles-300.jpg\" width=\"300\" height=\"300\" srcset=\"https:\/\/www.imaginary-institute.com\/blog\/wp-content\/uploads\/2013\/09\/rotatingHexTiles-300.jpg 300w, https:\/\/www.imaginary-institute.com\/blog\/wp-content\/uploads\/2013\/09\/rotatingHexTiles-300-150x150.jpg 150w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a>I finished up a project the other day, so I gave myself a few minutes to make something just for fun. Here&#8217;s a grid of hexagonal tiles with little bits of graphics in them. Over time, random tiles rotate to create a new pattern (in this screenshot, you can see 5 tiles in mid-rotation). I played around with a whole bunch of different coloring schemes, and found that this combination of light and dark warm browns had just the right kind of feeling for me. Although it may look like the tiles are circular (a sensation that&#8217;s even stronger when you watch them rotate), they really are all hexagons. Read on for how I did this and the program itself.<\/p>\n<p><!--more--><\/p>\n<p>Each hexagonal tile <a href=\"http:\/\/www.imaginary-institute.com\/blog\/wp-content\/uploads\/2013\/09\/HexTiles.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-150 alignright\" alt=\"HexTiles\" src=\"http:\/\/www.imaginary-institute.com\/blog\/wp-content\/uploads\/2013\/09\/HexTiles.jpg\" width=\"300\" height=\"99\" \/><\/a>has six sides, and each side has one bit of a &#8220;band&#8221; on each edge. I decided for simplicity that I didn&#8217;t want the internal bands to overlap. So how many different tiles can you draw with that constraint? Factoring out rotation and reflection, there are 10 types of tiles. It&#8217;s fun to think about these and make sure you&#8217;ve got them all. I drew these out on a piece of paper and gave each one a number, so I could type their descriptions into my program and I&#8217;d know which tile I meant at what position.<\/p>\n<p><a href=\"http:\/\/www.imaginary-institute.com\/blog\/wp-content\/uploads\/2013\/09\/HexBeziers.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-151 alignleft\" alt=\"HexBeziers\" src=\"http:\/\/www.imaginary-institute.com\/blog\/wp-content\/uploads\/2013\/09\/HexBeziers.jpg\" width=\"300\" height=\"203\" \/><\/a>There are just four different types of shapes inside these tiles: the little end-cap, the straight line that joins opposite sides, and the two curves that join neighboring sides, or sides with one side between them. I draw all of these with a pair of Bezier curves (joined by straight lines along the edges). I wanted the curves to be graceful and interesting, so I played with the locations of the Bezier knots until they looked good to me. This is one of the pleasures of this kind of programming: once the math is in place, you can just fiddle with the numbers intuitively until the picture feels right.<\/p>\n<p>My program first populates the world with random tiles, though it tries to choose them so that we don&#8217;t get too many small closed loops. Then on every frame, I look at any tiles that have just finished rotating, and choose a neighbor to start rotating. The tiles spin at slightly different speeds, so they start and stop at different times. It&#8217;s fun to watch the evolving patterns.<\/p>\n<p>Here&#8217;s the code. I haven&#8217;t cleaned it up or tried to make it really nice &#8211; this was just a little fun project, after all, and I didn&#8217;t intend to share it. Think of this as a rough draft. There are two files: rotatingHexTiles.pde is the main project. Tile.pde holds the Tile class.<\/p>\n<p><strong>rotatingHexTiles.pde:<\/strong><\/p>\n<pre>\/\/ rotating hexagon tiles, version 1.0\r\n\/\/ (c) 2013 Andrew Glassner\r\nTile[] TileList;\r\n\/\/ These are the 10 different types of tiles. Codes:\r\n\/\/ -1 = nothing \"starts\" at this edge\r\n\/\/  0 = end cap (or half a dot)\r\n\/\/  1 = connects to next edge clockwise\r\n\/\/  2 = connects to edge that's two edges clockwise\r\n\/\/  3 = connects to edge opposite this one\r\nint[][] Styles = {\r\n\u00a0 { -1, 3, 1, -1, -1, 1 },\r\n\u00a0 {-1, 1, -1, 1, -1, 1 },\r\n\u00a0 { 0, 1, -1, 0, 1, -1 },\r\n\u00a0 {-1, 3, 0, 0, -1, 1 },\r\n\u00a0 { -1, 0, 1, -1, 2, 0 },\r\n\u00a0 { 0, 3, 0, 0, -1, 0 },\r\n\u00a0 { -1, 0, 0, 0, 0, 1 },\r\n\u00a0 {-1, 0, 0, 0, 2, 0 },\r\n\u00a0 { 0, 0, 0, 0, 0, 0 },\r\n\u00a0 { -1, 2, 0, -1, 2, 0 }\r\n};\r\nint NumX, NumY;\r\nint RotateDurationRangeStart = 20;\r\nint RotateDurationRangeEnd = 50;\r\n\r\nvoid setup() {\r\n\u00a0 size(800, 800);\r\n\u00a0 float r = 40;\r\n\u00a0 float h = r\/Cos30;\r\n\u00a0 float s2 = h*Sin30;\r\n\u00a0 float s = 2*s2;\r\n\u00a0 NumX = int(1+(2*ceil(width*1.0\/(h+s2))));\r\n\u00a0 NumY = int(1+(ceil(height*1.0\/(2*r))));\r\n\r\n\u00a0 TileList = new Tile[NumX*NumY];\r\n\u00a0 for (int y=0; y&lt;NumY; y++) {\r\n\u00a0\u00a0\u00a0 for (int x=0; x&lt;NumX; x++) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 float cx = x*(h+s2);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 float cy = y*(2*r);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 if (x%2 == 1) cy += r;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 int index = (y*NumX)+x;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 int whichStyle = int(random(0,2));\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 boolean hasDots = random(0,1) &gt; .5;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 if (hasDots) whichStyle = int(random(2,10));\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 TileList[index] = new Tile(cx, cy, r, int(random(0,6))*PI\/3, \r\n                                 color(240,233,205), Styles[whichStyle]);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 boolean doChange = random(0, 1) &gt; .95;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 if (doChange) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 int stopFrame = int(random(RotateDurationRangeStart, \r\n                                   RotateDurationRangeEnd));\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 TileList[index].startChange(0, stopFrame, random(0,1)&gt;.5, Styles[0]);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0 }\r\n\u00a0 }\r\n}\r\n\r\nvoid draw() {\r\n\u00a0 background(195,155,135);\r\n\u00a0 for (int i=0; i&lt;TileList.length; i++) {\r\n\u00a0\u00a0\u00a0 TileList[i].render();\r\n\u00a0\u00a0\u00a0 \/\/ if this tile just stopped rotating, start up a neighbor\r\n\u00a0\u00a0\u00a0 if (TileList[i].justStoppedChanging) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 int thisY = int(i*1.0\/NumY);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 int thisX = i-(thisY*NumX);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 int offset = int(random(0,4));\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 for (int j=0; j&lt;4; j++) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 int newIndex = -1;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 int whichCase = (j+offset)%4;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 switch (whichCase) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 case 0: \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (thisX &gt; 0) newIndex = (thisY*NumX)+(thisX-1);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 break;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 case 1: \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (thisX &lt; NumX-1) newIndex = (thisY*NumX)+(thisX+1);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 break;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 case 2: \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (thisY &gt; 0) newIndex = ((thisY-1)*NumX)+thisX;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 break;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 case 3: \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (thisY &lt; NumY-1) newIndex = ((thisY+1)*NumX)+thisX;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 break;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (newIndex &gt;= 0) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (!TileList[newIndex].changing) {\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 int stopFrame = frameCount+int(random(RotateDurationRangeStart, \r\n                                                  RotateDurationRangeEnd));\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 TileList[newIndex].startChange(frameCount, stopFrame, \r\n                                           random(0,1)&gt;.5, Styles[0]);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 break;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0 }\r\n\u00a0 }\r\n}<\/pre>\n<p><strong>Tile.pde:<\/strong><\/p>\n<pre>\/\/ A class for a hexagonal tile with an internal pattern, version 1.0\r\n\/\/ (c) 2013 Andrew Glassner\r\n\r\nfloat Sin30 = .5;\r\nfloat Cos30 = cos(radians(30));\r\nfloat Sin60 = Cos30;\r\nfloat Cos60 = .5;\r\n\r\nclass Tile {\r\n\u00a0 float cx, cy, r, s, s2, h;\r\n\u00a0 int[] ecode;\r\n\u00a0 float barWeight;\r\n\u00a0 color strokeColor;\r\n\u00a0 float spinAngle;\r\n\u00a0 float bezD;\r\n\u00a0 boolean changing, justStoppedChanging;\r\n\u00a0 int changeStartFrame, changeStopFrame;\r\n\u00a0 boolean changeClockwise;\r\n\u00a0 int[] changeEcode;\r\n\r\n\u00a0 Tile(float tx, float ty, float tr, float rotationAngle,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 color c, int[] edgeStyle) {\r\n\u00a0\u00a0\u00a0 cx = tx;\r\n\u00a0\u00a0\u00a0 cy = ty;\r\n\u00a0\u00a0\u00a0 r = tr;\r\n\u00a0\u00a0\u00a0 h = r\/Cos30;\r\n\u00a0\u00a0\u00a0 s2 = h*Sin30;\r\n\u00a0\u00a0\u00a0 s = 2*s2;\r\n\u00a0\u00a0\u00a0 bezD = h*.6;\r\n\u00a0\u00a0\u00a0 spinAngle = rotationAngle;\r\n\u00a0\u00a0\u00a0 strokeColor = c;\r\n\u00a0\u00a0\u00a0 ecode = new int[6];\r\n\u00a0\u00a0\u00a0 for (int i=0; i&lt;6; i++) ecode[i] = edgeStyle[i];\r\n\u00a0\u00a0\u00a0 barWeight = .125 * (h\/Sin30);\r\n\u00a0\u00a0\u00a0 changing = false;\r\n\u00a0\u00a0\u00a0 justStoppedChanging = false;\r\n\u00a0\u00a0\u00a0 changeEcode = new int[6];\r\n\u00a0 }\r\n\r\n\u00a0 void startChange(int startFrame, int stopFrame, \r\n                   boolean clockwise, int[] newcode) {\r\n\u00a0\u00a0\u00a0 changeStartFrame = startFrame;\r\n\u00a0\u00a0\u00a0 changeStopFrame = stopFrame;\r\n\u00a0\u00a0\u00a0 changeClockwise = clockwise;\r\n\u00a0\u00a0\u00a0 for (int i=0; i&lt;6; i++) changeEcode[i] = newcode[i];\r\n\u00a0\u00a0\u00a0 changing = true;\r\n\u00a0 }\r\n\r\n\u00a0 PVector lerpPVector(PVector a, PVector b, float alfa) {\r\n\u00a0\u00a0\u00a0 PVector c = new PVector(lerp(a.x, b.x, alfa), lerp(a.y, b.y, alfa));\r\n\u00a0\u00a0\u00a0 return(c);\r\n\u00a0 }\r\n\r\n\u00a0 float ease(float x) {\r\n\u00a0\u00a0\u00a0 return(map(cos(PI*x), 1, -1, 0, 1));\r\n\u00a0 }\r\n\r\n\u00a0 void render() {\r\n\u00a0\u00a0\u00a0 float blendNear = (s2-barWeight\/2.0)\/s;\r\n\u00a0\u00a0\u00a0 float blendFar\u00a0 = (s2+barWeight\/2.0)\/s;\r\n\u00a0\u00a0\u00a0 PVector ul = new PVector(-s2, -r);\r\n\u00a0\u00a0\u00a0 PVector ur = new PVector( s2, -r);\r\n\u00a0\u00a0\u00a0 PVector mr = new PVector(\u00a0 h,\u00a0 0);\r\n\u00a0\u00a0\u00a0 PVector lr = new PVector( s2,\u00a0 r);\r\n\u00a0\u00a0\u00a0 PVector ll = new PVector(-s2,\u00a0 r);\r\n\u00a0\u00a0\u00a0 PVector pA0 = lerpPVector(ul, ur, blendNear);\r\n\u00a0\u00a0\u00a0 PVector pB0 = lerpPVector(ul, ur, blendFar);\r\n\u00a0\u00a0\u00a0 PVector pC0 = lerpPVector(ur, mr, blendNear);\r\n\u00a0\u00a0\u00a0 PVector pD0 = lerpPVector(ur, mr, blendFar);\r\n\u00a0\u00a0\u00a0 PVector pE0 = lerpPVector(mr, lr, blendNear);\r\n\u00a0\u00a0\u00a0 PVector pF0 = lerpPVector(mr, lr, blendFar);\r\n\u00a0\u00a0\u00a0 PVector pG0 = lerpPVector(lr, ll, blendNear);\r\n\u00a0\u00a0\u00a0 PVector pH0 = lerpPVector(lr, ll, blendFar);\r\n\u00a0\u00a0\u00a0 PVector pA1 = new PVector(pA0.x, pA0.y+bezD);\r\n\u00a0\u00a0\u00a0 PVector pB1 = new PVector(pB0.x, pB0.y+bezD);\r\n\u00a0\u00a0\u00a0 PVector pC1 = new PVector(pC0.x - (bezD*Cos30), pC0.y + (bezD*Sin30));\r\n\u00a0\u00a0\u00a0 PVector pD1 = new PVector(pD0.x - (bezD*Cos30), pD0.y + (bezD*Sin30));\r\n\u00a0\u00a0\u00a0 PVector pE1 = new PVector(pE0.x - (bezD*Cos30), pE0.y - (bezD*Sin30));\r\n\u00a0\u00a0\u00a0 PVector pF1 = new PVector(pF0.x - (bezD*Cos30), pF0.y - (bezD*Sin30));\r\n\u00a0\u00a0\u00a0 PVector pG1 = new PVector(pG0.x, pG0.y-bezD);\r\n\u00a0\u00a0\u00a0 PVector pH1 = new PVector(pH0.x, pH0.y-bezD);\r\n\u00a0\u00a0\u00a0 justStoppedChanging = false;\r\n\r\n\u00a0\u00a0\u00a0 for (int i=0; i&lt;6; i++) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 pushMatrix();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 translate(cx, cy);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 rotate(i*PI\/3);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (changing) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (frameCount &gt; changeStopFrame) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 changing = false;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 justStoppedChanging = true;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (changeClockwise) spinAngle += PI\/3;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 else spinAngle -= PI\/3;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 } else {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 float theta = map(frameCount, changeStartFrame, \r\n                              changeStopFrame, 0, 1);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 theta = (PI\/3)*ease(theta);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 theta = min(theta, PI\/3);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (!changeClockwise) theta = -theta;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 rotate(theta);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 } \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 rotate(spinAngle);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 stroke(strokeColor);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 fill(strokeColor);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 strokeWeight(1);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/line(-s2, -r, s2, -r);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 beginShape();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 switch (ecode[i]) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 case 0:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 vertex(pA0.x, pA0.y);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 bezierVertex(pA1.x, pA1.y, pB1.x, pB1.y, pB0.x, pB0.y);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 break;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 case 1:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 case 5:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (ecode[i] == 5) rotate(-TWO_PI\/6);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 vertex(pA0.x, pA0.y);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 bezierVertex(pA1.x, pA1.y, pD1.x, pD1.y, pD0.x, pD0.y);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 vertex(pC0.x, pC0.y);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 bezierVertex(pC1.x, pC1.y, pB1.x, pB1.y, pB0.x, pB0.y);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 break;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 case 2:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 case 4:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (ecode[i] == 4) rotate(-TWO_PI\/3);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 vertex(pA0.x, pA0.y);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 bezierVertex(pA1.x, pA1.y, pF1.x, pF1.y, pF0.x, pF0.y);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 vertex(pE0.x, pE0.y);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 bezierVertex(pE1.x, pE1.y, pB1.x, pB1.y, pB0.x, pB0.y);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 break;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 case 3:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 vertex(pA0.x, pA0.y);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 vertex(pH0.x, pH0.y);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 vertex(pG0.x, pG0.y);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 vertex(pB0.x, pB0.y);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 break;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 default:\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 endShape(CLOSE);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 popMatrix();\r\n\u00a0\u00a0\u00a0 }\r\n\u00a0 }\r\n}<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>I finished up a project the other day, so I gave myself a few minutes to make something just for fun. Here&#8217;s a grid of hexagonal tiles with little bits of graphics in them. Over time, random tiles rotate to create a new pattern (in this screenshot, you can see 5 tiles in mid-rotation). I [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-146","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/www.imaginary-institute.com\/blog\/wp-json\/wp\/v2\/posts\/146","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.imaginary-institute.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.imaginary-institute.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.imaginary-institute.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.imaginary-institute.com\/blog\/wp-json\/wp\/v2\/comments?post=146"}],"version-history":[{"count":11,"href":"https:\/\/www.imaginary-institute.com\/blog\/wp-json\/wp\/v2\/posts\/146\/revisions"}],"predecessor-version":[{"id":161,"href":"https:\/\/www.imaginary-institute.com\/blog\/wp-json\/wp\/v2\/posts\/146\/revisions\/161"}],"wp:attachment":[{"href":"https:\/\/www.imaginary-institute.com\/blog\/wp-json\/wp\/v2\/media?parent=146"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.imaginary-institute.com\/blog\/wp-json\/wp\/v2\/categories?post=146"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.imaginary-institute.com\/blog\/wp-json\/wp\/v2\/tags?post=146"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}