{"id":293,"date":"2015-09-04T09:41:45","date_gmt":"2015-09-04T13:41:45","guid":{"rendered":"https:\/\/blogs.mathworks.com\/graphics\/?p=293"},"modified":"2016-08-23T10:40:45","modified_gmt":"2016-08-23T14:40:45","slug":"tiling-quadrilaterals","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/graphics\/2015\/09\/04\/tiling-quadrilaterals\/","title":{"rendered":"Tiling Quadrilaterals"},"content":{"rendered":"<div class=\"content\"><h3>Tiling Quadrilaterals<\/h3><p>Last time I was <a href=\"https:\/\/blogs.mathworks.com\/graphics\/2015\/08\/19\/type-15-convex-pentagon\/\">talking about the new pentagon tiling<\/a> which was recently discovered. There are lots of other wonderful things to explore in how polygons tile the plane. One of my favorites involves quadrilaterals. They're much easier to tile than pentagons are. That's because the sum of their internal angles is 360 degrees. In fact, quadrilaterals are so easy to tile that you can make a tiling from any quadrilateral at all! Let's take a look at how that works.<\/p><p>First we'll need a random quadrilateral. That's a bit trickier than you might think. We obviously want to start with 4 random points, but what order do we connect the points in? With triangles it's simple, but with quadrilaterals we need to avoid orders that have self intersections like this one:<\/p><pre class=\"codeinput\">rng <span class=\"string\">default<\/span>\r\nx = randn(1,4);\r\ny = randn(1,4);\r\ncols = get(gca,<span class=\"string\">'ColorOrder'<\/span>);\r\npatch(<span class=\"string\">'XData'<\/span>,x,<span class=\"string\">'YData'<\/span>,y,<span class=\"string\">'FaceColor'<\/span>,cols(1,:))\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/quadrilateral_01.png\" alt=\"\"> <p>We could use convhull, but that would leave out concave quads, and we're interested in them. We want to eliminate the self intersecting cases without eliminating the concave cases.<\/p><p>It turns out that one of the simplest ways to create a random quadrilateral in MATLAB is to create a Delaunay triangulation from the random points, and then keep 2 of the triangles. This is actually a useful technique to know because it extends to larger polygons, as you can see <a href=\"http:\/\/stackoverflow.com\/questions\/8997099\/algorithm-to-generate-random-2d-polygon\">here<\/a>.<\/p><p>The implementation of that (minus some coincident point error checking) looks something like this:<\/p><pre class=\"language-matlab\"><span class=\"keyword\">function<\/span> [x, y] = random_quad()\r\n  <span class=\"comment\">% Start with 4 random points<\/span>\r\n  x = randn(1,4);\r\n  y = randn(1,4);\r\n  <span class=\"comment\">% Triangulate them<\/span>\r\n  t = delaunayTriangulation(x',y');\r\n  <span class=\"comment\">% If we found 3 triangles, throw one away<\/span>\r\n  <span class=\"keyword\">if<\/span> size(t,1) &gt; 2\r\n    t = triangulation(t.ConnectivityList(1:2,:),x',y');\r\n  <span class=\"keyword\">end<\/span>\r\n  <span class=\"comment\">% Return the points in the order of the boundary<\/span>\r\n  bound = freeBoundary(t);\r\n  bound = bound(:,1);\r\n  x = x(bound);\r\n  y = y(bound);\r\n<\/pre><p>Let's draw a bunch of those and see if they look nice and random.<\/p><pre class=\"codeinput\">cla\r\n<span class=\"keyword\">for<\/span> i=1:5\r\n    <span class=\"keyword\">for<\/span> j=1:4\r\n        [x,y] = random_quad;\r\n        patch(<span class=\"string\">'XData'<\/span>,x+i*4,<span class=\"string\">'YData'<\/span>,y+j*4,<span class=\"string\">'FaceColor'<\/span>,rand(1,3))\r\n    <span class=\"keyword\">end<\/span>\r\n<span class=\"keyword\">end<\/span>\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/quadrilateral_02.png\" alt=\"\"> <p>Those look pretty good, so let's pick one and see how we can tile the plane with it.<\/p><p>I found this one that I like the looks of, so we'll use it as for our example. But remember, this algorithm will work with any quadrilateral that doesn't self intersect.<\/p><pre class=\"codeinput\">rng(1913)\r\n[x,y] = random_quad;\r\n\r\ncla\r\naxis <span class=\"string\">equal<\/span>\r\npatch(<span class=\"string\">'XData'<\/span>,x,<span class=\"string\">'YData'<\/span>,y,<span class=\"string\">'FaceColor'<\/span>,cols(1,:))\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/quadrilateral_03.png\" alt=\"\"> <p>So how are we going to tile the plane with this? One thing we can see is that if we rotate a copy of it by 180 degrees around the center of one of the edges, then the two quads will line up nicely. We can use the same transform matrices we used <a href=\"https:\/\/blogs.mathworks.com\/graphics\/2015\/08\/19\/type-15-convex-pentagon\/\">last time<\/a>.<\/p><pre class=\"codeinput\"><span class=\"comment\">% Points in the convenient form for transforming<\/span>\r\npts = [x; y; ones(1,4)];\r\n\r\n<span class=\"comment\">% Matrix which rotates by 180 degrees<\/span>\r\nrotmat = [-1  0 0; <span class=\"keyword\">...<\/span>\r\n           0 -1 0; <span class=\"keyword\">...<\/span>\r\n           0  0 1];\r\n\r\n<span class=\"comment\">% The center of the first edge<\/span>\r\nc = pts(:,1)\/2 + pts(:,2)\/2;\r\n\r\n<span class=\"comment\">% Rotate by 180, and translate into place<\/span>\r\noffset = rotmat*c - c;\r\nxlatmat = [1 0 offset(1); <span class=\"keyword\">...<\/span>\r\n           0 1 offset(2); <span class=\"keyword\">...<\/span>\r\n           0 0         1];\r\np2 = rotmat*xlatmat*pts;\r\n\r\n<span class=\"comment\">% and draw<\/span>\r\npatch(<span class=\"string\">'XData'<\/span>,p2(1,:),<span class=\"string\">'YData'<\/span>,p2(2,:),<span class=\"string\">'FaceColor'<\/span>,cols(2,:))\r\ncm = line(c(1),c(2),<span class=\"string\">'Color'<\/span>,<span class=\"string\">'black'<\/span>,<span class=\"string\">'Marker'<\/span>,<span class=\"string\">'o'<\/span>,<span class=\"string\">'MarkerSize'<\/span>,12);\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/quadrilateral_04.png\" alt=\"\"> <p>And we could do the same thing around the second edge:<\/p><pre class=\"codeinput\">c = pts(:,2)\/2 + pts(:,3)\/2;\r\noffset = rotmat*c - c;\r\nxlatmat = [1 0 offset(1); <span class=\"keyword\">...<\/span>\r\n           0 1 offset(2); <span class=\"keyword\">...<\/span>\r\n           0 0         1];\r\np2 = rotmat*xlatmat*pts;\r\npatch(<span class=\"string\">'XData'<\/span>,p2(1,:),<span class=\"string\">'YData'<\/span>,p2(2,:),<span class=\"string\">'FaceColor'<\/span>,cols(3,:))\r\ndelete(cm)\r\ncm = line(c(1),c(2),<span class=\"string\">'Color'<\/span>,<span class=\"string\">'black'<\/span>,<span class=\"string\">'Marker'<\/span>,<span class=\"string\">'o'<\/span>,<span class=\"string\">'MarkerSize'<\/span>,12);\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/quadrilateral_05.png\" alt=\"\"> <p>... or the third edge:<\/p><pre class=\"codeinput\">c = pts(:,3)\/2 + pts(:,4)\/2;\r\noffset = rotmat*c - c;\r\nxlatmat = [1 0 offset(1); <span class=\"keyword\">...<\/span>\r\n           0 1 offset(2); <span class=\"keyword\">...<\/span>\r\n           0 0         1];\r\np2 = rotmat*xlatmat*pts;\r\npatch(<span class=\"string\">'XData'<\/span>,p2(1,:),<span class=\"string\">'YData'<\/span>,p2(2,:),<span class=\"string\">'FaceColor'<\/span>,cols(4,:))\r\ndelete(cm)\r\ncm = line(c(1),c(2),<span class=\"string\">'Color'<\/span>,<span class=\"string\">'black'<\/span>,<span class=\"string\">'Marker'<\/span>,<span class=\"string\">'o'<\/span>,<span class=\"string\">'MarkerSize'<\/span>,12);\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/quadrilateral_06.png\" alt=\"\"> <p>... or the fourth edge:<\/p><pre class=\"codeinput\">c = pts(:,4)\/2 + pts(:,1)\/2;\r\noffset = rotmat*c - c;\r\nxlatmat = [1 0 offset(1); <span class=\"keyword\">...<\/span>\r\n           0 1 offset(2); <span class=\"keyword\">...<\/span>\r\n           0 0         1];\r\np2 = rotmat*xlatmat*pts;\r\npatch(<span class=\"string\">'XData'<\/span>,p2(1,:),<span class=\"string\">'YData'<\/span>,p2(2,:),<span class=\"string\">'FaceColor'<\/span>,cols(5,:))\r\ndelete(cm)\r\ncm = line(c(1),c(2),<span class=\"string\">'Color'<\/span>,<span class=\"string\">'black'<\/span>,<span class=\"string\">'Marker'<\/span>,<span class=\"string\">'o'<\/span>,<span class=\"string\">'MarkerSize'<\/span>,12);\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/quadrilateral_07.png\" alt=\"\"> <p>We notice a few things looking at this picture.<\/p><p>All four of those new copies are translations of each other, because they're all 180 degree rotations of the original.<\/p><p>And there appear to be gaps between them that look like the original quad.<\/p><p>In fact, if we do the same for any of the \"other\" three sides of each of those copies, we'll see that we get a translation of the original (because two rotations by 180 degrees cancel) which does tuck into one of the holes.<\/p><pre class=\"codeinput\"><span class=\"comment\">% Rotate around the first side again<\/span>\r\nc1 = pts(:,1)\/2 + pts(:,2)\/2;\r\noffset = rotmat*c1 - c1;\r\nxlatmat = [1 0 offset(1); <span class=\"keyword\">...<\/span>\r\n           0 1 offset(2); <span class=\"keyword\">...<\/span>\r\n           0 0         1];\r\np2 = rotmat*xlatmat*pts;\r\n\r\n<span class=\"comment\">% And then rotate that around the second side of the result.<\/span>\r\nc2 = p2(:,2)\/2 + p2(:,3)\/2;\r\noffset = rotmat*c2 - c2;\r\nxlatmat = [1 0 offset(1); <span class=\"keyword\">...<\/span>\r\n           0 1 offset(2); <span class=\"keyword\">...<\/span>\r\n           0 0         1];\r\np3 = rotmat*xlatmat*p2;\r\n\r\ndelete(cm)\r\npatch(<span class=\"string\">'XData'<\/span>,p3(1,:),<span class=\"string\">'YData'<\/span>,p3(2,:),<span class=\"string\">'FaceColor'<\/span>,cols(6,:))\r\ncm = line([c1(1) c2(1)],[c1(2) c2(2)],<span class=\"string\">'Color'<\/span>,<span class=\"string\">'black'<\/span>,<span class=\"string\">'LineStyle'<\/span>,<span class=\"string\">'none'<\/span>,<span class=\"string\">'Marker'<\/span>,<span class=\"string\">'o'<\/span>,<span class=\"string\">'MarkerSize'<\/span>,12);\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/quadrilateral_08.png\" alt=\"\"> <p>This means that fundamental region of this tiling consists of two copies of the original quadrilateral, one of which is rotated by 180 degrees, and which share one side. We can pick any two neighbors, but I'll pick the first two we drew.<\/p><pre class=\"codeinput\">cla\r\naxis <span class=\"string\">off<\/span>\r\nset(gca,<span class=\"string\">'Position'<\/span>,[0 0 1 1])\r\nxdata = pts(1,:);\r\nydata = pts(2,:);\r\n\r\nc = [(pts(1:2,1) + pts(1:2,2))\/2; 1];\r\noffset = rotmat*c - c;\r\nxlatmat = [1 0 offset(1); <span class=\"keyword\">...<\/span>\r\n           0 1 offset(2); <span class=\"keyword\">...<\/span>\r\n           0 0         1];\r\np2 = rotmat*xlatmat*pts;\r\nxdata(2,:) = p2(1,:);\r\nydata(2,:) = p2(2,:);\r\n\r\ndark = [.75 .75 .75];\r\nlight = [.875 .875 .875];\r\npatch(<span class=\"string\">'XData'<\/span>,xdata',<span class=\"string\">'YData'<\/span>,ydata',<span class=\"string\">'FaceColor'<\/span>,dark)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/quadrilateral_09.png\" alt=\"\"> <p>And we can use these two translation vectors ...<\/p><pre class=\"codeinput\">uvec = pts(:,1) - pts(:,3);\r\nvvec = pts(:,2) - pts(:,4);\r\n<\/pre><p>... to assemble copies of the fundamental region into a tiling.<\/p><pre class=\"codeinput\">cla\r\npatch(<span class=\"string\">'XData'<\/span>,xdata'+uvec(1),<span class=\"string\">'YData'<\/span>,ydata'+uvec(2),<span class=\"string\">'FaceColor'<\/span>,light,<span class=\"string\">'EdgeColor'<\/span>,dark)\r\npatch(<span class=\"string\">'XData'<\/span>,xdata'+vvec(1),<span class=\"string\">'YData'<\/span>,ydata'+vvec(2),<span class=\"string\">'FaceColor'<\/span>,light,<span class=\"string\">'EdgeColor'<\/span>,dark)\r\npatch(<span class=\"string\">'XData'<\/span>,xdata',<span class=\"string\">'YData'<\/span>,ydata',<span class=\"string\">'FaceColor'<\/span>,light)\r\nline(pts(1,1) + [0 uvec(1)],pts(2,1) + [0 uvec(2)],<span class=\"string\">'Color'<\/span>,cols(1,:),<span class=\"string\">'LineWidth'<\/span>,2)\r\nline(pts(1,1) + [0 vvec(1)],pts(2,1) + [0 vvec(2)],<span class=\"string\">'Color'<\/span>,cols(2,:),<span class=\"string\">'LineWidth'<\/span>,2)\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/quadrilateral_10.png\" alt=\"\"> <p>And we can repeat as far as we'd like.<\/p><pre class=\"codeinput\">cla\r\n<span class=\"keyword\">for<\/span> i=-7:7\r\n    <span class=\"keyword\">for<\/span> j=-5:5\r\n        ci = mod(3*j+2*i,5);\r\n        h = patch(<span class=\"string\">'XData'<\/span>,xdata' + i*uvec(1) + j*vvec(1),<span class=\"string\">'YData'<\/span>,ydata' + i*uvec(2) + j*vvec(2));\r\n        h.FaceVertexCData = cols(ci+(1:2),:);\r\n        h.FaceColor = <span class=\"string\">'flat'<\/span>;\r\n    <span class=\"keyword\">end<\/span>\r\n<span class=\"keyword\">end<\/span>\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/quadrilateral_11.png\" alt=\"\"> <p>And finally, let's zoom in for a closer look.<\/p><pre class=\"codeinput\">ax = gca;\r\nax.Position = [0 0 1 1];\r\nset(ax.Children,<span class=\"string\">'EdgeColor'<\/span>,<span class=\"string\">'none'<\/span>)\r\nylim([-3.5 3.5])\r\n<\/pre><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/quadrilateral_12.png\" alt=\"\"> <p>And here are a couple more which I created with different seeds for the random number generator.<\/p><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/quadtile_seed983.png\" alt=\"\"> <\/p><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/quadtile_seed8111212.png\" alt=\"\"> <\/p><p><img decoding=\"async\" vspace=\"5\" hspace=\"5\" src=\"https:\/\/blogs.mathworks.com\/images\/graphics\/2015\/quadtile_seed123234.png\" alt=\"\"> <\/p><p>Aren't those fun? Wouldn't you like a set of tiles like that for your kitchen floor? They'd wake you up in the morning.<\/p><script language=\"JavaScript\"> <!-- \r\n    function grabCode_6a686efa3819435f8de78b0d87b19eaf() {\r\n        \/\/ Remember the title so we can use it in the new page\r\n        title = document.title;\r\n\r\n        \/\/ Break up these strings so that their presence\r\n        \/\/ in the Javascript doesn't mess up the search for\r\n        \/\/ the MATLAB code.\r\n        t1='6a686efa3819435f8de78b0d87b19eaf ' + '##### ' + 'SOURCE BEGIN' + ' #####';\r\n        t2='##### ' + 'SOURCE END' + ' #####' + ' 6a686efa3819435f8de78b0d87b19eaf';\r\n    \r\n        b=document.getElementsByTagName('body')[0];\r\n        i1=b.innerHTML.indexOf(t1)+t1.length;\r\n        i2=b.innerHTML.indexOf(t2);\r\n \r\n        code_string = b.innerHTML.substring(i1, i2);\r\n        code_string = code_string.replace(\/REPLACE_WITH_DASH_DASH\/g,'--');\r\n\r\n        \/\/ Use \/x3C\/g instead of the less-than character to avoid errors \r\n        \/\/ in the XML parser.\r\n        \/\/ Use '\\x26#60;' instead of '<' so that the XML parser\r\n        \/\/ doesn't go ahead and substitute the less-than character. \r\n        code_string = code_string.replace(\/\\x3C\/g, '\\x26#60;');\r\n\r\n        copyright = 'Copyright 2015 The MathWorks, Inc.';\r\n\r\n        w = window.open();\r\n        d = w.document;\r\n        d.write('<pre>\\n');\r\n        d.write(code_string);\r\n\r\n        \/\/ Add copyright line at the bottom if specified.\r\n        if (copyright.length > 0) {\r\n            d.writeln('');\r\n            d.writeln('%%');\r\n            if (copyright.length > 0) {\r\n                d.writeln('% _' + copyright + '_');\r\n            }\r\n        }\r\n\r\n        d.write('<\/pre>\\n');\r\n\r\n        d.title = title + ' (MATLAB code)';\r\n        d.close();\r\n    }   \r\n     --> <\/script><p style=\"text-align: right; font-size: xx-small; font-weight:lighter;   font-style: italic; color: gray\"><br><a href=\"javascript:grabCode_6a686efa3819435f8de78b0d87b19eaf()\"><span style=\"font-size: x-small;        font-style: italic;\">Get \r\n      the MATLAB code <noscript>(requires JavaScript)<\/noscript><\/span><\/a><br><br>\r\n      Published with MATLAB&reg; R2015a<br><\/p><\/div><!--\r\n6a686efa3819435f8de78b0d87b19eaf ##### SOURCE BEGIN #####\r\n%% Tiling Quadrilaterals\r\n% Last time I was <https:\/\/blogs.mathworks.com\/graphics\/2015\/08\/19\/type-15-convex-pentagon\/\r\n% talking about the new pentagon tiling> which was recently\r\n% discovered. There are lots of other wonderful things to explore in how\r\n% <http:\/\/euler.slu.edu\/escher\/index.php\/Tessellations_by_Polygons polygons tile the plane>. \r\n% One of my favorites involves quadrilaterals. They're much easier to tile\r\n% than pentagons are. That's because the sum of their internal angles is\r\n% 360 degrees. In fact, quadrilaterals are so easy to tile that you can\r\n% make a tiling from any quadrilateral at all! Let's take a look at how that works.\r\n%\r\n% First we'll need a random quadrilateral. That's a bit trickier than you\r\n% might think. We obviously want to start with 4 random points, but what\r\n% order do we connect the points in? With triangles it's simple, but with\r\n% quadrilaterals we need to avoid orders that have self intersections like\r\n% this one:\r\n%\r\nrng default\r\nx = randn(1,4);\r\ny = randn(1,4);\r\ncols = get(gca,'ColorOrder');\r\npatch('XData',x,'YData',y,'FaceColor',cols(1,:))\r\n\r\n%%\r\n% We could use convhull, but that would leave\r\n% out concave quads, and we're interested in them. We want to eliminate the\r\n% self intersecting cases without eliminating the concave cases.\r\n%\r\n% It turns out that one of the simplest ways to create a random\r\n% quadrilateral in MATLAB is to create a Delaunay triangulation from the\r\n% random points, and then keep 2 of the triangles. This is actually a useful\r\n% technique to know because it extends to larger polygons, as you can see \r\n% <http:\/\/stackoverflow.com\/questions\/8997099\/algorithm-to-generate-random-2d-polygon\r\n% here>.\r\n% \r\n% The implementation of that (minus some coincident point error checking) \r\n% looks something like this:\r\n%\r\n%\r\n%   function [x, y] = random_quad()\r\n%     % Start with 4 random points\r\n%     x = randn(1,4);\r\n%     y = randn(1,4);\r\n%     % Triangulate them\r\n%     t = delaunayTriangulation(x',y');\r\n%     % If we found 3 triangles, throw one away\r\n%     if size(t,1) > 2\r\n%       t = triangulation(t.ConnectivityList(1:2,:),x',y');\r\n%     end\r\n%     % Return the points in the order of the boundary\r\n%     bound = freeBoundary(t);\r\n%     bound = bound(:,1);\r\n%     x = x(bound);\r\n%     y = y(bound);\r\n%\r\n\r\n%%\r\n% Let's draw a bunch of those and see if they look nice and random.\r\n%\r\ncla\r\nfor i=1:5\r\n    for j=1:4\r\n        [x,y] = random_quad;\r\n        patch('XData',x+i*4,'YData',y+j*4,'FaceColor',rand(1,3))\r\n    end\r\nend\r\n\r\n%%\r\n% Those look pretty good, so let's pick one and see how we can tile the\r\n% plane with it. \r\n%\r\n% I found this one that I like the looks of, so we'll use it as for our\r\n% example. But remember, this algorithm will work with any quadrilateral\r\n% that doesn't self intersect.\r\n%\r\nrng(1913)\r\n[x,y] = random_quad;\r\n\r\ncla\r\naxis equal\r\npatch('XData',x,'YData',y,'FaceColor',cols(1,:))\r\n\r\n%%\r\n% So how are we going to tile the plane with this? One thing we can see is\r\n% that if we rotate a copy of it by 180 degrees around the center of one of \r\n% the edges, then the two quads will line up nicely. We can use the same\r\n% transform matrices we used\r\n% <https:\/\/blogs.mathworks.com\/graphics\/2015\/08\/19\/type-15-convex-pentagon\/\r\n% last time>.\r\n%\r\n\r\n% Points in the convenient form for transforming\r\npts = [x; y; ones(1,4)];\r\n\r\n% Matrix which rotates by 180 degrees\r\nrotmat = [-1  0 0; ...\r\n           0 -1 0; ...\r\n           0  0 1];\r\n\r\n% The center of the first edge\r\nc = pts(:,1)\/2 + pts(:,2)\/2;\r\n\r\n% Rotate by 180, and translate into place\r\noffset = rotmat*c - c;\r\nxlatmat = [1 0 offset(1); ...\r\n           0 1 offset(2); ...\r\n           0 0         1];\r\np2 = rotmat*xlatmat*pts;\r\n\r\n% and draw\r\npatch('XData',p2(1,:),'YData',p2(2,:),'FaceColor',cols(2,:))\r\ncm = line(c(1),c(2),'Color','black','Marker','o','MarkerSize',12);\r\n\r\n%%\r\n% And we could do the same thing around the second edge:\r\n%\r\nc = pts(:,2)\/2 + pts(:,3)\/2;\r\noffset = rotmat*c - c;\r\nxlatmat = [1 0 offset(1); ...\r\n           0 1 offset(2); ...\r\n           0 0         1];\r\np2 = rotmat*xlatmat*pts;\r\npatch('XData',p2(1,:),'YData',p2(2,:),'FaceColor',cols(3,:))\r\ndelete(cm)\r\ncm = line(c(1),c(2),'Color','black','Marker','o','MarkerSize',12);\r\n\r\n%%\r\n% ... or the third edge:\r\n%\r\nc = pts(:,3)\/2 + pts(:,4)\/2;\r\noffset = rotmat*c - c;\r\nxlatmat = [1 0 offset(1); ...\r\n           0 1 offset(2); ...\r\n           0 0         1];\r\np2 = rotmat*xlatmat*pts;\r\npatch('XData',p2(1,:),'YData',p2(2,:),'FaceColor',cols(4,:))\r\ndelete(cm)\r\ncm = line(c(1),c(2),'Color','black','Marker','o','MarkerSize',12);\r\n\r\n%%\r\n% ... or the fourth edge:\r\nc = pts(:,4)\/2 + pts(:,1)\/2;\r\noffset = rotmat*c - c;\r\nxlatmat = [1 0 offset(1); ...\r\n           0 1 offset(2); ...\r\n           0 0         1];\r\np2 = rotmat*xlatmat*pts;\r\npatch('XData',p2(1,:),'YData',p2(2,:),'FaceColor',cols(5,:))\r\ndelete(cm)\r\ncm = line(c(1),c(2),'Color','black','Marker','o','MarkerSize',12);\r\n\r\n%%\r\n% We notice a few things looking at this picture. \r\n%\r\n% All four of those new copies are translations of each other, because\r\n% they're all 180 degree rotations of the original.\r\n%\r\n% And there appear to be gaps between them that look like the original\r\n% quad.\r\n%\r\n% In fact, if we do the same for any of the \"other\" three sides of each of \r\n% those copies, we'll see that we get a translation of the original (because \r\n% two rotations by 180 degrees cancel) which does tuck into one of the holes.\r\n%\r\n\r\n% Rotate around the first side again\r\nc1 = pts(:,1)\/2 + pts(:,2)\/2;\r\noffset = rotmat*c1 - c1;\r\nxlatmat = [1 0 offset(1); ...\r\n           0 1 offset(2); ...\r\n           0 0         1];\r\np2 = rotmat*xlatmat*pts;\r\n\r\n% And then rotate that around the second side of the result.\r\nc2 = p2(:,2)\/2 + p2(:,3)\/2;\r\noffset = rotmat*c2 - c2;\r\nxlatmat = [1 0 offset(1); ...\r\n           0 1 offset(2); ...\r\n           0 0         1];\r\np3 = rotmat*xlatmat*p2;\r\n\r\ndelete(cm)\r\npatch('XData',p3(1,:),'YData',p3(2,:),'FaceColor',cols(6,:))\r\ncm = line([c1(1) c2(1)],[c1(2) c2(2)],'Color','black','LineStyle','none','Marker','o','MarkerSize',12);\r\n\r\n%%\r\n% This means that fundamental region of this tiling consists of two copies\r\n% of the original quadrilateral, one of which is rotated by 180 degrees,\r\n% and which share one side. We can pick any two neighbors, but I'll pick\r\n% the first two we drew.\r\n%\r\ncla\r\naxis off\r\nset(gca,'Position',[0 0 1 1])\r\nxdata = pts(1,:);\r\nydata = pts(2,:);\r\n\r\nc = [(pts(1:2,1) + pts(1:2,2))\/2; 1];\r\noffset = rotmat*c - c;\r\nxlatmat = [1 0 offset(1); ...\r\n           0 1 offset(2); ...\r\n           0 0         1];\r\np2 = rotmat*xlatmat*pts;\r\nxdata(2,:) = p2(1,:);\r\nydata(2,:) = p2(2,:);\r\n\r\ndark = [.75 .75 .75];\r\nlight = [.875 .875 .875];\r\npatch('XData',xdata','YData',ydata','FaceColor',dark)\r\n\r\n\r\n%%\r\n% And we can use these two translation vectors ...\r\nuvec = pts(:,1) - pts(:,3);\r\nvvec = pts(:,2) - pts(:,4);\r\n\r\n%%\r\n% ... to assemble copies of the fundamental region into a tiling.\r\n%\r\ncla\r\npatch('XData',xdata'+uvec(1),'YData',ydata'+uvec(2),'FaceColor',light,'EdgeColor',dark)\r\npatch('XData',xdata'+vvec(1),'YData',ydata'+vvec(2),'FaceColor',light,'EdgeColor',dark)\r\npatch('XData',xdata','YData',ydata','FaceColor',light)\r\nline(pts(1,1) + [0 uvec(1)],pts(2,1) + [0 uvec(2)],'Color',cols(1,:),'LineWidth',2)\r\nline(pts(1,1) + [0 vvec(1)],pts(2,1) + [0 vvec(2)],'Color',cols(2,:),'LineWidth',2)\r\n\r\n%%\r\n% And we can repeat as far as we'd like.\r\n%\r\ncla\r\nfor i=-7:7\r\n    for j=-5:5\r\n        ci = mod(3*j+2*i,5);\r\n        h = patch('XData',xdata' + i*uvec(1) + j*vvec(1),'YData',ydata' + i*uvec(2) + j*vvec(2));\r\n        h.FaceVertexCData = cols(ci+(1:2),:);\r\n        h.FaceColor = 'flat';\r\n    end\r\nend\r\n\r\n%%\r\n% And finally, let's zoom in for a closer look.\r\nax = gca;\r\nax.Position = [0 0 1 1];\r\nset(ax.Children,'EdgeColor','none')\r\nylim([-3.5 3.5])\r\n\r\n%%\r\n% And here are a couple more which I created with different seeds for the\r\n% random number generator.\r\n%\r\n% <<..\/quadtile_seed983.png>>\r\n%\r\n% <<..\/quadtile_seed8111212.png>>\r\n%\r\n% <<..\/quadtile_seed123234.png>>\r\n%\r\n% Aren't those fun? Wouldn't you like a set of tiles like that for your\r\n% kitchen floor? They'd wake you up in the morning.\r\n\r\n##### SOURCE END ##### 6a686efa3819435f8de78b0d87b19eaf\r\n-->","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img src=\"https:\/\/blogs.mathworks.com\/graphics\/files\/feature_image\/quadtile_thumbnail.png\" class=\"img-responsive attachment-post-thumbnail size-post-thumbnail wp-post-image\" alt=\"\" decoding=\"async\" loading=\"lazy\" \/><\/div><p>Tiling QuadrilateralsLast time I was talking about the new pentagon tiling which was recently discovered. There are lots of other wonderful things to explore in how polygons tile the plane. One of my... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/graphics\/2015\/09\/04\/tiling-quadrilaterals\/\">read more >><\/a><\/p>","protected":false},"author":89,"featured_media":296,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[5],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/posts\/293"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/users\/89"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/comments?post=293"}],"version-history":[{"count":3,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/posts\/293\/revisions"}],"predecessor-version":[{"id":602,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/posts\/293\/revisions\/602"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/media\/296"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/media?parent=293"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/categories?post=293"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics\/wp-json\/wp\/v2\/tags?post=293"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}