Download code

From LiteratePrograms

Jump to: navigation, search

Back to Turtle_graphics_(JavaScript)

Download for Windows: single file, zip

Download for UNIX: single file, zip, tar.gz, tar.bz2

terrapin.htm

  1 <html><head>
  2 <title>a buggy concatenative turtle</title>
  3 <!-- 20070131 [DL] swap renamed flip.  improve tokenization -->
  4 <!-- 20060822 [DL] lame kludge for Opera 9.01 -->
  5 <!-- 20060820 [DL] written -->
  6 <script type="text/javascript"><!--
  7 function codevec(l)
  8 {
  9   var v = l.slice(0)
 10   v.sarg = function() { return checkarg(this.shift()) }
 11   v.varg = function() { return [].concat(this.sarg()) }
 12   v.call = function(l) {
 13 		for(var w = codevec(l); w.length; this.unshift(w.pop())); }
 14   return v
 15 }
 16 
 17 var plan = {}	// source tokens for user-defined words
 18 var user = {}	// functions for user-defined words
 19 var dict = {	// functions for system-defined words
 20 'pen':		function(ctx,v) { ctx.penState = !ctx.penState },
 21 'mirror':	function(ctx,v) { ctx.scale(1,-1) },
 22 'reverse':	function(ctx,v) { ctx.scale(-1,1) },
 23 'turn':		function(ctx,v) { ctx.rotate(v.sarg()*3.1415926/180) },
 24 'forward':	function(ctx,v) { ctx.translate(v.sarg(),0); ctx.displace() },
 25 'scale':	function(ctx,v) { 
 26 			var sc = v.sarg()
 27 			ctx.lineWidth /= sc
 28 			ctx.scale(sc,sc)
 29 				},
 30 'repeat':	function(ctx,v) { 
 31 			var n  = v.sarg()
 32 			var rv = v.varg()
 33 			if(n < 0)	{ n = -n; rv = invert(rv) }
 34 			while(n--)	{ interp(ctx, rv) }
 35 			/////////////////////
 36 			// if(n == 0)	return
 37 			// v.call(rv.concat(['repeat',n-1,rv]))
 38 			/////////////////////
 39 				},
 40 'poly':		function(ctx, v) {
 41 			var n  = v.sarg()
 42 			var a  = 360/(n<0?-n:n)
 43 			v.call(['repeat',n,v.varg().concat(['turn',a])]) },
 44 'def':		function(ctx,v) {
 45 			var name = v.shift()
 46 			plan[name] = v.varg()
 47 			user[name] = function(ctx,v) { v.call(plan[name]) }
 48 				},
 49 'inverse':	function(ctx,v)	{ v.call(invert(v.varg())) },
 50 'identity':	function(ctx,v) { v.call(       v.varg() ) },
 51 'under':	function(ctx,v) {
 52 			var av = v.varg()
 53 			var uv = v.varg()
 54 			v.call(av.concat(uv.concat(invert(av))))
 55 				},
 56 'within':	function(ctx,v)	{
 57 			var av = v.varg()
 58 			var wv = v.varg()
 59 			v.call(av.concat(wv.concat(av)))
 60 				},
 61 'flip':		function(ctx,v) {
 62 			var fn = v.sarg()
 63 			var bv = v.varg()
 64 			var av = v.varg()
 65 			v.call([fn,av,bv])
 66 				},
 67 '':		ignore
 68 
 69 }
 70 function invert(ov)
 71 {
 72   var ov = codevec(ov)
 73   var nv = []
 74   while(ov.length)  {
 75     var e = ov.sarg()
 76     switch(e)  {
 77     case 'pen':
 78     case 'mirror':
 79     case 'reverse':
 80       nv.unshift(e)
 81       break
 82     case 'turn':
 83     case 'forward':
 84       nv = [e,-ov.sarg()].concat(nv)
 85       break
 86     case 'scale':
 87       nv = [e,1/ov.sarg()].concat(nv)
 88       break
 89     case 'repeat':
 90     case 'poly':
 91       var c  = ov.sarg()
 92       var ev = ov.varg()
 93       nv = [e,-c,ev].concat(nv)
 94       break
 95     case 'inverse':
 96       nv = ['identity',ov.varg()].concat(nv)
 97       break
 98     case 'identity':
 99       nv = ['inverse',ov.varg()].concat(nv)
100       break
101     case 'under':
102       var av = ov.varg()
103       var uv = ov.varg()
104       nv = [e,av,invert(uv)].concat(nv)
105       break
106     case 'within':
107       var av = ov.varg()
108       var wv = ov.varg()
109       nv = [e,invert(av),invert(wv)].concat(nv)
110       break
111     case 'flip':
112       var fn = ov.sarg()
113       var bv = ov.varg()
114       var av = ov.varg()
115       e = [fn,av,bv]
116       // fall through
117     default:
118       return invert(e.concat(ov)).concat(nv)
119     }
120   }
121   return nv
122 }
123 
124 
125 
126 function checkarg(e) { return (plan[e] || e) }
127 function checkop(e)  { return (dict[e] || user[e] || ignore) }
128 
129 function ignore(ctx, v) { }
130 function donext(ctx, v) { checkop(v.shift())(ctx,v) }
131 function interp(ctx, v) { for(v = codevec(v); v.length; donext(ctx,v)); }
132 
133 function tokens(s) { return s.replace(/([\[\]])/g," $1 ").split(/\s+/) }
134 function tree(v)
135 {
136   var t = []
137   v.nxt = function() { return this.length ? this.shift() : ']' }
138   for(var e = v.nxt(); e != ']'; e = v.nxt()) { t.push(e == '[' ? tree(v) : e) }
139   return(t)
140 }
141 
142 function turtle(t,c)
143 {
144   /////////////////////////
145   if(document.getElementById("kludge").checked)	{
146     dict['forward'] = function(ctx,v)	{
147 	var x = v.sarg()
148 	if(ctx.penState)	{
149 		ctx.beginPath()
150 		ctx.moveTo(0,0)
151 		ctx.lineTo(x,0)
152 		ctx.stroke()
153 	}
154 	ctx.translate(x,0)
155     }
156   } else {
157     dict['forward'] = function(ctx,v) {
158 	ctx.translate(v.sarg(),0); ctx.displace() }
159   }
160   /////////////////////////
161 
162   var txt = document.getElementById(t)
163   var cvs = document.getElementById(c)
164   var src = txt.value
165   var ctx = cvs.getContext("2d")
166 
167   ctx.save()
168   ctx.clearRect(0,0,cvs.width,cvs.height)
169   ctx.translate(cvs.width/2,cvs.height/2)
170   ctx.beginPath()	// start track display
171   ctx.moveTo(0,0)
172 
173   ctx.penState = 1
174   ctx.displace = function() { this.penState ? ctx.lineTo(0,0)
175 					    : ctx.moveTo(0,0) }
176   plan = {}
177   user = {}
178   interp(ctx, tree(tokens(src)))
179 
180   ctx.stroke()		// show the track
181   ctx.beginPath()	// start turtle display
182   ctx.moveTo(0,-5)
183   ctx.lineTo(20,0)
184   ctx.lineTo(0, 5)
185   ctx.closePath()
186   ctx.fill()		// show the turtle
187   ctx.restore()
188 }
189 
190 function init() { document.getElementById("kludge").checked = !!window.opera }
191 
192 //--></script>
193 <style type="text/css">
194 body	 { font-family: arial; font-size: 10pt;
195 	   background-color: #CCC; color: #000; }
196 h1	 { font-size: 14pt; }
197 canvas   { background-color: #EEE; }
198 textarea { background-color: #EEE; }
199 .doc	 { float: right; border: 1px solid #000; background-color: #FEC; }
200 </style></head><body onLoad="init();turtle('txt','cvs')">
201 <h1>a buggy concatenative turtle <i>(mobilis terrapin)</i></h1>
202 <canvas height=256 width=256 id="cvs" onClick="turtle('txt','cvs')"></canvas>
203 <button onClick="turtle('txt','cvs')">&lt;&lt; draw </button>
204 <textarea cols=60 rows=20 id="txt" onPaste="turtle('txt','cvs')">
205 def jog [ forward 30 under [ turn 45 ] [ forward 10 ] ]
206 def joggle [ under jog reverse reverse ]
207 poly 16 [ poly 4 joggle ]
208 </textarea>
209 <p>Requires javascript and &lt;canvas&gt; support <small> (Safari,Opera,Firefox?)</small>.  Userproofing not included.</p>
210 <p>My Opera can't hack matrix changes while drawing &mdash; if you don't see any output, enable
211 <label for="kludge"> the
212 <input id="kludge" type="checkbox" onClick="turtle('txt','cvs')"/>
213 bletcherous kludge</label></p> 
214 <hr>
215 <div class="doc">
216 <table>
217 <tr><td>pen             </td><td> toggle pen up/down</td></tr>
218 <tr><td>mirror		</td><td> toggle left/right</td></tr>
219 <tr><td>reverse		</td><td> toggle forward/back</td></tr>
220 <tr><td>turn X		</td><td> rotate X degrees</td></tr>
221 <tr><td>forward X	</td><td> translate X units</td></tr>
222 <tr><td>scale X		</td><td> multiply unit size</td></tr>
223 <tr><td></td></tr>
224 <tr><td>repeat N [ ]	</td><td> repeat a plan N times</td></tr>
225 <tr><td>poly N [ ]	</td><td> repeat with implicit turning</td></tr>
226 <tr><td>within [ ] [ ]	</td><td> sandwich a plan<br>(within a b == a b a)</td></tr>
227 <tr><td></td></tr>
228 <tr><td>inverse [ ]	</td><td> produce the opposite of a plan <br>(inverse a == a<sup>-1</sup>)</td></tr>
229 <tr><td>under [ ] [ ]	</td><td> make a do/undo sandwich<br>(under a b == a b a<sup>-1</sup>)</td></tr>
230 <tr><td></td></tr>
231 <tr><td>flip NAME	</td><td> switch argument order<br>(flip f b a == f a b)</td></tr>
232 <tr><td>def NAME [ ]	</td><td> define a subplan<br>(sorry, no arguments)</td></tr>
233 </table>
234 </div>
235 repeat 4 [ forward 100 turn 90 ]<br>
236 <hr>
237 poly 6 [ poly 36 [ reverse pen forward 20 ] ]<br>
238 <hr>
239 def spot [ poly 6 [ forward 10 ] ]<br>
240 def arm [ under [ forward 70 turn -60 ] ]<br>
241 poly 12 [ arm spot ]<br> 
242 <hr>
243 def coil [ repeat 300 [ turn 5 forward 5 scale .99 ] ]<br>
244 def branch [ flip under [ ] ]<br>
245 poly 2 [ branch coil ]<br>
246 <hr>
247 def jog [ forward 30 under [ turn 45 ] [ forward 10 ] ]<br>
248 def joggle [ under jog reverse reverse ]<br>
249 poly 6 [ poly 5 joggle ]<br>
250 <hr>
251 def t [ turn 90 ]<br>
252 def f [ forward 60 ]<br>
253 def h [ forward 30 ]<br>
254 def x [ under [ under t f ] h ]<br>
255 <br>
256 def u [ under t f h ]<br>
257 def q [ under [ repeat 2 u ] ]<br>
258 def w [ under [ repeat 1 u ] ]<br>
259 def e [ under [ repeat 0 u ] ]<br>
260 <br>
261 poly 4 [ q [<br>
262 poly 4 [ w [<br>
263 poly 4 [ e [ <br>
264 x inverse x<br>
265 ] ] ] ] ] ]<br>
266 </body> </html>
267 


Views
Personal tools