diff options
Diffstat (limited to 'lsys')
| -rw-r--r-- | lsys/README.md | 3 | ||||
| -rw-r--r-- | lsys/app.js | 60 | ||||
| -rw-r--r-- | lsys/index.html | 50 | ||||
| -rw-r--r-- | lsys/lsystem.js | 172 |
4 files changed, 285 insertions, 0 deletions
diff --git a/lsys/README.md b/lsys/README.md new file mode 100644 index 0000000..b8b2535 --- /dev/null +++ b/lsys/README.md @@ -0,0 +1,3 @@ +## L-system generator + +Plug in values and see what you get. You can click "Save Image" to generate a PNG for downloading (at least in Chrome -- I haven't tested it in other browsers). diff --git a/lsys/app.js b/lsys/app.js new file mode 100644 index 0000000..3c5e696 --- /dev/null +++ b/lsys/app.js @@ -0,0 +1,60 @@ +/* Based on http://www.robotacid.com/PBeta/LSystem/index.html */ + +var lsystem = new LSystem(); + +var width = 1200; +var height = 600; + +var HALF_PI = 3.141592 / 2; + +function setup(axiom, ruleset, iterations) { + lsystem = new LSystem(axiom, ruleset); + lsystem.iterate(iterations); +} + +function saveImage() { + console.log("save"); + window.open(c.toDataURL()); +} + +function draw(x, y, axiom, ruleset, iterations, angle, zoom, drawtype) { + a.fillStyle = "#fff"; + a.fillRect(0, 0, width, height); + + var angle_radians = parseFloat(angle) * (Math.PI / 360); + + lsystem.draw(x, y, zoom, angle_radians, drawtype); + + a.fillStyle = "#666"; + a.fillRect(0, 0, width, 20); + a.fillStyle = "#fff"; + a.font = "bold 10px 'Lucida Grande', Helvetica"; + + var str = "axiom: " + axiom + " "; + str += "ruleset: " + ruleset + " "; + str += "angle: " + angle + "ยบ "; + str += "iterations: " + iterations + " "; + str += "zoom: " + zoom + " "; + str += "x: " + x + " "; + str += "y: " + y + " "; + str += "drawtype: " + drawtype; + a.fillText(str, 5, 13); +} + +function generate() { + var axiom = document.getElementById("axiom").value; + var ruleset = document.getElementById("ruleset").value; + var angle = document.getElementById("angle").value; + var iterations = document.getElementById("iterations").value; + var zoom = document.getElementById("zoom").value; + + var x = document.getElementById("x").value; + var y = document.getElementById("y").value; + + var drawtype = document.getElementById("drawtype").value; + + setup(axiom, ruleset, iterations); + draw(x, y, axiom, ruleset, iterations, angle, zoom, drawtype); +} + +generate(); diff --git a/lsys/index.html b/lsys/index.html new file mode 100644 index 0000000..7197b7f --- /dev/null +++ b/lsys/index.html @@ -0,0 +1,50 @@ +<!DOCTYPE html> +<html> + <head> + <title>L-System test</title> + <meta charset="utf-8" /> + <style type="text/css" media="screen"> + body { margin: 0; padding: 15px; border-top: solid 10px #000; } + canvas { border: solid 1px #999; } + #controls { font-family: "Lucida Grande", Helvetica, Arial, sans-serif; font-size: 11px; margin-bottom: 10px; } + #controls input[type="text"] { border: solid 1px #ccc; font-weight: bold; padding: 2px; font-size: 12px; width: 35px; margin-right: 10px; } + #controls input#axiom { width: 75px; } + #controls input#ruleset { width: 200px; } + </style> + </head> + <body> + <div id="controls"> + <form action="" onsubmit="generate(); return false;"> + Axiom: <input type="text" id="axiom" name="axiom" value="F" /> + Ruleset: <input type="text" id="ruleset" name="ruleset" value="F-F+FF-F-F+F" /> + Angle: <input type="text" id="angle" name="angle" value="200" /> + Iterations: <input type="text" id="iterations" name="iterations" value="4" /> + Zoom: <input type="text" id="zoom" name="zoom" value="10" /> + X: <input type="text" id="x" name="x" value="600" /> + Y: <input type="text" id="y" name="y" value="300" /> + + <select id="drawtype" name="drawtype" onchange="generate()"> + <option value="line">Line</option> + <option value="hollow_circle">Hollow Circle</option> + <option value="filled_circle">Filled Circle</option> + <option value="small_circles">Small Circles</option> + <option value="more_circles">More Circles</option> + <option value="faint">Faint</option> + <option value="triangles">Triangles</option> + <option value="hatch">Hatch</option> + </select> + + <input id="generateButton" type="submit" value="Generate" /> + <input id="saveButton" type="button" value="Download" onclick="saveImage()" /> + </form> + </div> + <canvas width="1200" height="600"></canvas> + + <script> + var c = document.getElementsByTagName('canvas')[0]; + var a = c.getContext('2d'); + </script> + <script type="text/javascript" charset="utf-8" src="lsystem.js"></script> + <script type="text/javascript" charset="utf-8" src="app.js"></script> + </body> +</html> diff --git a/lsys/lsystem.js b/lsys/lsystem.js new file mode 100644 index 0000000..c3896e5 --- /dev/null +++ b/lsys/lsystem.js @@ -0,0 +1,172 @@ +/* LSystem */ + +function LSystem(axiom, ruleset) { + this.alphabet = ['F', '+', '-', '[', ']']; + this.axiom = axiom; + this.rule = ["", "+", "-", "[", "]"]; + this.tree = ""; + + this.rule[0] = ruleset; + + this.draw = function(x, y, zoom, angle, drawtype) { + a.fillStyle = "#000"; + a.strokeStyle = "#000"; + + a.save(); + a.translate(x, y); + + var i; + + for (i=0; i<this.tree.length; i++) { + switch (this.tree.charAt(i)) { + case 'F': + switch (drawtype) { + case 'line': + a.beginPath(); + a.moveTo(0, 0); + a.lineTo(zoom, 0); + a.closePath(); + a.stroke(); + break; + case 'hollow_circle': + a.beginPath(); + a.arc(0, 0, zoom / 10, 0, Math.PI*2, true); + a.closePath(); + a.stroke(); + break; + case 'filled_circle': + a.beginPath(); + a.arc(0, 0, zoom / 10, 0, Math.PI*2, true); + a.closePath(); + a.fill(); + break; + case 'faint': + a.fillStyle = "rgba(0, 0, 0, " + (i / this.tree.length) + ")"; + a.beginPath(); + a.moveTo(Math.random() - .5, Math.random() - .5); + a.lineTo(Math.sin(zoom) + (zoom / 2), Math.random() - .5); + a.lineTo(zoom, 0); + a.closePath(); + a.fill(); + break; + case 'small_circles': + a.fillStyle = "rgba(0, 0, 0, " + (i / this.tree.length) + 0.2 + ")"; + a.beginPath(); + a.moveTo(Math.random() - .5, Math.random() - .5); + a.lineTo(Math.sin(zoom) + (zoom / 2), Math.random() - .5); + a.arc(Math.sin(zoom) + (zoom / 2), Math.random() - .5, zoom / 5, 0, Math.PI*2, true); + a.lineTo(zoom, 0); + a.closePath(); + a.fill(); + break; + case 'triangles': + a.fillStyle = "rgba(0, 0, 0, " + (i / this.tree.length) + ")"; + a.beginPath(); + + var dist = zoom / 2; + var halfdist = dist / 2; + a.moveTo(0, dist); + a.lineTo(halfdist, halfdist); + a.lineTo(dist, 0); + a.lineTo(halfdist, -halfdist); + a.lineTo(0, -dist); + a.closePath(); + a.fill(); + break; + case 'more_circles': + a.fillStyle = "rgba(0, 0, 0, " + Math.random() + ")"; + a.beginPath(); + a.arc(Math.random() + .5, Math.random() - .5, (i / this.tree.length) * 5, 0, Math.PI*2, true); + a.closePath(); + a.fill(); + + a.fillStyle = "rgba(0, 0, 0, " + Math.random() + ")"; + a.beginPath(); + a.arc(Math.random() - .5, Math.random() + .5, (i / this.tree.length) * 3, 0, Math.PI*2, true); + a.closePath(); + a.fill(); + + break; + case 'hatch': + var red = Math.random() * 255; + var green = Math.random() * 255; + var blue = Math.random() * 255; + a.strokeStyle = "rgba(" + red + ", " + green + ", " + blue + ", " + (i / this.tree.length) + ")"; + a.beginPath(); + + var dist = zoom / 2; + a.moveTo(-dist, -dist); + a.lineTo(dist, -dist); + a.moveTo(-dist, 0); + a.lineTo(dist, 0); + a.moveTo(-dist, dist); + a.lineTo(dist, dist); + a.closePath(); + a.stroke(); + break; + } + a.translate(zoom, 0); + break; + + case '+': + a.rotate(angle); + break; + + case '-': + a.rotate(-angle); + break; + + case '[': + a.save(); + break; + + case ']': + a.restore(); + break; + } + } + a.restore(); + } + + this.iterate = function(max_length) { + this.tree = this.axiom; + var rule_length = []; + var i; + + for (i=0; i<this.alphabet.length; i++) { + rule_length[i] = this.rule[i].length; + } + + for (i=0; i<max_length; i++) { + var new_length = 0; + var j; + + for (j=0; j<this.tree.length; j++) { + var c = this.tree.charAt(j); + var k; + + for (k=0; k<this.alphabet.length; k++) { + if (c == this.alphabet[k]) { + new_length += rule_length[k]; + break; + } + } + } + + var new_tree = []; + + for (j=0; j<this.tree.length; j++) { + var c = this.tree.charAt(j); + var k; + + for (k=0; k<this.alphabet.length; k++) { + if (c == this.alphabet[k]) { + new_tree.push(this.rule[k]); + break; + } + } + } + this.tree = new_tree.join(""); + } + } +} |
