summaryrefslogtreecommitdiff
path: root/ipl/gprocs/lsystem.icn
blob: b6ef102b76e5a56e766792e5b4dbbd21cf4ed88a (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
############################################################################
#
#       File:     lsystem.icn
#
#	Subject:  Procedures for Lindenmayer systems support
#
#	Author:   Stephen B. Wampler
#
#	Date:     May 2, 2001
#
############################################################################
#
#   This file is in the public domain.
#
############################################################################
#
#	Version:  1.0
#
############################################################################
#
#   Comments: This package is the collection of routines
#      developed to facilitate experiments with L-systems,
#      including the interpretation of strings as turtle
#      graphics commands.
#
#      Only rudimentary L-systems are currently implemented.
#	users are encouraged to extend this system.
#
############################################################################
#
#	Requires:  Version 9 graphics, co-expressions (for glib.icn)
#
############################################################################
#
#	Links: glib
#
############################################################################

link glib
record Lsys(order, dist, delta, axiom, rewrite)

# lsmap(s1,T) - replace, in s1, occurrences of character key values in T
#     with assigned value for that key.  (Suitable for l-system rules!)
#
procedure lsmap(s1,T)
   local s

   if type(T) ~== "table" then
      stop("lsmap() - second argument not a table!")

   s := ""
   s1 ? while s ||:= (\T[move(1)] | move(1))

   return s
end

# mk_map(L) - build a rewriting map table from list L
#
procedure mk_map(L)
   local a, t

   t := table()
   every a := !L do {
      t[a[1]] := a[2]
      }

   return t
end
      
# read_Lsystem(f) - read in an L system from a file...
#
#      Form for an L_system:
#
#	order: n
#	delta: angle
#	axiom: string
#	map:   c = string
#
procedure read_Lsystem(f)
   local ls, line, next_token

   ls := Lsys(0,10,90,"",table())

   while line := read(f) do {
      next_token := create gen_tokens(line)

      case map(@next_token) of {
         "order:": ls.order := integer(@next_token)
         "dist:" : ls.dist  := integer(@next_token)
         "delta:": ls.delta := numeric(@next_token)
	 "axiom:": ls.axiom := @next_token
	 "map:"  : ls.rewrite[@next_token] := (@next_token, @next_token)
         }
      }

   return ls
end


# write_Lsystem(ls) - display L-system ls (for debugging, mainly)
#
procedure  write_Lsystem(ls)
   write("L-system:")
   write("\torder: ",ls.order)
   write("\t dist: ",ls.dist)
   write("\tdelta: ",ls.delta)
   write("\taxiom: ",ls.axiom)
   every key := key(ls.rewrite) do
       write("\t  map: ",key," -> ",ls.rewrite[key])
   return
end


# build_cmd(ls) - return the command string for
#	l-system ls
#
procedure build_cmd(ls)
   local s

   s := ls.axiom
   every 1 to ls.order do
      s := lsmap(s, ls.rewrite)
   return s

end

# eval_cmd(s) - apply turtle t to command string
#
procedure eval_cmd(t,s,dist,delta)

   s ? while obey(t,move(1), dist, delta)

   return
end
         

# eval_lsys(t,ls,dist,delta) - apply turtle t directly to
#    an Lsystem avoids constructing full Lsystem string
#    at once (i.e. no need to call build_cmd).
#
procedure eval_lsys(t,ls)
   evaluate(t,ls.axiom, ls.rewrite, ls.order, ls.delta, ls.dist)
end

# evaluate(t,s, Ls_map, n, delta, dist) - recursive l-system evaluation
#   (avoids building entire command string)
procedure evaluate(t, s, Ls_map, n, delta, dist)

    if n = 0 then return eval_cmd(t,s,dist,delta)

    s ? while evaluate(t, lsmap(move(1), Ls_map), Ls_map, n-1, delta, dist)
    return
end

# obey(t, c, dist, delta) - execute the appropriate turtle command
#      using turtle t.   (INCOMPLETE) (this is where L-systems could
#      be greatly extended.)
procedure obey(t, c, dist, delta)

    case c of {
       "f" : Move_Forward(t, dist)
       "+" : Left(t, delta)
       "-" : Right(t, delta)
       default: Line_Forward(t, dist)
       }

   return
end

# get_tokens(s) - suspend the tokens in string s
#
procedure gen_tokens(s, ws)
   local nws
   
   /ws := ' \t'
   nws := ~ws

   s ? while tab(upto(nws)) do
          suspend tab(many(nws)) \ 1

end