{"id":1281,"date":"2018-01-04T16:07:23","date_gmt":"2018-01-04T21:07:23","guid":{"rendered":"http:\/\/bluegalaxy.info\/codewalk\/?p=1281"},"modified":"2021-01-17T20:20:40","modified_gmt":"2021-01-18T01:20:40","slug":"p5-js-build-menger-sponge","status":"publish","type":"post","link":"https:\/\/bluegalaxy.info\/codewalk\/2018\/01\/04\/p5-js-build-menger-sponge\/","title":{"rendered":"p5.js: How to build a Menger sponge"},"content":{"rendered":"<p>According to <a href=\"https:\/\/en.wikipedia.org\/wiki\/Menger_sponge\">Wikipedia<\/a>, a Menger sponge is:<\/p>\n<blockquote><p>In mathematics, the Menger sponge (also known as the Menger universal curve) is a fractal curve. It is a three-dimensional generalization of the Cantor set and Sierpinski carpet, though it is slightly different from a Sierpinski sponge. It was first described by Karl Menger in 1926, in his studies of the concept of topological dimension.<\/p><\/blockquote>\n<p>A Menger sponge is essentially a block that is recursively subdivided into smaller blocks where the central block on each side is removed. Here is an animation showing what the Menger sponge looks like after four iterations:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-1282 size-full\" src=\"http:\/\/bluegalaxy.info\/codewalk\/wp-content\/uploads\/2018\/01\/Mengersponge.gif\" alt=\"\" width=\"360\" height=\"391\" \/><\/p>\n<p>This code uses a class called Box to create the boxes and it has constructor(), generate(), and show() functions. The constructor uses the p5.js <code class=\"EnlighterJSRAW\" data-enlighter-language=\"no-highlight\">createVector(x, y, z)<\/code> method.<\/p>\n<p>According to the <a href=\"https:\/\/p5js.org\/reference\/#\/p5\/createVector\">p5js.org reference page<\/a>, createVector():<\/p>\n<blockquote><p><span class=\"description-text\">Creates a new p5.Vector (the datatype for storing vectors). This provides a two or three dimensional vector, specifically a Euclidean (also known as geometric) vector. A vector is an entity that has both magnitude and direction.<\/span><\/p>\n<p>createVector(x, y, z)<code class=\" language-javascript\"><\/code><\/p><\/blockquote>\n<p>The generate() function uses nested for loops to create all of the sub boxes, stored in an array.<\/p>\n<p>There is a mousePressed() function (the name of the function also happens to be a built-in for the mousePressed event, which means the function is triggered when the mouse is pressed!) which uses the generate() function to further sub-divide the box and create new boxes recursively.<\/p>\n<p>Here is the complete p5.js code for creating this:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\">var a = 0;\nvar sponge = [];\n\nclass Box {\n  constructor(x, y, z, r) {\n    this.pos = createVector(x, y, z);\n    this.r = r;\n  }\n\n  generate() {\n    var boxes = [];\n    for (var x = -1; x &lt; 2; x++) {\n      for (var y = -1; y &lt; 2; y++) {\n        for (var z = -1; z &lt; 2; z++) {\n          var sum = abs(x) + abs(y) + abs(z);\n          var newR = this.r \/ 3;\n          if (sum &gt; 1) {\n            var b = new Box(this.pos.x + x * newR, this.pos.y + y * newR, this.pos.z + z * newR, newR);\n            boxes.push(b);\n          }\n        }\n      }\n    }\n    return boxes;\n  }\n\n  show() {\n    push();\n    translate(this.pos.x, this.pos.y, this.pos.z);\n    stroke(255);\n    noStroke();\n    noFill();\n    fill(\"#00ff00\");\n    pointLight(255, width\/2, height\/2, 0);\n    box(this.r);\n    pop();\n  }\n}\n\nfunction setup() { \n  createCanvas(400, 400, WEBGL);\n  \n  \/\/ An array of Box objects\n  \/\/ Start with one\n  var b = new Box(0, 0, 0, 200);\n  sponge.push(b);\n} \n\nfunction mousePressed() {\n  \/\/ Generate the next set of boxes\n  var next = [];\n  for (var i = 0; i &lt; sponge.length; i++) {\n    var b = sponge[i];\n    var newBoxes = b.generate();\n    next = next.concat(newBoxes);\n  }\n  sponge = next;\n}\n\nfunction draw() { \n  background(51);\n  rotateX(a);\n  rotateY(a * 0.4);\n  rotateZ(a * 0.1);\n  \n  for (var i = 0; i &lt; sponge.length; i++) {\n    sponge[i].show();    \n  }\n  \n  a += 0.01;\n}<\/pre>\n<p>Here is what the final result looks like: (Click the box only twice. Otherwise it will slow to a crawl.)<\/p>\n\n<!-- iframe plugin v.5.2 wordpress.org\/plugins\/iframe\/ -->\n<iframe loading=\"lazy\" src=\"https:\/\/bluegalaxy.info\/processing\/p5\/menger_sponge\/\" scrolling=\"no\" width=\"400\" height=\"400\" id=\"iframe_drop_shadow\" name=\"menger_sponge\" class=\"iframe-class\" frameborder=\"0\"><\/iframe>\n\n<p><button class=\"btn\">Start Over<\/button><\/p>\n<p><script language=\"JavaScript\"><br \/>\n    function refreshIframe(name) {<br \/>\n        var ifr = document.getElementsByName(name)[0];<br \/>\n        ifr.src = ifr.src;<br \/>\n    }<br \/>\n<\/script><\/p>\n<p>The code in this article is based on The Coding Train \u2013 &#8220;<a href=\"https:\/\/www.youtube.com\/watch?v=LG8ZK-rRkXo&amp;t=3s\">Coding Challenge #2: Menger Sponge Fractal&#8221;<\/a>. This video was coded by Daniel Shiffman in Processing. As I followed along, I translated it into p5.js. Then I double checked my code against the <a href=\"https:\/\/github.com\/CodingTrain\/Rainbow-Code\/tree\/master\/CodingChallenges\/CC_02_MengerSponge_p5.js\">p5.js code<\/a> that was posted on github. My code does have some small differences.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>According to Wikipedia, a Menger sponge is: In mathematics, the Menger sponge (also known as the Menger universal curve) is a fractal curve. It is a three-dimensional generalization of the Cantor set and Sierpinski carpet, though it is slightly different from a Sierpinski sponge. It was first described by Karl Menger in 1926, in his &hellip; <a href=\"https:\/\/bluegalaxy.info\/codewalk\/2018\/01\/04\/p5-js-build-menger-sponge\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">p5.js: How to build a Menger sponge<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[47,35],"tags":[45,90,48],"class_list":["post-1281","post","type-post","status-publish","format-standard","hentry","category-p5-js","category-processing-language","tag-javascript","tag-mousepressed","tag-p5-js"],"_links":{"self":[{"href":"https:\/\/bluegalaxy.info\/codewalk\/wp-json\/wp\/v2\/posts\/1281","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bluegalaxy.info\/codewalk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bluegalaxy.info\/codewalk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bluegalaxy.info\/codewalk\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bluegalaxy.info\/codewalk\/wp-json\/wp\/v2\/comments?post=1281"}],"version-history":[{"count":11,"href":"https:\/\/bluegalaxy.info\/codewalk\/wp-json\/wp\/v2\/posts\/1281\/revisions"}],"predecessor-version":[{"id":3327,"href":"https:\/\/bluegalaxy.info\/codewalk\/wp-json\/wp\/v2\/posts\/1281\/revisions\/3327"}],"wp:attachment":[{"href":"https:\/\/bluegalaxy.info\/codewalk\/wp-json\/wp\/v2\/media?parent=1281"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bluegalaxy.info\/codewalk\/wp-json\/wp\/v2\/categories?post=1281"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bluegalaxy.info\/codewalk\/wp-json\/wp\/v2\/tags?post=1281"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}