<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":38,"date":"2014-03-01T17:49:04","date_gmt":"2014-03-01T17:49:04","guid":{"rendered":"http:\/\/barradeau.com\/blog\/?p=38"},"modified":"2020-03-29T09:47:52","modified_gmt":"2020-03-29T09:47:52","slug":"hydra","status":"publish","type":"post","link":"http:\/\/barradeau.com\/blog\/?p=38","title":{"rendered":"hydra"},"content":{"rendered":"<p>Hydra is a generative shadowplay.<br \/>\nyou can see it here <a href=\"http:\/\/barradeau.com\/2013\/hydra\/\">http:\/\/barradeau.com\/2013\/hydra\/<\/a><\/p>\n<p>I had the idea of doing this for a long time and being unemployed due to\u00a0<em>Flash&#8217;s death<\/em>, it turned out to be both a good way to learn HTML and the right time to do so.<\/p>\n<p>this article is about how it works, the problems I faced and how I solved them.<\/p>\n<p>here are some outputs of the engine<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-156\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/out_1.png\" alt=\"out_1\" width=\"960\" height=\"540\" srcset=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/out_1.png 960w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/out_1-300x168.png 300w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/out_1-700x393.png 700w\" sizes=\"(max-width: 960px) 100vw, 960px\" \/><\/p>\n<p>&nbsp;<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-157\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/out_2.png\" alt=\"out_2\" width=\"960\" height=\"540\" srcset=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/out_2.png 960w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/out_2-300x168.png 300w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/out_2-700x393.png 700w\" sizes=\"(max-width: 960px) 100vw, 960px\" \/><\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-158\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/out_3.png\" alt=\"out_3\" width=\"960\" height=\"540\" srcset=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/out_3.png 960w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/out_3-300x168.png 300w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/out_3-700x393.png 700w\" sizes=\"(max-width: 960px) 100vw, 960px\" \/><\/p>\n<p>&nbsp;<\/p>\n<blockquote><p>the algorithm<\/p><\/blockquote>\n<p>I wanted to keep things as simple as possible ; ideally a child should be able to figure out how it works and get an interesting result. or&#8230;\u00a0well&#8230;\u00a0something.<\/p>\n<p>the algorithm is therefore fairly simple<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-75\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/principe.png\" alt=\"principe\" width=\"722\" height=\"437\" srcset=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/principe.png 722w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/principe-300x181.png 300w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/principe-700x423.png 700w\" sizes=\"(max-width: 722px) 100vw, 722px\" \/><\/p>\n<ol>\n<li>select a random polygon from a library<\/li>\n<li>start a stroke on mouseDown<\/li>\n<li>slice up the polygon on mouseUp<\/li>\n<li>pick one of the slices on mouseDown\u00a0(red)<\/li>\n<li>shrink the selected slice (red)<\/li>\n<li>compute a random slice on a random polygon\u00a0(blue bottom)<\/li>\n<li>align the random slice it to the stroke (blue top)<\/li>\n<li>grow the new slice\u00a0(blue top)<\/li>\n<li>merge the new polygon with the previous<\/li>\n<\/ol>\n<blockquote><p>1\u00a0select a random polygon from a library<\/p><\/blockquote>\n<p>the first step was probably the easiest, I used the Flash IDE to turn Fonts outline into vector shapes. I used a rather unsophisticated <a href=\"http:\/\/ericlin2.tripod.com\/bugwire\/bugwiret.html\">JSFL by Eric Lin<\/a><br \/>\nanother option is to create a custom font and use the <a href=\"http:\/\/typeface.neocracy.org\/fonts.html\">typeface.js<\/a>\u00a0generator to convert it to a JSON file describing each character as a series of vectors.<\/p>\n<p>this is a list of the fonts I used:<\/p>\n<ul>\n<li><a href=\"http:\/\/www.dafont.com\/fr\/zoologic.font\">http:\/\/www.dafont.com\/fr\/animals.font<\/a><\/li>\n<li><a href=\"http:\/\/www.dafont.com\/fr\/ding-o-saurs.font\">http:\/\/www.dafont.com\/fr\/ding-o-saurs.font<\/a><\/li>\n<li><a href=\"http:\/\/www.dafont.com\/fr\/heroez.font\">http:\/\/www.dafont.com\/fr\/heroez.font<\/a><\/li>\n<li><a href=\"http:\/\/www.dafont.com\/fr\/the-beetles.font\">http:\/\/www.dafont.com\/fr\/the-beetles.font<\/a><\/li>\n<li><a href=\"http:\/\/www.dafont.com\/tool.font\">http:\/\/www.dafont.com\/tool.font<\/a><\/li>\n<li><a href=\"http:\/\/www.dafont.com\/toolz-tfb.font\">http:\/\/www.dafont.com\/toolz-tfb.font<\/a><\/li>\n<li><a href=\"http:\/\/www.dafont.com\/fr\/zoologic.font\">http:\/\/www.dafont.com\/fr\/zoologic.font<\/a><\/li>\n<\/ul>\n<p>additionally, I&#8217;ve used <a href=\"http:\/\/www.dafont.com\/fr\/le-monde-de-victor.font\">le monde de Victor<\/a>\u00a0to perform tests, this is the one used in the videos below. the final library contains 101 shapes.<\/p>\n<p>once we have the path of each polygon, drawing them to the Canvas is trivial so I won&#8217;t cover this but you can refer to the\u00a0<a href=\"http:\/\/www.w3.org\/TR\/2dcontext\/\">W3C specification<\/a>\u00a0and ask internet for tutorials.<\/p>\n<p>one key concept here is the <em>interpolation (<\/em>aka<em> lerp <\/em>or<em> lrp)\u00a0<\/em>; the fact of going from a value A to a value B over time. it is used later to inflate\/deflate the shapes, it is the most widely used animation technique. the minimal example would go like<\/p>\n<pre class=\"prettyprint linenums\">\/\/the linear interpolation method\r\nfunction lerp( time, a, b )\r\n{\r\n  return a + ( b - a ) * time;\r\n}\r\n\/\/print the result of a linear interpolation between 0 and 1 in the console\r\nsetInterval( function()\r\n{\r\n    console.clear();\r\n    var time = .5 + ( Math.sin( Date.now() * 0.001 ) * .5 );\r\n    console.log( lerp( time, 0, 1 ) ); \r\n}, 1000 \/ 60 );<\/pre>\n<p>this should log a value that oscillates between 0 and 1.<\/p>\n<p>here is a graphic extension of the above on the X and Y axes:<\/p>\n<div id=\"lerpSample\" style=\"width: 100%; height: 400px;\"><\/div>\n<p>this is an essential concept to understand for anyone willing to animate something on a screen. in the above example, the X coordinate is bound to a lerp and the the Y coordinate as well as the radius of the disc is bound to another lerp (another time value).<\/p>\n<blockquote><p>2 start a stroke on mouseDown<\/p><\/blockquote>\n<p>I was wondering how to create a dashed stroke and found <a href=\"http:\/\/www.rgraph.net\/blog\/2013\/january\/html5-canvas-dashed-lines.html\">this a<\/a>rticle.\u00a0as it&#8217;s not supported in all browsers, the trick is to create a fallback method on the context like so:<\/p>\n<pre class=\"prettyprint linenums\">if (!context.setLineDash) {\r\n    context.setLineDash = function () {}\r\n}<\/pre>\n<p>then to get it to move, we&#8217;ll need to store a &#8220;dashOffset&#8221; value somewhere and say<\/p>\n<pre class=\"prettyprint linenums\">context.lineDashOffset = dashOffset;\r\ndashOffset += speed;\/\/ : int<\/pre>\n<p>the rest of <a href=\"http:\/\/www.rgraph.net\/blog\/2013\/january\/html5-canvas-dashed-lines.html\">the article<\/a> is pretty clear, it&#8217;s worth mentioning that the method is now properly supported by Chrome, FF, IE and Opera.<br \/>\non a side note, I tried using <a href=\"http:\/\/eightmedia.github.io\/hammer.js\/\">Hammer.js<\/a>\u00a0to handle gestures and it caused some spectacular crashes on iPad so I simply bound the <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/Guide\/Events\/Touch_events\">touch events<\/a>\u00a0to the mouse events handlers and it did the thing.<\/p>\n<p>as I used rounded coordinates\u00a0(read below), I needed to <em>inflate<\/em> the slice axis a bit before the clipping operation so\u00a0here&#8217;s an implementation of the dashed line &amp; a line extrusion:<\/p>\n<div id=\"dashedSample\" style=\"width: 100%; height: 400px;\"><\/div>\n<blockquote><p>3 slice up the polygon on mouseUp<\/p><\/blockquote>\n<p>I knew this would be the hardest part,\u00a0mostly because it&#8217;s impossible to foresee where the polygon will be cut so it would have to work in all sorts of degenerate cases.\u00a0it means that we might end up dealing with concave polygons, complex polygons and self-intersecting polygons which are tricky cases to deal with.<\/p>\n<p>after failing badly at handling simple polygons &amp; degenerate cases, I saw this <a href=\"http:\/\/polyk.ivank.net\/?p=demos&amp;d=slice\">DEMO<\/a>\u00a0and started a prototype using the <a href=\"http:\/\/polyk.ivank.net\/\">POLYK lib<\/a>. unfortunately the\u00a0lib <em>only <\/em>handles simple polygons. still, it&#8217;s handy &amp;\u00a0I would recommend it for smaller projects that don&#8217;t require intense polygon action.<\/p>\n<p>then I searched a bit more and found\u00a0<a href=\"http:\/\/sourceforge.net\/projects\/jsclipper\/?source=directory\">Javascript Clipper<\/a>\u00a0a port of a C++ library.\u00a0it is extremely robust, rather fast (even in JS) &amp; apart for the use of capital .X \/ .Y, I found nothing to frown upon so I ended up using it. here&#8217;s a live <a href=\"http:\/\/jsclipper.sourceforge.net\/6.1.3.2\/main_demo.html\">DEMO<\/a>\u00a0to see for yourself.<\/p>\n<p>technically, I&#8217;m using IntPoints to spare some computations. when the user slices a polygon, the segment is extruded to create a Quad and I perform an XOR operation with Clipper where the subject is the current polygon and the clip is the newly created Quad.<\/p>\n<p>a<span style=\"line-height: 1.5;\">fter some time, this part was working pretty nicely but the mayhem was far from over.<\/span><\/p>\n<blockquote><p>4 pick one of the slices on mouseDown<\/p><\/blockquote>\n<p>to know which polygon is clicked, I needed a <em>contains<\/em> method. there are different approaches to solve this, the one I used so far was the one described by Paul Bourke <a href=\"http:\/\/paulbourke.net\/geometry\/polygonmesh\/\">here<\/a> ( <a href=\"http:\/\/paulbourke.net\/geometry\/polygonmesh\/InsidePolygonWithBounds.cpp\">code here<\/a> ). it appeared to be rather slow &amp; after some research I found <a href=\"http:\/\/jsfromhell.com\/math\/is-point-in-poly\">another one here<\/a> that&#8217;s way more compact and worked just as fine:<\/p>\n<pre class=\"prettyprint linenums\">function contains( poly, x, y )\r\n{\r\n    var c = false,\r\n        l = poly.length,\r\n        j = l - 1;\r\n\r\n    for( var i = -1; ++i &lt; l; j = i)\r\n    {\r\n        (   ( poly[ i ].y &lt;= y &amp;&amp; y &lt; poly[ j ].y ) \r\n        ||  ( poly[ j ].y &lt;= y &amp;&amp; y &lt; poly[ i ].y ) )\r\n        &amp;&amp;  ( x &lt; ( poly[ j ].x - poly[ i ].x ) * ( y - poly[ i ].y ) \/ ( poly[ j ].y - poly[ i ].y ) + poly[ i ].x )\r\n        &amp;&amp;  ( c = !c);\r\n    }\r\n    return c;\r\n}<\/pre>\n<p>where <em>poly<\/em> is an array of points &amp; <em>C<\/em> is a Boolean indicating whether or not the mouse is inside the polygon. it&#8217;s quite cryptic yet it works with <em>convex<\/em>, <em>concave<\/em> &amp; <em>(self-) intersecting<\/em> polygons. in my case there was non need to handle <em>complex polygons<\/em> so I went with it. when the user clicks on a polygon, I test every shape and if one of them contains the mouse Position, it shrinks.\u00a0later I&#8217;ve added the double click to reset the original polygon, this doesn&#8217;t use the contains test.<\/p>\n<p>here&#8217;s an example of this in action<\/p>\n<div id=\"containsSample\" style=\"width: 100%; height: 400px;\"><\/div>\n<p>additionally I had to build a graph of the sliced up pieces ; if 2 pieces share a collinear edge, they&#8217;re connected. only the pieces that have exactly one connection are candidates for a click.<br \/>\nimagine a &#8220;U&#8221; shape and slice it horizontally, the 2 upper legs are valid candidates but the bottom piece can&#8217;t be selected.<\/p>\n<blockquote><p>5 shrink the selected slice<\/p><\/blockquote>\n<p><span style=\"line-height: 1.5;\">I had some very <\/span><em style=\"line-height: 1.5;\">organic<\/em><span style=\"line-height: 1.5;\"> &#8211; as in<\/span><em style=\"line-height: 1.5;\"> organic matter<\/em><span style=\"line-height: 1.5;\"> &#8211; yet very <\/span><em style=\"line-height: 1.5;\">mechanic<\/em><span style=\"line-height: 1.5;\"> motion\u00a0in mind. the best example would be the insects&#8217; motion as they stand somewhere between the animal and the machine. on a side note, insects have developed incredibly sophisticated mechanisms to accomplish all kinds of tasks ; if you&#8217;re interested in this, I&#8217;d recommend searching about <\/span><a style=\"line-height: 1.5;\" href=\"http:\/\/en.wikipedia.org\/wiki\/Biomimicry\">Biomimicry<\/a><span style=\"line-height: 1.5;\">.<\/span><\/p>\n<p>for the sake of documenting , here&#8217;s what I usually go through when I&#8217;m after an animation principle\u00a0(grow\/shrink in this case).\u00a0I tried them all but none of them made it to the final app.<\/p>\n<p><a href=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/expand_0.png\" data-rel=\"lightbox-image-0\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/expand_0.png\" alt=\"expand_0\" width=\"550\" height=\"457\" \/><\/a><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/expand_1.png\" alt=\"expand_1\" width=\"592\" height=\"585\" \/><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"line-height: 1.5;\">I tried to collapse all the shape&#8217;s points to the polygon&#8217;s centroid.\u00a0<\/span><span style=\"line-height: 1.5;\">then I tried to use a set of &#8220;springs&#8221; that would shorten progressively ; after a while, any shape would turn into a straight line (the slice axis) from which I would grow a new shape.\u00a0I also tried to get the points to follow the shape&#8217;s path, fail.\u00a0then I thought about using the polygon&#8217;s convex hull and projecting points onto it&#8230;<\/span><\/p>\n<p><span style=\"line-height: 1.5;\">in practice, everything caused the shape to look ugly because it overlooked the <strong><em>morphology<\/em><\/strong> of the polygon ; it was too mechanical. here&#8217;s where failing is good ; after all this, I could put a name on what\u00a0<\/span>I wanted and this name was a\u00a0<em><strong>morphological skeleton.<\/strong><\/em><\/p>\n<p>it appears that I did this <a href=\"http:\/\/en.nicoptere.net\/?p=381\">Binary Skeletonization<\/a> algorithm some years ago. it retrieves a structure (the medial axis) that gives a rough &#8220;skeleton&#8221; of a binary (black and white) image.\u00a0First I tried to compute a geometric medial axis and failed miserably, I took a series of snapshots, never to forget<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-145\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/mat_0.png\" alt=\"mat_0\" width=\"960\" height=\"540\" srcset=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/mat_0.png 960w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/mat_0-300x168.png 300w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/mat_0-700x393.png 700w\" sizes=\"(max-width: 960px) 100vw, 960px\" \/><\/p>\n<p>this was a good start, finding the bisectors was relatively easy but then&#8230;<img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-146\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/mat_1.png\" alt=\"mat_1\" width=\"960\" height=\"540\" srcset=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/mat_1.png 960w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/mat_1-300x168.png 300w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/mat_1-700x393.png 700w\" sizes=\"(max-width: 960px) 100vw, 960px\" \/>extruding the edges went<img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-147\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/mat_2.png\" alt=\"mat_2\" width=\"960\" height=\"540\" srcset=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/mat_2.png 960w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/mat_2-300x168.png 300w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/mat_2-700x393.png 700w\" sizes=\"(max-width: 960px) 100vw, 960px\" \/><a href=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/mat_2.png\" data-rel=\"lightbox-image-1\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><br \/>\n<\/a>really<br \/>\n<img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-148\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/mat_3.png\" alt=\"mat_3\" width=\"960\" height=\"540\" srcset=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/mat_3.png 960w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/mat_3-300x168.png 300w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/mat_3-700x393.png 700w\" sizes=\"(max-width: 960px) 100vw, 960px\" \/>wrong.<a href=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/mat_3.png\" data-rel=\"lightbox-image-2\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><br \/>\n<\/a><\/p>\n<p>so I ported my AS class to Javascript and added a brute force vectorization which gave me this.<br \/>\n<img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-149\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/mat_4.png\" alt=\"mat_4\" width=\"960\" height=\"540\" srcset=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/mat_4.png 960w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/mat_4-300x168.png 300w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/mat_4-700x393.png 700w\" sizes=\"(max-width: 960px) 100vw, 960px\" \/><\/p>\n<p>this was a debug view,\u00a0the final version has connected components.<\/p>\n<p><span style=\"line-height: 1.5;\">here&#8217;s a demo for you to play with (computationally intensive).<\/span><\/p>\n<div id=\"hilditchSample\" style=\"width: 100%; height: 500px;\"><\/div>\n<p><a href=\"https:\/\/www.barradeau.com\/js\/hydra\/Hilditch.js\">\u00a0the Hilditch class is here if you need it,<\/a>\u00a0here&#8217;s how to use it:<\/p>\n<p><!--?prettify linenums=true?--><\/p>\n<pre class=\"prettyprint linenums\">\/\/perform the skeletization\r\nvar skeleton= Hilditch.skeletize( sourceContext );\r\n\r\n\/\/render the pixels of the skeleton\r\ncontext.clear();\r\ncontext.fillStyle = \"#06C\";\r\nfor( var i = 0; i &lt; skeleton.length; i+= 2 )\r\n{\r\n\tcontext.fillRect( skeleton[ i ], skeleton[ i+1 ], 1, 1 );\r\n}<\/pre>\n<p>then I projected the points of the shape onto\u00a0the skeleton.\u00a0the result was much better than all the previous attempts. here&#8217;s a sample video.<\/p>\n<div class=\"embed-vimeo\" style=\"text-align: center;\"><iframe loading=\"lazy\" src=\"https:\/\/player.vimeo.com\/video\/79191928\" width=\"700\" height=\"394\" frameborder=\"0\" webkitallowfullscreen mozallowfullscreen allowfullscreen><\/iframe><\/div>\n<p>and here&#8217;s the what happens when chaining the transformation<\/p>\n<div class=\"embed-vimeo\" style=\"text-align: center;\"><iframe loading=\"lazy\" src=\"https:\/\/player.vimeo.com\/video\/82493158\" width=\"700\" height=\"394\" frameborder=\"0\" webkitallowfullscreen mozallowfullscreen allowfullscreen><\/iframe><\/div>\n<p>that was it!<br \/>\nI could shrink my shapes in a nice way. I kept the spring-based approach to reset the shape ; it works very well to <em>melt it down <\/em>(double click anywhere on the hydra page to see what it does).<\/p>\n<blockquote><p>6 compute a random slice on a random polygon<\/p><\/blockquote>\n<p>having solved the picking and slicing algorithms, I thought this part would be a piece of cake but\u00a0the difficulty here was to find <em>an <strong>automatic<\/strong> way to detect the <strong>interesting parts<\/strong> of a shape<\/em>.<\/p>\n<p>the brain is very good at reading the topology of objects. mentally, we do this all the time.\u00a0I&#8217;d recommend reading\u00a0<i><a href=\"http:\/\/www.oliversacks.com\/books\/man-who-mistook-his-wife\/\">The Man Who Mistook His Wife for a Hat (Oliver Sacks, 1985 )<\/a>\u00a0<\/i>if you&#8217;re interested in what happens when your brain stops reading the world properly.<\/p>\n<p>a computer\u00a0<span style=\"line-height: 1.5;\">on the other hand,<\/span><span style=\"line-height: 1.5;\">\u00a0<\/span><span style=\"line-height: 1.5;\">is a complete retard when it comes to this. rather, the notion of <\/span><em style=\"line-height: 1.5;\">topology<\/em><span style=\"line-height: 1.5;\"> is alien to a machine unless you help it a bit. when you have a set of objects that obey some construction rules (a <em>formal grammar<\/em>), it&#8217;s easier to isolate those rules and imagine an algorithm that will handle them. \u00a0in this case, the shapes&#8217; library was very varied which prevented me from taking shortcuts.\u00a0I searched a way to quantify the polygons &amp; stumbled upon the <a href=\"http:\/\/en.wikipedia.org\/wiki\/K-means_clustering\">K-Means Clustering<\/a>.<\/span><\/p>\n<p>in a nutshell, a polygon being a set of 2d points, the K-Means will try to find a given amount of points &#8220;clusters&#8221; that <em>work together<\/em>\u00a0(that have a\u00a0minimal sum of least squares). the only constraint here is that we must specify the number of clusters ; I chose to have 3 sites which gave me 6 different slice axes per shape.<\/p>\n<p>here&#8217;s a video of the K-Means clustering in action<\/p>\n<div class=\"embed-vimeo\" style=\"text-align: center;\"><iframe loading=\"lazy\" src=\"https:\/\/player.vimeo.com\/video\/79191927\" width=\"700\" height=\"394\" frameborder=\"0\" webkitallowfullscreen mozallowfullscreen allowfullscreen><\/iframe><\/div>\n<p>it&#8217;s important to note that it&#8217;s an emerging process ; it takes a number of iterations to produce stable clusters. you can see the emerging\u00a0process as the clusters move around to find their final position. it allowed me <em>preprocess<\/em> all the polygons of the library and isolate slicing axes along which I could cut any polygon before stitching it back to the current shape.<\/p>\n<p>after some research I found an <em>improved<\/em> version of the K-Means which is called <a href=\"http:\/\/en.wikipedia.org\/wiki\/Expectation%E2%80%93maximization_algorithm\">Expectation Maximization Clustering <\/a>and a <a href=\"http:\/\/jormungand.net\/projects\/misc\/em\/\">javascript implementation by Chris Jormungand<\/a>. I used the Oriented Bounding Box of the ellipse and selected the edge that was the closest to the shape&#8217;s centroid (the red and green dots in the picture below).<\/p>\n<p><a href=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/em_clustering.png\" data-rel=\"lightbox-image-3\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-144\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/em_clustering.png\" alt=\"em_clustering\" width=\"717\" height=\"716\" srcset=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/em_clustering.png 717w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/em_clustering-150x150.png 150w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/em_clustering-300x300.png 300w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/em_clustering-360x360.png 360w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/em_clustering-700x699.png 700w\" sizes=\"(max-width: 717px) 100vw, 717px\" \/><\/a><br \/>\n<em>the slice axes found with the EM clustering algorithm<\/em><\/p>\n<blockquote><p>7 align the random slice\u00a0to the stroke<\/p><\/blockquote>\n<p>we have a stroke and a new slice to stick to it but it&#8217;s not over yet ; for it to work, we need to align the new slice to the slice axis. there&#8217;s no rocket science in there yet I went through a lot of trial error. here&#8217;s a time lapse of me doing the alignment:<\/p>\n<div class=\"embed-vimeo\" style=\"text-align: center;\"><iframe loading=\"lazy\" src=\"https:\/\/player.vimeo.com\/video\/82493384\" width=\"700\" height=\"394\" frameborder=\"0\" webkitallowfullscreen mozallowfullscreen allowfullscreen><\/iframe><\/div>\n<p>when you see the red rabbit, I&#8217;m almost done. below is a clearer view of what happens ; left: pick a random slice, right: align it to an arbitrary axis.<\/p>\n<p><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-151\" src=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/align.png\" alt=\"align\" width=\"960\" height=\"540\" srcset=\"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/align.png 960w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/align-300x168.png 300w, http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/align-700x393.png 700w\" sizes=\"(max-width: 960px) 100vw, 960px\" \/><\/p>\n<blockquote><p>8 grow the new slice<\/p><\/blockquote>\n<p>this uses the same algorithm as the shrinking.<br \/>\nas it&#8217;s a linear interpolation, <em>rewinding<\/em> is fairly easy.<\/p>\n<blockquote><p>9 merge the new polygon with the previous<\/p><\/blockquote>\n<p>like slicing, merging is a complex operation so I let\u00a0the ClipperLib handle it, recursively adding all the parts using a UNION operation.<br \/>\nand we&#8217;re done!<\/p>\n<blockquote><p>some extras<\/p><\/blockquote>\n<p>there is some sound when the user cuts the shape and when it shrinks &amp; grows. I used <a href=\"http:\/\/goldfirestudios.com\/blog\/104\/howler.js-Modern-Web-Audio-Javascript-Library\">Howler.js<\/a> to handle this. it is supported erratically among browsers but on desktops at least it was ok-ish.\u00a0I wanted some concrete sounds, like paper being torn, I found some quality items on <a href=\"http:\/\/www.freesound.org\/people\/stereostereo\/sounds\/124527\/\">freesound<\/a>.<\/p>\n<p>there is also some blur to mimic a flickering, for now it&#8217;s only supported by webkit. tried using the <a href=\"http:\/\/docs.webplatform.org\/wiki\/svg\/tutorials\/smarter_svg_filters\">SVG filters<\/a> too but the computation was disappointingly slow.<\/p>\n<p>on right-click, an option panel appears to let you save the hydra.\u00a0I wanted to have the possibility to save the hydra both as a picture and as a vector shape.\u00a0exporting a PNG was straightforward ; I render the polygon normally and use\u00a0<a href=\"https:\/\/github.com\/eligrey\/FileSaver.js\">FileSaver.js<\/a>\u00a0to save the canvas.<br \/>\nthe Vector format was a bit more complicated, first, which vector format? SVG would have been easy to encode but I wanted to be easily editable so I chose the PDF and used this lib <a href=\"http:\/\/parall.ax\/products\/jspdf\">jsPDF<\/a>.<\/p>\n<p>the lib works pretty well, one thing was puzzling though, when drawing something, it uses a <em>turtle<\/em>. so instead of passing it absolute points locations, you give it a starting point and a series of <em>deltas<\/em>\u00a0; the XY difference between the current point and the next.<\/p>\n<p>I also added a smoothing option which was a straight port of my old smoothing functions along with a Douglas-Peucker simplification method.<\/p>\n<div id=\"sism\" style=\"width: 100%; height: 500px;\"><\/div>\n<p>the classes are here:<\/p>\n<ul>\n<li><a href=\"https:\/\/www.barradeau.com\/js\/hydra\/CubicPath.js\">CubicPath<\/a><\/li>\n<li><a href=\"https:\/\/www.barradeau.com\/js\/hydra\/Simplify.js\">Simplify<\/a><\/li>\n<\/ul>\n<p>usage<\/p>\n<pre class=\"prettyprint linenums\">\/\/simplify path\r\nvar simple = Simplify.compute( points, 15 );\r\n\/\/smooth path\r\nvar cubic = new CubicPath();\r\nvar smooth = cubic.compute( simple, .1, false );<\/pre>\n<p>&amp; that&#8217;s it for the technique.<\/p>\n<blockquote><p>final note<\/p><\/blockquote>\n<p>it was my first HTML &#8220;app&#8221; and my first online art piece. I dare qualifying it as art \u00a0because it\u00a0serves no purpose other than\u00a0<em>being<\/em>, it\u00a0conveys an idea in a<em>\u00a0performative<\/em>\u00a0way\u00a0and I found nothing to add or remove from it.\u00a0there&#8217;s no\u00a0<em>manifesto<\/em>\u00a0so to speak.<br \/>\nfor me, shadows have a great evocative power &amp; I wanted to bring them to life.<\/p>\n<p style=\"visibility: hidden; display: none;\"><script src=\"https:\/\/www.barradeau.com\/js\/utils\/GeomUtils.js\" type=\"text\/javascript\"><\/script><script src=\"https:\/\/www.barradeau.com\/js\/utils\/Utils.js\" type=\"text\/javascript\"><\/script><script src=\"https:\/\/www.barradeau.com\/js\/utils\/CanvasUtils.js\" type=\"text\/javascript\"><\/script><script src=\"https:\/\/www.barradeau.com\/js\/utils\/ContextUtils.js\" type=\"text\/javascript\"><\/script><script src=\"https:\/\/www.barradeau.com\/js\/utils\/DomUtils.js\" type=\"text\/javascript\"><\/script><script type=\"text\/javascript\">\/\/ <![CDATA[\nvar updateMethods = [];\nvar mouseX = 0;\nvar mouseY = 0;\n        function updateLoop()\n        {\n            raf( updateLoop );\n            for( var i = 0; i < updateMethods.length; i++ )             {                 ( updateMethods[ i ] )();             }         }         updateLoop();         console.log( updateMethods );\n\/\/ ]]><\/script><br \/>\n<script src=\"https:\/\/www.barradeau.com\/js\/vendor\/hammer.min.js\" type=\"text\/javascript\"><\/script><br \/>\n<script src=\"https:\/\/www.barradeau.com\/js\/hydra\/LerpSample.js\" type=\"text\/javascript\"><\/script><br \/>\n<script src=\"https:\/\/www.barradeau.com\/js\/hydra\/PolyContains.js\" type=\"text\/javascript\"><\/script><script src=\"https:\/\/www.barradeau.com\/js\/hydra\/DashedSample.js\" type=\"text\/javascript\"><\/script><script src=\"https:\/\/www.barradeau.com\/js\/hydra\/Hilditch.js\" type=\"text\/javascript\"><\/script><script src=\"https:\/\/www.barradeau.com\/js\/hydra\/HilditchSample.js\" type=\"text\/javascript\"><\/script><script src=\"https:\/\/www.barradeau.com\/js\/hydra\/CubicPath.js\" type=\"text\/javascript\"><\/script><script src=\"https:\/\/www.barradeau.com\/js\/hydra\/Simplify.js\" type=\"text\/javascript\"><\/script><script src=\"https:\/\/www.barradeau.com\/js\/hydra\/SimplifySmooth.js\" type=\"text\/javascript\"><\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hydra is a generative shadowplay. you can see it here http:\/\/barradeau.com\/2013\/hydra\/ I had the idea of doing this for a long time and being unemployed due to\u00a0Flash&#8217;s death, it turned out to be both a good way to learn HTML and the right time to do so. this article is about how it works, the &#8230; <span class=\"more\"><a class=\"more-link\" href=\"http:\/\/barradeau.com\/blog\/?p=38\">[Read more&#8230;]<\/a><\/span><\/p>\n","protected":false},"author":1,"featured_media":158,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"sharing_disabled":false,"spay_email":"","jetpack_publicize_message":""},"categories":[3],"tags":[2],"jetpack_featured_media_url":"http:\/\/barradeau.com\/blog\/wp-content\/uploads\/2014\/03\/out_3.png","jetpack_publicize_connections":[],"jetpack_shortlink":"https:\/\/wp.me\/s4oXhx-hydra","_links":{"self":[{"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/38"}],"collection":[{"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=38"}],"version-history":[{"count":127,"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/38\/revisions"}],"predecessor-version":[{"id":1202,"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/38\/revisions\/1202"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=\/wp\/v2\/media\/158"}],"wp:attachment":[{"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=38"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=38"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/barradeau.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=38"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}