-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlsystem2.html
179 lines (156 loc) · 6.04 KB
/
lsystem2.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
<!DOCTYPE html >
<!--
By Dave Lawrence on 16/3/2010
LSystem 2
http://proceduralgraphics.blogspost.com
-->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>LSystem</title>
<script type="text/javascript" src="util.js"></script>
<script type="text/javascript" src="lsystem.js"></script>
<script type="text/javascript">
var lsysTypes = {
'Plant with leaves': { axiom: 'S--X', angle: 0.436, rules: new Array('L->', 'X->FL-[[X]+X]+FL[+FLX]-X', 'F->FF'),
funcs: {
// Setup (from axiom, will just sit as the first letter)
'S': function(args) {
args.ctx.lineWidth = 2;
args.ctx.strokeStyle = '#644a35';
},
// Leaves
'L': function(args) {
args.ctx.fillStyle = '#00ff00';
args.ctx.beginPath();
args.ctx.arc(0, 0, 2, 0, 2 * Math.PI, true);
args.ctx.fill();
}
}
},
'Plant': { axiom: '--X', angle: 0.436, rules: new Array('X->F-[[X]+X]+F[+FX]-X', 'F->FF')},
'Koch Snowflake': { axiom: 'F--F--F', angle: Math.PI / 3, rules: new Array('F->F+F--F+F') },
'Serpinski Carpet': { axiom: 'F-F-F-F', angle: Math.PI / 2, rules: new Array('F->F[F]-F+F[--F]+F-F') },
'Serpinski Carpet (color)': {
axiom: 'F-F-F-F', angle: Math.PI / 2, rules: new Array('F->F[CF]-F+F[C--F]+F-F'),
// A 'C' is put inside each push '[' so color is changed according to depth
funcs: {
'C': function(args) {
var colors = ['#FFFFFF', '#39de60', '#fffc22', '#ff0000', '#0000FF'];
args.ctx.strokeStyle = colors[ Math.min(colors.length-1, args.depth) ];
}
}
},
'Serpinski Square': { axiom: 'F-F-F-F', angle: Math.PI / 2, rules: new Array('F->FF[-F-F-F]F') },
'Serpinski Triangle': { axiom: 'A', angle: Math.PI / 3, rules: new Array('A->B-A-B', 'B->A+B+A')},
'Serpinski Gasket': { axiom: 'F--F--F', angle: Math.PI / 3, rules: new Array('F->F--F--F--GG', 'G->GG') }
};
// All of the interesting l-sys drawing code is in lsystem.js, the code below is mostly boring HTML stuff
var width = window.innerWidth - 40;
var height = window.innerHeight * .7;
var DEFAULT_ITERATIONS = 4;
var ctx;
var selectLsys;
var input = {}; // convenience map that holds inputs
// write out canvas as we have to put width/height inline in the HTML, CSS will just scale pixels
document.write('<canvas id="canvas" width=' + width + ' height=' + height + '></canvas>');
function setup() {
ctx = document.getElementById("canvas").getContext("2d");
input = {
axiom: document.getElementById('axiom'),
rules: document.getElementById('rules'),
angle: document.getElementById('angle'),
iterations: document.getElementById('iterations')
};
selectLsys = document.getElementById('l-sys');
selectLsys.options.length = 0; // clear out existing items
for (var key in lsysTypes) {
selectLsys.options.add(new Option(key, key))
}
selectLsys.options[0].selected = true;
selectLsys.onchange = updateSelect;
input.iterations.value = DEFAULT_ITERATIONS;
document.getElementById('inc').onclick = function() { input.iterations.value++; };
document.getElementById('dec').onclick = function() { input.iterations.value--; };
document.getElementById('update').onclick = update;
updateSelect();
}
function updateSelect() {
var chosenOption= selectLsys.options[selectLsys.selectedIndex];
var l = lsysTypes[chosenOption.value];
input.axiom.value = l.axiom;
input.rules.value = l.rules.join(',');
input.angle.value = l.angle;
update();
}
function update() {
var l = {};
l.axiom = input.axiom.value;
l.rules = input.rules.value.split(',');
l.angle = input.angle.value;
// TODO: Make funcs editable
var chosenOption= selectLsys.options[selectLsys.selectedIndex];
l.funcs = lsysTypes[chosenOption.value].funcs;
draw(l);
}
function draw(l) {
ctx.save();
drawBackground();
ctx.translate(width/10, height/10); // hack margin, until I make proper alignment/zooming etc
ctx.strokeStyle = "#FFFFFF";
var lsys = new LSystem(l.axiom, l.rules);
var iterations = input.iterations.value;
var turtleInput = lsys.iterate(iterations);
var args = {};
args.ctx = ctx;
args.str = turtleInput;
args.distance = 5;
args.angle = l.angle;
args.angleVariance = 0.0;
args.iterations = iterations;
var handler = getDefaultLSystemHandler();
// Add extra drawing funcs
if (l.funcs) {
for (var f in l.funcs) {
handler[f] = l.funcs[f];
}
}
drawLSystem(args, handler);
ctx.restore();
}
function drawBackground() {
ctx.fillStyle = "#000000";
ctx.fillRect(0,0, width, height);
}
</script>
<style>
html,body { width:100%; height:100%; margin:0; overflow:hidden; }
body { padding:20px; }
table, tr { width: "100%"; }
th { font-weight: bold; }
td { text-align: center; border: 0px; padding: 5px; }
input#rules { width: 400px; }
input#angle { width: 40px; }
input#iterations { width: 30px; }
div#instructions { margin-top: 20px; }
div.heading { font-weight: bold; };
</style>
</head>
<body onload="setup()">
<div>
Select to load existing l-systems: <select id="l-sys"></select>
</div>
<div id="info">
<table>
<tr><th>Axiom</th><th>Rules</th><th>Angle</th><th>Iterations</th></tr>
<tr>
<td><input id="axiom" /></td>
<td><input id="rules" /></td>
<td><input id="angle" /></td>
<td><input id="dec" type="button" value="-" /><input id="iterations" /><input id="inc" type="button" value="+" /></td>
<td><input id="update" type="button" value="update" /></td>
</tr>
</table>
</div>
<div><A href="http://proceduralgraphics.blogspot.com">http://proceduralgraphics.blogspot.com</A></div>
</body>
</html>