{"id":863,"date":"2020-12-04T15:11:11","date_gmt":"2020-12-04T15:11:11","guid":{"rendered":"https:\/\/potatodie.nl\/diffuse-write-ups\/?p=863"},"modified":"2020-12-07T11:03:10","modified_gmt":"2020-12-07T11:03:10","slug":"transforms-and-symmetry-of-triangles","status":"publish","type":"post","link":"https:\/\/potatodie.nl\/diffuse-write-ups\/transforms-and-symmetry-of-triangles\/","title":{"rendered":"Create seamless patterns of triangles"},"content":{"rendered":"\n<p>In <a href=\"https:\/\/potatodie.nl\/diffuse-write-ups\/fun-with-canvas-transforms\/\" data-type=\"post\" data-id=\"702\">Fun with canvas transforms<\/a> a few basic examples of transforms with <code>canvas<\/code> where presented. Let&#8217;s make it a bit more interesting and create a tile of triangles to use as a seamless pattern as used in the <a href=\"https:\/\/potatodie.nl\/lab\/kaleidoscope\">Kaleidoscope toy tool<\/a>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"517\" src=\"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/12\/hexalogy1-1024x517.png\" alt=\"\" class=\"wp-image-864\" srcset=\"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/12\/hexalogy1-1024x517.png 1024w, https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/12\/hexalogy1-300x151.png 300w, https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/12\/hexalogy1-768x387.png 768w, https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/12\/hexalogy1-1200x605.png 1200w, https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/12\/hexalogy1.png 1346w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption>Kaleidoscope toy tool in triangle mode<\/figcaption><\/figure>\n\n\n\n<p>The point of depart is a triangular base fragment. The triangle is equilateral: all sides have the same length and (therefor) all angles are 60 degrees.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/12\/basicF-2.png\" alt=\"\" class=\"wp-image-867\" width=\"404\" height=\"350\" srcset=\"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/12\/basicF-2.png 600w, https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/12\/basicF-2-300x260.png 300w\" sizes=\"auto, (max-width: 404px) 100vw, 404px\" \/><\/figure>\n\n\n\n<p>Drawing copies of that image using transforms we will make the following tile:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"588\" src=\"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/12\/hexalogy2-3-1024x588.png\" alt=\"\" class=\"wp-image-871\" srcset=\"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/12\/hexalogy2-3-1024x588.png 1024w, https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/12\/hexalogy2-3-300x172.png 300w, https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/12\/hexalogy2-3-768x441.png 768w, https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/12\/hexalogy2-3-1200x689.png 1200w, https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/12\/hexalogy2-3.png 1259w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>If you add copies of the tile horizontally or vertically the pattern just goes on and on: it&#8217;s <em>seamless<\/em>.<\/p>\n\n\n\n<p>I find it useful when figuring out what transforms you need to get a desired result, to pick a point in the source fragment that you can use as an <em>anchor<\/em>. The anchor will be translated to it&#8217;s definite location and will not leave that place anymore whatever rotations or scalings follow. For the triangle you could use one of the vertices for an anchor, but I think it&#8217;s most clear to use the center of the triangle. <\/p>\n\n\n\n<p>But where is the center of the triangle? <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Centre of a triangle<\/h2>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/12\/triangle-center-1.svg\" alt=\"\" class=\"wp-image-885\" width=\"379\" height=\"340\"\/><\/figure>\n\n\n\n<p>Let&#8217;s first establish the height of the triangle. Suppose the sides of the triangle have length <code><em>d<\/em><\/code>, then the height <code><em>h<\/em><\/code> follows from Pythagoras&#8217;s theorem.<\/p>\n\n\n\n<div class=\"wp-block-katex-display-block katex-eq\" data-katex-display=\"true\"><pre>h = \\tfrac{1}{2} \\sqrt{3} d<\/pre><\/div>\n\n\n\n<p>A little more geometry shows that the distance of <em>M<\/em> to the top of the triangle is twice the distance of <em>M<\/em> to the base. So the coordinates of <code><em>M<\/em><\/code> relative to the left-top of the bounding box are<\/p>\n\n\n\n<div class=\"wp-block-katex-display-block katex-eq\" data-katex-display=\"true\"><pre>(\\tfrac{d}{2}, \\tfrac{2}{3}h)<\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Position centered triangle<\/h2>\n\n\n\n<p>If we draw the triangle image on position (0, 0)<\/p>\n\n\n<div class=\"wp-block-advanced-gutenberg-blocks-code\">\n  <header class=\"wp-block-advanced-gutenberg-blocks-code__header\">\n    <div class=\"wp-block-advanced-gutenberg-blocks-code__lang is-lang-js\">\n      JS    <\/div>\n    <div class=\"wp-block-advanced-gutenberg-blocks-code__file\">\n          <\/div>\n  <\/header>\n  <textarea \n    class=\"wp-block-advanced-gutenberg-blocks-code__source\" \n    name=\"codemirror-436882363\" \n    id=\"codemirror-436882363\"\n  >ctx.drawImage(image, 0, 0)\t<\/textarea>\n  <script>\n    CodeMirror.fromTextArea( document.getElementById('codemirror-436882363'), {\n      mode: 'javascript',\n      readOnly: true,\n      theme: 'hopscotch', \n      lineNumbers: true,\n      firstLineNumber: 1,\n      matchBrackets: true,\n      indentUnit: 4,\n      tabSize: 4,\n      lineWrapping: true,\n    } ); \n  <\/script>\n<\/div>\n\n\n\n<p>the left-top of the triangle&#8217;s bounding box would land on the origin. To draw the triangle with its center on the origin you&#8217;d offset the coordinates with the negation of the values calculated above.<\/p>\n\n\n<div class=\"wp-block-advanced-gutenberg-blocks-code\">\n  <header class=\"wp-block-advanced-gutenberg-blocks-code__header\">\n    <div class=\"wp-block-advanced-gutenberg-blocks-code__lang is-lang-js\">\n      JS    <\/div>\n    <div class=\"wp-block-advanced-gutenberg-blocks-code__file\">\n          <\/div>\n  <\/header>\n  <textarea \n    class=\"wp-block-advanced-gutenberg-blocks-code__source\" \n    name=\"codemirror-1991660123\" \n    id=\"codemirror-1991660123\"\n  >ctx.drawImage(image, -d \/ 2, -2 * h \/ 3)\t<\/textarea>\n  <script>\n    CodeMirror.fromTextArea( document.getElementById('codemirror-1991660123'), {\n      mode: 'javascript',\n      readOnly: true,\n      theme: 'hopscotch', \n      lineNumbers: true,\n      firstLineNumber: 1,\n      matchBrackets: true,\n      indentUnit: 4,\n      tabSize: 4,\n      lineWrapping: true,\n    } ); \n  <\/script>\n<\/div>\n\n\n\n<p>Of course if the origin is in its original position you would just see a part of the triangle. But as we will move the origin by translation, we may hope to see more of it!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Understanding transforms<\/h2>\n\n\n\n<p>In the <a href=\"https:\/\/potatodie.nl\/diffuse-write-ups\/fun-with-canvas-transforms\/\" data-type=\"post\" data-id=\"702\">previous post on transforms<\/a> we mentioned that what is transformed is the drawing context, rather than the canvas. Put differently: a transform does not affect what already has been drawn, but affects what will be drawn afterwards.<\/p>\n\n\n\n<p>Another thing that may raise confusion is that if a transform follows another transform, the second transform is relative to the coordinate system after the first transform. (Unless of course you restore the original situation.)<\/p>\n\n\n\n<p>Example: if you rotate the drawing context with 45 degrees and then translate along the x-axis, you don&#8217;t move horizontally over the canvas, but diagonally, since the transformed x-axis is rotated 45 degrees. <\/p>\n\n\n\n<p>Another example (which is of importance for our goal of creating a seamless pattern): If you mirror the context in, for instance, the y-axis, using <code>scale(-1, 1)<\/code>, then rotate 30 degrees, you will see that graphics you draw afterwards will appear rotated -30 degrees. It&#8217;s like you are looking at it from the other side (or in a mirror).<\/p>\n\n\n\n<p>In the sandbox embedded below you can tinker with transforms and check that what happens meets your expectations.<\/p>\n\n\n\n<iframe src=\"https:\/\/codesandbox.io\/embed\/triangle-transforms-kngkt?codemirror=1\" style=\"width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;\" allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\" sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"><\/iframe>\n\n\n\n<p>For instance the transformations of the green triangle (on top of those for the blue triangle) are as follows:<\/p>\n\n\n<div class=\"wp-block-advanced-gutenberg-blocks-code\">\n  <header class=\"wp-block-advanced-gutenberg-blocks-code__header\">\n    <div class=\"wp-block-advanced-gutenberg-blocks-code__lang is-lang-js\">\n      JS    <\/div>\n    <div class=\"wp-block-advanced-gutenberg-blocks-code__file\">\n          <\/div>\n  <\/header>\n  <textarea \n    class=\"wp-block-advanced-gutenberg-blocks-code__source\" \n    name=\"codemirror-1518071849\" \n    id=\"codemirror-1518071849\"\n  > \/\/ GREEN TRIANGLE\n  color = &quot;#0f0&quot;;\n\n  \/\/ Set transformations\n  stageCtx.scale(-1, 1);\n  stageCtx.rotate((-1 * Math.PI) \/ 6);\n\n  drawTriangleAndAxes(ctx, d, h, color, sourceCanvas, stageCtx);<\/textarea>\n  <script>\n    CodeMirror.fromTextArea( document.getElementById('codemirror-1518071849'), {\n      mode: 'javascript',\n      readOnly: true,\n      theme: 'hopscotch', \n      lineNumbers: true,\n      firstLineNumber: 1,\n      matchBrackets: true,\n      indentUnit: 4,\n      tabSize: 4,\n      lineWrapping: true,\n    } ); \n  <\/script>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Build the pattern<\/h2>\n\n\n\n<p>Now we know how to draw transformed triangles on the spot we want them, we can build the pattern.<\/p>\n\n\n\n<p>Actually, we just need to create the top row, then mirror a copy of that row (again using transforms).<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1616\" height=\"951\" src=\"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-content\/uploads\/2020\/12\/top-row.svg\" alt=\"\" class=\"wp-image-891\"\/><\/figure>\n\n\n\n<p>From left to right the <em>y<\/em>-coordinate of the triangle center alternates between <code>2<em>h<\/em>\/3<\/code> and <code><em>h<\/em>\/3<\/code>. Let&#8217;s draw the first two:<\/p>\n\n\n<div class=\"wp-block-advanced-gutenberg-blocks-code\">\n  <header class=\"wp-block-advanced-gutenberg-blocks-code__header\">\n    <div class=\"wp-block-advanced-gutenberg-blocks-code__lang is-lang-js\">\n      JS    <\/div>\n    <div class=\"wp-block-advanced-gutenberg-blocks-code__file\">\n          <\/div>\n  <\/header>\n  <textarea \n    class=\"wp-block-advanced-gutenberg-blocks-code__source\" \n    name=\"codemirror-2083005727\" \n    id=\"codemirror-2083005727\"\n  >\/\/ First triangle, pointing up\nctx.save()\nctx.translate(0, 2 * h \/ 3)\nctx.drawImage(triangleCanvas, -d \/ 2, -2 * h \/ 3);\nctx.restore()\n\n\/\/ Second triangle, pointing down\nctx.save()\nctx.translate(d \/ 2, h \/ 3)\nctx.scale(-1, 1);\nctx.rotate(Math.PI \/ 3);\nctx.drawImage(triangleCanvas, -d \/ 2, -2 * h \/ 3);\nctx.restore()<\/textarea>\n  <script>\n    CodeMirror.fromTextArea( document.getElementById('codemirror-2083005727'), {\n      mode: 'javascript',\n      readOnly: true,\n      theme: 'hopscotch', \n      lineNumbers: true,\n      firstLineNumber: 1,\n      matchBrackets: true,\n      indentUnit: 4,\n      tabSize: 4,\n      lineWrapping: true,\n    } ); \n  <\/script>\n<\/div>\n\n\n\n<p>This follows the strategy outlined above of anchoring the triangle&#8217;s center each time, then scale\/rotate. Variations are possible, but the variation chosen above allows to draw all triangles of the top row in a loop:<\/p>\n\n\n<div class=\"wp-block-advanced-gutenberg-blocks-code\">\n  <header class=\"wp-block-advanced-gutenberg-blocks-code__header\">\n    <div class=\"wp-block-advanced-gutenberg-blocks-code__lang is-lang-js\">\n      JS    <\/div>\n    <div class=\"wp-block-advanced-gutenberg-blocks-code__file\">\n          <\/div>\n  <\/header>\n  <textarea \n    class=\"wp-block-advanced-gutenberg-blocks-code__source\" \n    name=\"codemirror-231208727\" \n    id=\"codemirror-231208727\"\n  >for (let i = 0; i &lt; 7; i++) {\n    ctx.save();\n    if (i % 2) {\n        ctx.translate((i * d) \/ 2, h \/ 3);\n        ctx.scale(-1, 1);\n    } else {\n        ctx.translate((i * d) \/ 2, 2 * h \/ 3);\n    }\n    ctx.rotate((i * Math.PI) \/ 3);\n    ctx.drawImage(triangleCanvas, -d \/ 2, -2 * h \/ 3);\n    ctx.restore();\n}<\/textarea>\n  <script>\n    CodeMirror.fromTextArea( document.getElementById('codemirror-231208727'), {\n      mode: 'javascript',\n      readOnly: true,\n      theme: 'hopscotch', \n      lineNumbers: true,\n      firstLineNumber: 1,\n      matchBrackets: true,\n      indentUnit: 4,\n      tabSize: 4,\n      lineWrapping: true,\n    } ); \n  <\/script>\n<\/div>\n\n\n\n<p>Now add a mirrored copy of what we have sofar. The sandbox below shows the end result.<\/p>\n\n\n\n<iframe src=\"https:\/\/codesandbox.io\/embed\/hexatile-pattern-with-capital-f-detyh?codemirror=1\" style=\"width:100%; height:400px; border:0; border-radius: 4px; overflow:hidden;\" allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\" sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"><\/iframe>\n\n\n\n<h2 class=\"wp-block-heading\">Finished pattern<\/h2>\n\n\n\n<p>So now the tile is ready to <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/CanvasRenderingContext2D\/createPattern\">use as a pattern<\/a> for <code>fill<\/code> operations!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In Fun with canvas transforms a few basic examples of transforms with canvas where presented. Let&#8217;s make it a bit more interesting and create a tile of triangles to use as a seamless pattern as used in the Kaleidoscope toy tool. The point of depart is a triangular base fragment. The triangle is equilateral: all [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[30,20,29,2,7],"tags":[39,45,12,47],"class_list":["post-863","post","type-post","status-publish","format-standard","hentry","category-geometry","category-javascript","category-mathematics","category-patterns","category-web-development","tag-canvas","tag-symmetry","tag-transform","tag-triangle"],"acf":[],"_links":{"self":[{"href":"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-json\/wp\/v2\/posts\/863","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-json\/wp\/v2\/comments?post=863"}],"version-history":[{"count":19,"href":"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-json\/wp\/v2\/posts\/863\/revisions"}],"predecessor-version":[{"id":917,"href":"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-json\/wp\/v2\/posts\/863\/revisions\/917"}],"wp:attachment":[{"href":"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-json\/wp\/v2\/media?parent=863"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-json\/wp\/v2\/categories?post=863"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/potatodie.nl\/diffuse-write-ups\/wp-json\/wp\/v2\/tags?post=863"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}