<br />
<b>Warning</b>:  Declaration of Jetpack_IXR_Client::query() should be compatible with IXR_Client::query(...$args) in <b>/home/clients/7267bc096562fcdb78c0ab60d3ac51fb/web/blog/wp-content/plugins/jetpack/class.jetpack-ixr-client.php</b> on line <b>91</b><br />
{"id":921,"date":"2016-11-17T12:48:09","date_gmt":"2016-11-17T12:48:09","guid":{"rendered":"http:\/\/barradeau.com\/blog\/?p=921"},"modified":"2016-11-17T12:48:09","modified_gmt":"2016-11-17T12:48:09","slug":"triangle-grid-breakdown","status":"publish","type":"post","link":"https:\/\/barradeau.com\/blog\/?p=921","title":{"rendered":"Triangle grid breakdown"},"content":{"rendered":"<p>this is a reply to @upupzealot asking for more details about <a href=\"https:\/\/codepen.io\/nicoptere\/details\/vXoxJz\/\">this pen<\/a>.<\/p>\n<p>there is no random so to speak, the PRNG (Pseudo Random Number Generator) creates a seed-based (&amp; therefore reproductible) series of seemingly random numbers.<br \/>\nthe first thing I do, line 1 is to create a self contained PRNG object (it&#8217;s a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Mersenne_Twister\">Mersenne twister<\/a> btw):<\/p>\n<pre class=\"lang:js decode:true \">var PRNG = function( exports )<\/pre>\n<p>then I set up a canvas \/ context, nothing special.<\/p>\n<p>in the update() function, the first thing I do is to reset the PRNG value: `PRNG.setSeed(3);` to make sure I&#8217;ll get the same random sequence each time.<\/p>\n<p>then the first loop creates vertices (2D points)<br \/>\nit&#8217;s done in 2 steps, first create <strong><em>count<\/em><\/strong>\u00a0points (lattices) around the center at a random angle <strong><em>a<\/em><\/strong> and a random radius <strong><em>r<\/em><\/strong>.<br \/>\nthen create <em><strong>spawn<\/strong><\/em>\u00a0points around this lattice also at a random angle but with a much smaller radius <strong><em>offset<\/em><\/strong>.<\/p>\n<pre class=\"lang:js decode:true\">var r, a, v, o;\r\nvar count = 20;\r\nvar spawn = 40;\r\nvar offset = 100;\r\nvertices = [];\r\nfor( var i = 0; i &lt; count; i++ ){\r\n\r\n    r = ( PRNG.random() - .5 ) * window.innerWidth \/ 2;\r\n    \/\/ NB (i%2==0?-1:1) flips the direction of every other particle.\r\n    \/\/ the \"even\" lattices rotate clockwise \r\n    \/\/ and \"odd\" lattices rotate counter clockwise.\r\n    a = (i%2==0?1:-1) * Date.now() * 0.0001 + PRNG.random() * Math.PI * 2;\r\n\r\n    \/\/create a vertex: an array where [0] is x and [1] is y\r\n    v = [\r\n        Math.cos( a ) * r,\r\n        Math.sin( a ) * r\r\n    ];\r\n    \/\/ unshift() is like push() but at the biginning of the array\r\n    vertices.unshift( v );\r\n\r\n    \/\/this is where the \"children\" are build around the lattice\r\n    for( var j = 0; j &lt; spawn * ( .5 + PRNG.random() ); j++ ){\r\n\r\n        r = PRNG.random() * offset;\r\n        a = (j%2==0?-1:1) * Date.now() * 0.0002 + PRNG.random() * Math.PI * 2;\r\n\r\n        \/\/ as the lattice was \"unshifted()\" to vertices and not pushed,\r\n        \/\/ it is at position 0 in the array, so vertices[0] is the point we created above\r\n        o = vertices[ 0 ];\r\n\r\n        \/\/we use it as the center to position this vertex\r\n        v = [\r\n            o[0] + Math.cos( a % r ) * r,\r\n            o[1] + Math.sin( a % r * 2 ) * r\r\n        ];\r\n        vertices.push( v );\r\n    }\r\n}<\/pre>\n<p>then we have some context reset and we call yolo a given amount of times so it renders at different scales.<\/p>\n<pre class=\"lang:js decode:true\">var m = size\/8;\r\nfor( i = 8; i &lt;= m; i *= 2 ){\r\n    ctx.globalAlpha = (1 - i\/m) * .1;\r\n    yolo( vertices, i, size, size );\r\n}<\/pre>\n<p>the yolo() method will build a virtual equilateral triangles&#8217; grid to determine the closest lattices of the grid to each vertex then decide how to render it. it can be either:<\/p>\n<ul>\n<li>a line from the vertex to the closest lattice of the grid<\/li>\n<li>the closest edge of the grid without connection to the vertex<\/li>\n<li>a filled triangle between the 3 closest points of the grid<\/li>\n<\/ul>\n<p>to compute the equilateral triangles grid, we need to compute some variables, especially an equilateral triangle side length and height.<br \/>\nnote that this also work for N-sided regular polygons, in this case we have 3 sides.<\/p>\n<pre class=\"lang:js decode:true \">function yolo( vertices, size, _w, _h ){\r\n\r\n    \/\/measures of an equalateral triangle\r\n    var sides = 3;\r\n    var l = 2 * Math.sin( Math.PI \/ sides ); \/\/side length\r\n    var a = l \/ ( 2 * Math.tan( Math.PI \/ sides ) ); \/\/apothem\r\n    var h = ( 1 + a ); \/\/radius + apothem\r\n<\/pre>\n<p>here&#8217;s a visual helper for the values above:<br \/>\n<img decoding=\"async\" loading=\"lazy\" class=\"aligncenter size-full wp-image-923\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2016\/11\/equilateral_0.png\" alt=\"equilateral_0\" width=\"778\" height=\"413\" srcset=\"https:\/\/barradeau.com\/blog\/wp-content\/uploads\/2016\/11\/equilateral_0.png 778w, https:\/\/barradeau.com\/blog\/wp-content\/uploads\/2016\/11\/equilateral_0-300x159.png 300w, https:\/\/barradeau.com\/blog\/wp-content\/uploads\/2016\/11\/equilateral_0-768x408.png 768w\" sizes=\"(max-width: 778px) 100vw, 778px\" \/><\/p>\n<p>we now have the dimensions of a <em>module<\/em> that contains a triangle, and with this <em>module<\/em>, we can build a grid like this:<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter size-full wp-image-924\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2016\/11\/equilateral_1.png\" alt=\"equilateral_1\" width=\"521\" height=\"451\" srcset=\"https:\/\/barradeau.com\/blog\/wp-content\/uploads\/2016\/11\/equilateral_1.png 521w, https:\/\/barradeau.com\/blog\/wp-content\/uploads\/2016\/11\/equilateral_1-300x260.png 300w\" sizes=\"(max-width: 521px) 100vw, 521px\" \/><\/p>\n<pre class=\"lang:js decode:true\">    size = size || 1;\r\n    l *= size;\r\n    h *= size;\r\n\r\n    var mx = 2 * Math.ceil( _w \/ l );\r\n    var my = Math.ceil( _h \/ h );\r\n\r\n    var fills = [];\r\n    ctx.beginPath();\r\n    vertices.forEach( function( v ){\r\n\r\n        var cell_x = Math.round( norm( v[0], 0, _w ) * mx );\r\n        var cell_y = Math.round( norm( v[1], 0, _h ) * my );<\/pre>\n<p>having a rectangular grid helps a lot when it comes to finding which is the closest lattice.<\/p>\n<p>for instance cell_x &amp; cell_y can tell us which is the closest lattice without the usual minimum distance computation.<\/p>\n<p>the illustration below show what the\u00a0code above correspond to:<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"aligncenter size-full wp-image-925\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2016\/11\/equilateral_2.png\" alt=\"equilateral_2\" width=\"862\" height=\"927\" srcset=\"https:\/\/barradeau.com\/blog\/wp-content\/uploads\/2016\/11\/equilateral_2.png 862w, https:\/\/barradeau.com\/blog\/wp-content\/uploads\/2016\/11\/equilateral_2-279x300.png 279w, https:\/\/barradeau.com\/blog\/wp-content\/uploads\/2016\/11\/equilateral_2-768x826.png 768w\" sizes=\"(max-width: 862px) 100vw, 862px\" \/><\/p>\n<p>once we found which celle the vertex belongs to, \u00a0we can iterate only on the neighbour cells to find the closests valid lattices. that&#8217;s why the loop ranges from <em>cell_x-2 <\/em>to<em> cell_x+2<\/em> &amp; <em>cell_y-2 <\/em>to<em> cell_y+2. <\/em>this saves a lot of computations.<\/p>\n<pre class=\"lang:js decode:true\">        var md = Number.POSITIVE_INFINITY, d, x, y, ix, iy, ps = [];\r\n\r\n        for( var i = cell_x - 2; i &lt; cell_x + 2; i++ ){\r\n\r\n            for( var j = cell_y - 2; j &lt; cell_y + 2; j++ ){\r\n\r\n                if(( Math.abs( i ) % 2 == 1 &amp;&amp; Math.abs( j ) % 2 == 0 )\r\n                || ( Math.abs( i ) % 2 == 0 &amp;&amp; Math.abs( j ) % 2 == 1 ) ){\r\n\r\n                    \/\/ here we found a valid lattice in the cells surrounding our point, \r\n                    \/\/ we can check the lattice-vertex distance and store it in a temporary array (ps).\r\n\r\n                    ix = ( i ) * l\/2;\r\n                    iy = ( j ) * h;\r\n\r\n                    d = squareDistance( [ix,iy], v );\r\n                    if( d &lt; md ){\r\n                        md = d;\r\n                        x = ( i ) * l\/2;\r\n                        y = ( j ) * h;\r\n                        ps.unshift( x, y );\r\n                    }\r\n                }\r\n            }\r\n        }\r\n\r\n        \/\/now we have what we need to render the vertex.\r\n        \/\/50% chance to draw a lattice-vertex line\r\n\r\n        if( PRNG.random() &gt; .5 ){\r\n            ctx.moveTo( v[0], v[1] );\r\n            ctx.lineTo( ps[0], ps[1] );\r\n        }else{\r\n            \r\n            \/\/50% chance to draw the closest edge to the vertex\r\n\r\n            ctx.moveTo( ps[0], ps[1] );\r\n            ctx.lineTo( ps[2], ps[3] );\r\n            \r\n            \/\/and 5% of 50% chance to draw a filled triangle\r\n\r\n            if( PRNG.random() &gt; .95 ){\r\n                fills.push( ps );\r\n            }\r\n        }\r\n\r\n    } );\r\n    ctx.stroke();\r\n\r\n    \/\/we draw all the filled triangles at once\r\n\r\n    ctx.beginPath();\r\n    ctx.fillStyle = \"#FFF\";\r\n    fills.forEach( function(ps){\r\n        ctx.moveTo( ps[0], ps[1] );\r\n        ctx.lineTo( ps[2], ps[3] );\r\n        ctx.lineTo( ps[4], ps[5] );\r\n        ctx.lineTo( ps[0], ps[1] );\r\n    });\r\n    ctx.fill();\r\n}<\/pre>\n<p>the important thing to remember is that there is no random but <strong>Pseudo random <\/strong>and time. Since it&#8217;s always the same sequence of random numbers, the &#8216;random&#8217; chances of drawing, an edge or a triangle are always the same\u00a0; it doesn&#8217;t flicker like it would if we had used a regular Random function.<\/p>\n<p>and that&#8217;s it! :)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>this is a reply to @upupzealot asking for more details about this pen. there is no random so to speak, the PRNG (Pseudo Random Number Generator) creates a seed-based (&amp; therefore reproductible) series of seemingly random numbers. the first thing I do, line 1 is to create a self contained PRNG object (it&#8217;s a Mersenne &#8230; <span class=\"more\"><a class=\"more-link\" href=\"https:\/\/barradeau.com\/blog\/?p=921\">[Read more&#8230;]<\/a><\/span><\/p>\n","protected":false},"author":1,"featured_media":927,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"sharing_disabled":false,"spay_email":"","jetpack_publicize_message":""},"categories":[3],"tags":[],"jetpack_featured_media_url":"https:\/\/barradeau.com\/blog\/wp-content\/uploads\/2016\/11\/cover_triangles.png","jetpack_publicize_connections":[],"jetpack_shortlink":"https:\/\/wp.me\/p4oXhx-eR","_links":{"self":[{"href":"https:\/\/barradeau.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/921"}],"collection":[{"href":"https:\/\/barradeau.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/barradeau.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/barradeau.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/barradeau.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=921"}],"version-history":[{"count":6,"href":"https:\/\/barradeau.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/921\/revisions"}],"predecessor-version":[{"id":931,"href":"https:\/\/barradeau.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/921\/revisions\/931"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/barradeau.com\/blog\/index.php?rest_route=\/wp\/v2\/media\/927"}],"wp:attachment":[{"href":"https:\/\/barradeau.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=921"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/barradeau.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=921"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/barradeau.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=921"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}