summaryrefslogtreecommitdiff
path: root/ipl/gprocs/turtle.icn
blob: d81c5f746eb141b98f8265fb2315650a6b2d2c1f (plain)
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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
############################################################################
#
#	File:     turtle.icn
#
#	Subject:  Procedures for turtle-graphics interface
#
#	Author:   Gregg M. Townsend
#
#	Date:     August 8, 2000
#
############################################################################
#
#   This file is in the public domain.
#
############################################################################
#
#	These procedures provide a "turtle graphics" interface to Icon.
#	With this approach, popularized by the Logo programming language,
#	all drawing is done by a "turtle" that carries a pen over a drawing
#	surface under program control.
#
#	TWindow(W)	sets the turtle window.
#
#	TDraw(n)	moves forward and draws.
#
#	TSkip(n)	skips forward without drawing.
#
#	TDrawto(x, y)	draws to the point (x,y).
#
#	TScale(n)	sets or queries current scaling factor.
#
#	TRight(d)	turns right d degrees.
#
#	TLeft(d)	turns left d degrees.
#
#	THeading(a)	sets or queries the heading.
#
#	TFace(x, y)	sets or queries the heading.
#
#	TX(x)		sets or queries the current x position.
#
#	TY(y)		sets or queries the current y position.
#
#	TGoto(x, y, a)	sets the location and optionally changes the heading.
#
#	THome()		moves to the window center and turns to face upward.
#
#	TReset()	clears the window and reinitializes.
#
#	TSave()		saves the turtle state.
#
#	TRestore()	restores the turtle state.
#
#	TRect(h, w)	draws a rectangle centered at the turtle.
#
#	TCircle(d)	draws a circle centered at the turtle.
#
#	TPoly(d, n)	draws a polygon centered at the turtle.
#
#	TFRect(h, w)	draws a filled rectangle centered at the turtle.
#
#	TFCircle(d)	draws a filled circle centered at the turtle.
#
#	TFPoly(d, n)	draws a filled polygon centered at the turtle.
#
############################################################################
#
#  In this package there is a single turtle which is itself invisible;
#  it is known only by the marks it leaves on the window.  It remembers
#  its location and heading between calls.
#
#  No explicit initialization is required.  The turtle begins at the
#  center of the window with a heading of -90 degrees (that is, pointed
#  towards the top of the window).
#
#  The turtle draws on &window unless a different window is specified by
#  calling TWindow().  If no window is provided and &window is null,
#  a 500x500 window is opened and assigned to &window.
#
#  Distances are measured in pixels and are always multiplied by a
#  settable scaling factor, initially 1.  Angles are measured in degrees;
#  absolute angles measure clockwise from the positive X axis.
#
############################################################################
#
#  The procedures are as follows:
#
#  TDraw(n) -- move forward and draw
#  TSkip(n) -- skip forward without drawing
#	The turtle moves forward n units.  n can be negative to move
#	backwards.
#	Default:  n = 1
#
#  TDrawto(x, y) -- draw to the point (x,y)
#	The turtle turns and draws a line to the point (x,y).
#	The heading is also set as a consequence of this movement.
#	Default:  center of window
#
#  TScale(n) -- set or query current scaling factor.
#	If n is supplied, the scaling factor applied to TDraw and TSkip
#	arguments is *multiplied* (not replaced) by n.  The resulting
#	(multiplied or unaltered) scaling factor is returned.
#	The turtle's heading and location do not change.
#
#  TRight(d) -- turn right
#  TLeft(d) -- turn left
#	The turtle turns d degrees to the right or left of its current
#	heading.  Its location does not change, and nothing is drawn.
#	The resulting heading is returned.
#	Default:  d = 90
#
#  THeading(a) -- set or query heading
#	The turtle's heading (in degrees) is returned.  If a is supplied,
#	the heading is first set to that value.  The location does not
#	change.
#
#  TFace(x, y) -- set or query heading
#	The turtle turns to face directly towards the point (x,y).
#	If x and y are missing or the turtle is already at (x,y),
#	the heading does not change.  The new heading is returned.
#	Default: center of window
#
#  TX(x) -- set or query current x position
#  TY(y) -- set or query current y position
#	The unscaled x- or y-coordinate of the turtle's current location
#	is returned.  If an argument is supplied, the coordinate value
#	is first set, moving the turtle without drawing.  The turtle's
#	heading does not change.
#
#  TGoto(x, y, a) -- set location and optionally change heading
#	The turtle moves to the point (x,y) without drawing.
#	The turtle's heading remains unaltered unless <a> is supplied,
#	in which case the turtle then turns to a heading of <a>.
#	Default:  center of window
#
#  THome() -- move to home (center of window) and point North
#	The turtle moves to the center of the window without drawing
#	and the heading is set to -90 degrees.  The scaling factor
#	remains unaltered.
#
#  TReset() -- clear window and reinitialize
#	The window is cleared, the turtle moves to the center of the
#	window without drawing, the heading is set to -90 degrees, the
#	scaling factor is reset to 1, and the TRestore() stack is
#	cleared.  These actions restore the initial conditions.
#
#  TSave() -- save turtle state
#  TRestore() -- restore turtle state
#	TSave saves the current turtle window, location, heading, and
#	scale on an internal stack.  TRestore pops the stack and sets
#	those values, or fails if the stack is empty.
#
#  TRect(h, w) -- draw a rectangle centered at the turtle
#  TCircle(d) -- draw a circle centered at the turtle
#  TPoly(d, n) -- draw an n-sided regular polygon centered at the turtle
#	These three procedures draw a figure centered at the turtle's
#	current location.  The location and heading do not change.
#	The base of the figure, if any, is directly behind the turtle.
#
#	TRect(h, w) draws a rectangle of height h and width w.
#	"width" is the dimension perpendicular to the turtle's path.
#	Default:  h = 1
#		  w = h
#
#	TCircle(d) draws a circle of diameter d.
#	Default:  d = 1
#
#	TPoly(d, n) draws an n-sided regular polygon whose circumscribed
#	circle would have a diameter of d.
#	Default:  d = 1
#		  n = 3
#
#  TFRect(h, w) -- draw a filled rectangle centered at the turtle
#  TFCircle(d) -- draw a filled circle centered at the turtle
#  TFPoly(d, n) -- draw an n-sided filled polygon centered at the turtle
#	These are like their counterparts above, but a solid figure is
#	drawn instead of just an outline.
#
#  TWindow(win) -- set turtle window
#	The turtle is moved to the given window, retaining its
#	coordinates and heading.
#	Default:   win = &window
#
#  These procedures do not attempt to provide a complete graphics interface;
#  in particular, no control of color is provided.  Missing functions can
#  be accomplished by calling the appropriate Icon routines.
#
#  Unlike most turtle graphics environments, there are no commands to
#  lift and drop the pen.  Instead, use TSkip() to move without drawing,
#  or set WAttrib("drawop=noop") if you really need a global "pen up"
#  state.
#
############################################################################
#
#  Requires:  Version 9 graphics
#
############################################################################

global T_x, T_y			# current location
global T_deg			# current heading
global T_scale			# current scaling
global T_stack			# turtle state stack
global T_win			# current window

#  TWindow(win) -- set turtle window

procedure TWindow(win)		#: set turtle window
   /win := &window
   if type(win) ~== "window" then
      runerr(140, win)
   T_win := win
   return
end

#  TInit() -- initialize turtle system, opening window if needed

procedure TInit()		#: initialize turtle system
   TInit := 1			# suppress any subsequent calls
   if /T_win then {
      /&window := open("turtle", "g", "width=500", "height=500") |
         stop("can't open window")
      T_win := &window
      }
   T_stack := []
   T_scale := 1.0
   TGoto(, , -90.0)
   return
end

#  TReset() -- clear window and stack, reset scaling, go to center, head -90

procedure TReset()		#: reset turtle system
   initial TInit()
   T_stack := []
   EraseArea(T_win, -WAttrib(T_win, "dx"), -WAttrib(T_win, "dy"))
   T_scale := 1.0
   return TGoto(, , -90.0)
end

#  THome() -- go to center and set heading to 90 degrees

procedure THome()		#: return turtle to home
   initial TInit()
   return TGoto(, , -90.0)
end

#  TScale(n) -- set / return scaling

procedure TScale(n)		#: turtle scaling
   initial TInit()
   if T_scale *:= (0.0 ~= \n) then
      THeading(T_deg)
   return T_scale
end

#  THeading(d), TLeft(d), TRight(d), TFace(x, y) -- set / return heading

procedure THeading(d)		#: turtle heading
   initial TInit()

   T_deg := \d % 360		# set normalized heading
   return T_deg
end

procedure TRight(d)		#: turn turtle right
   initial TInit()
   return THeading(T_deg + (\d | 90.0))
end

procedure TLeft(d)		#: turn turtle left
   initial TInit()
   return THeading(T_deg - (\d | 90.0))
end

procedure TFace(x, y)		#: face turtle
   initial TInit()
   /x := WAttrib(T_win, "width") / 2 + 0.5
   /y := WAttrib(T_win, "height") / 2 + 0.5
   if not (x = \T_x & y = \T_y) then
      return THeading(rtod(atan(y - T_y, x - T_x)))
   else
      return THeading()
end

#  TX(x), TY(y) -- set or return current x / y location (unscaled).

procedure TX(x)			#: turtle x coordinate
   initial TInit()
   return (T_x := \x) | T_x
end

procedure TY(y)			#: turtle y coordinate
   initial TInit()
   return (T_y := \y) | T_y
end

#  TDraw(n) -- move forward n units while drawing a line

procedure TDraw(n)		#: draw with turtle
   local rad
   initial TInit()

   /n := 1.0
   rad := dtor(T_deg)
   DrawLine(T_win, .T_x, .T_y,
      T_x +:= T_scale * cos(rad) * n, T_y +:= T_scale * sin(rad) * n)
   return
end

#  TSkip(n) -- move forward n units without drawing

procedure TSkip(n)		#: skip with turtle
   local rad
   initial TInit()

   /n := 1.0
   rad := dtor(T_deg)
   T_x +:= T_scale * cos(rad) * n
   T_y +:= T_scale * sin(rad) * n
   return
end

#  TGoto(x, y, a) -- move to (x,y) without drawing, and set heading if given

procedure TGoto(x, y, a)	#: go to with turtle
   initial TInit()
   T_x := \x | WAttrib(T_win, "width") / 2 + 0.5
   T_y := \y | WAttrib(T_win, "height") / 2 + 0.5
   THeading(\a)
   return
end

#  TDrawto(x, y, a) -- draw line to (x,y), and set heading if given

procedure TDrawto(x, y, a)	#: draw to with turtle
   initial TInit()
   /x := WAttrib(T_win, "width") / 2 + 0.5
   /y := WAttrib(T_win, "height") / 2 + 0.5
   if /a then
      TFace(x, y)
   DrawLine(T_win, .T_x, .T_y, T_x := x, T_y := y)
   THeading(\a)
   return
end

#  TSave() -- save turtle state

procedure TSave()		#: save turtle state
   initial TInit()
   push(T_stack, T_deg, T_y, T_x, T_scale, T_win)
   return
end

#  TRestore() -- restore turtle state

procedure TRestore()		#: restore turtle state
   initial TInit()
   T_win := pop(T_stack)
   T_scale := pop(T_stack)
   return TGoto(pop(T_stack), pop(T_stack), pop(T_stack))
end


############################################################################
#
#  Higher level routines.
#  These do not depend on the internals of procs above.
#
############################################################################

#  TRect(h, w) -- draw a rectangle centered at the turtle
#  TFRect(h, w) -- draw a filled rectangle centered at the turtle

procedure TRect(h, w)		#: draw rectangle centered at turtle
   return T_rectangle(h, w, DrawLine)
end

procedure TFRect(h, w)		#: draw filled rectangle centered at turtle
   return T_rectangle(h, w, FillPolygon)
end

procedure T_rectangle(h, w, xcall)
   local l

   /h := 1.0
   /w := h
   l := [T_win]
   TSkip(h / 2.0);  TRight()
   TSkip(w / 2.0);  put(l, TX(), TY());  TRight()
   TSkip(h);        put(l, TX(), TY());  TRight()
   TSkip(w);        put(l, TX(), TY());  TRight()
   TSkip(h);        put(l, TX(), TY());  TRight()
   TSkip(w / 2.0);  put(l, TX(), TY());  TLeft()
   TSkip(-h / 2.0)
   put(l, l[2], l[3])
   xcall ! l
   return
end

#  TCircle(d) -- draw a circle centered at the turtle
#  TFCircle(d) -- draw a filled circle centered at the turtle

procedure TCircle(d)		#: draw circle centered at turtle
   local r
   d := TScale() * (abs(\d) | 1.0)
   r := d / 2.0
   DrawArc(T_win, TX() - r, TY() - r, d, d)
   return
end

procedure TFCircle(d)		#: draw filled circle centered at turtle
   local r
   d := TScale() * (abs(\d) | 1.0)
   r := d / 2.0
   FillArc(T_win, TX() - r, TY() - r, d, d)
   return
end

#  TPoly(d, n) -- draw an n-sided regular polygon centered at the turtle
#  TFPoly(d, n) -- draw an n-sided filled polygon centered at the turtle

procedure TPoly(d, n)		#: draw polygon centered at turtle
   return T_polygon(d, n, DrawLine)
end

procedure TFPoly(d, n)		#: draw filled polygon centered at turtle
   return T_polygon(d, n, FillPolygon)
end

procedure T_polygon(d, n, xcall)
   local r, a, da, cx, cy, x, y, l
   r := TScale() * ((\d / 3.0) | 1.0)
   n := abs(integer(\n + 0.5)) | 3.0
   n <:= 2.0
   da := dtor(360.0 / n)
   a := dtor(THeading() + 180.0) + da / 2.0
   x := (cx := TX()) + r * cos(a)
   y := (cy := TY()) + r * sin(a)
   l := [T_win, x, y]
   every 1 to n do {
      put(l, x := cx + r * cos(a+:=da))
      put(l, y := cy + r * sin(a))
      }
   xcall ! l
   return
end