65 float Ymin; |
67 float Ymin; |
66 float Ymax; |
68 float Ymax; |
67 int border; |
69 int border; |
68 boolean normalizescaling; |
70 boolean normalizescaling; |
69 |
71 |
|
72 @Override |
70 public void init() { |
73 public void init() { |
71 String s; |
74 String s; |
72 cls = new ContextLSystem(this); |
75 cls = new ContextLSystem(this); |
73 s = getParameter("level"); |
76 s = getParameter("level"); |
74 if (s != null) fractLevel = Integer.parseInt(s); |
77 if (s != null) { |
|
78 fractLevel = Integer.parseInt(s); |
|
79 } |
75 s = getParameter("incremental"); |
80 s = getParameter("incremental"); |
76 if (s != null) incrementalUpdates = s.equalsIgnoreCase("true"); |
81 if (s != null) { |
|
82 incrementalUpdates = s.equalsIgnoreCase("true"); |
|
83 } |
77 s = getParameter("delay"); |
84 s = getParameter("delay"); |
78 if (s != null) repaintDelay = Integer.parseInt(s); |
85 if (s != null) { |
|
86 repaintDelay = Integer.parseInt(s); |
|
87 } |
79 s = getParameter("startAngle"); |
88 s = getParameter("startAngle"); |
80 if (s != null) startAngle = Float.valueOf(s).floatValue(); |
89 if (s != null) { |
|
90 startAngle = Float.valueOf(s).floatValue(); |
|
91 } |
81 s = getParameter("rotAngle"); |
92 s = getParameter("rotAngle"); |
82 if (s != null) rotAngle = Float.valueOf(s).floatValue(); |
93 if (s != null) { |
|
94 rotAngle = Float.valueOf(s).floatValue(); |
|
95 } |
83 rotAngle = rotAngle / 360 * 2 * 3.14159265358f; |
96 rotAngle = rotAngle / 360 * 2 * 3.14159265358f; |
84 s = getParameter("border"); |
97 s = getParameter("border"); |
85 if (s != null) border = Integer.parseInt(s); |
98 if (s != null) { |
|
99 border = Integer.parseInt(s); |
|
100 } |
86 s = getParameter("normalizescale"); |
101 s = getParameter("normalizescale"); |
87 if (s != null) normalizescaling = s.equalsIgnoreCase("true"); |
102 if (s != null) { |
|
103 normalizescaling = s.equalsIgnoreCase("true"); |
|
104 } |
88 addMouseListener(this); |
105 addMouseListener(this); |
89 } |
106 } |
90 |
107 |
|
108 @Override |
91 public void destroy() { |
109 public void destroy() { |
92 removeMouseListener(this); |
110 removeMouseListener(this); |
93 } |
111 } |
94 |
112 |
|
113 @Override |
95 public void run() { |
114 public void run() { |
96 Thread me = Thread.currentThread(); |
115 Thread me = Thread.currentThread(); |
97 boolean needsRepaint = false; |
116 boolean needsRepaint = false; |
98 while (kicker == me && cls.getLevel() < fractLevel) { |
117 while (kicker == me && cls.getLevel() < fractLevel) { |
99 cls.generate(); |
118 cls.generate(); |
100 if (kicker == me && incrementalUpdates) { |
119 if (kicker == me && incrementalUpdates) { |
101 repaint(); |
120 repaint(); |
102 try {Thread.sleep(repaintDelay);} catch (InterruptedException e){} |
121 try { |
|
122 Thread.sleep(repaintDelay); |
|
123 } catch (InterruptedException ignored) { |
|
124 } |
103 } else { |
125 } else { |
104 needsRepaint = true; |
126 needsRepaint = true; |
105 } |
127 } |
106 } |
128 } |
107 if (kicker == me) { |
129 if (kicker == me) { |
153 savedPath = fractalPath; |
182 savedPath = fractalPath; |
154 render(null, fractalPath); |
183 render(null, fractalPath); |
155 } |
184 } |
156 |
185 |
157 for (int i = 0; i < border; i++) { |
186 for (int i = 0; i < border; i++) { |
158 g.draw3DRect(i, i, getSize().width - i * 2, getSize().height - i * 2,false); |
187 g.draw3DRect(i, i, getSize().width - i * 2, getSize().height - i * 2, |
|
188 false); |
159 } |
189 } |
160 render(g, fractalPath); |
190 render(g, fractalPath); |
161 } |
191 } |
162 |
192 |
163 void render(Graphics g, String path) { |
193 void render(Graphics g, String path) { |
164 Stack turtleStack = new Stack(); |
194 Stack<CLSTurtle> turtleStack = new Stack<CLSTurtle>(); |
165 CLSTurtle turtle; |
195 CLSTurtle turtle; |
166 |
196 |
167 if (g == null) { |
197 if (g == null) { |
168 Xmin = 1E20f; |
198 Xmin = 1E20f; |
169 Ymin = 1E20f; |
199 Ymin = 1E20f; |
170 Xmax = -1E20f; |
200 Xmax = -1E20f; |
171 Ymax = -1E20f; |
201 Ymax = -1E20f; |
172 turtle = new CLSTurtle(startAngle, 0, 0, 0, 0, 1, 1); |
202 turtle = new CLSTurtle(startAngle, 0, 0, 0, 0, 1, 1); |
173 } else { |
203 } else { |
174 float frwidth = Xmax - Xmin; |
204 float frwidth = Xmax - Xmin; |
175 if (frwidth == 0) |
205 if (frwidth == 0) { |
176 frwidth = 1; |
206 frwidth = 1; |
|
207 } |
177 float frheight = Ymax - Ymin; |
208 float frheight = Ymax - Ymin; |
178 if (frheight == 0) |
209 if (frheight == 0) { |
179 frheight = 1; |
210 frheight = 1; |
|
211 } |
180 float xscale = (getSize().width - border * 2 - 1) / frwidth; |
212 float xscale = (getSize().width - border * 2 - 1) / frwidth; |
181 float yscale = (getSize().height - border * 2 - 1) / frheight; |
213 float yscale = (getSize().height - border * 2 - 1) / frheight; |
182 int xoff = border; |
214 int xoff = border; |
183 int yoff = border; |
215 int yoff = border; |
184 if (normalizescaling) { |
216 if (normalizescaling) { |
185 if (xscale < yscale) { |
217 if (xscale < yscale) { |
186 yoff += ((getSize().height - border * 2) |
218 yoff += ((getSize().height - border * 2) |
187 - ((Ymax - Ymin) * xscale)) / 2; |
219 - ((Ymax - Ymin) * xscale)) / 2; |
188 yscale = xscale; |
220 yscale = xscale; |
189 } else if (yscale < xscale) { |
221 } else if (yscale < xscale) { |
190 xoff += ((getSize().width - border * 2) |
222 xoff += ((getSize().width - border * 2) |
191 - ((Xmax - Xmin) * yscale)) / 2; |
223 - ((Xmax - Xmin) * yscale)) / 2; |
192 xscale = yscale; |
224 xscale = yscale; |
193 } |
225 } |
194 } |
226 } |
195 turtle = new CLSTurtle(startAngle, 0 - Xmin, 0 - Ymin, |
227 turtle = new CLSTurtle(startAngle, 0 - Xmin, 0 - Ymin, |
196 xoff, yoff, xscale, yscale); |
228 xoff, yoff, xscale, yscale); |
197 } |
229 } |
198 |
230 |
199 for (int pos = 0; pos < path.length(); pos++) { |
231 for (int pos = 0; pos < path.length(); pos++) { |
200 switch (path.charAt(pos)) { |
232 switch (path.charAt(pos)) { |
201 case '+': |
233 case '+': |
202 turtle.rotate(rotAngle); |
234 turtle.rotate(rotAngle); |
203 break; |
235 break; |
204 case '-': |
236 case '-': |
205 turtle.rotate(-rotAngle); |
237 turtle.rotate(-rotAngle); |
206 break; |
238 break; |
207 case '[': |
239 case '[': |
208 turtleStack.push(turtle); |
240 turtleStack.push(turtle); |
209 turtle = new CLSTurtle(turtle); |
241 turtle = new CLSTurtle(turtle); |
210 break; |
242 break; |
211 case ']': |
243 case ']': |
212 turtle = (CLSTurtle) turtleStack.pop(); |
244 turtle = turtleStack.pop(); |
213 break; |
245 break; |
214 case 'f': |
246 case 'f': |
215 turtle.jump(); |
|
216 break; |
|
217 case 'F': |
|
218 if (g == null) { |
|
219 includePt(turtle.X, turtle.Y); |
|
220 turtle.jump(); |
247 turtle.jump(); |
221 includePt(turtle.X, turtle.Y); |
248 break; |
222 } else { |
249 case 'F': |
223 turtle.draw(g); |
250 if (g == null) { |
224 } |
251 includePt(turtle.X, turtle.Y); |
225 break; |
252 turtle.jump(); |
226 default: |
253 includePt(turtle.X, turtle.Y); |
227 break; |
254 } else { |
|
255 turtle.draw(g); |
|
256 } |
|
257 break; |
|
258 default: |
|
259 break; |
228 } |
260 } |
229 } |
261 } |
230 } |
262 } |
231 |
263 |
232 void includePt(float x, float y) { |
264 void includePt(float x, float y) { |
233 if (x < Xmin) |
265 if (x < Xmin) { |
234 Xmin = x; |
266 Xmin = x; |
235 if (x > Xmax) |
267 } |
|
268 if (x > Xmax) { |
236 Xmax = x; |
269 Xmax = x; |
237 if (y < Ymin) |
270 } |
|
271 if (y < Ymin) { |
238 Ymin = y; |
272 Ymin = y; |
239 if (y > Ymax) |
273 } |
|
274 if (y > Ymax) { |
240 Ymax = y; |
275 Ymax = y; |
241 } |
276 } |
242 |
277 } |
243 public String getAppletInfo() { |
278 |
244 return "Title: CLSFractal 1.1f, 27 Mar 1995 \nAuthor: Jim Graham \nA (not yet) Context Sensitive L-System production rule. \nThis class encapsulates a production rule for a Context Sensitive\n L-System \n(pred, succ, lContext, rContext). The matches() method, however, does not \n(yet) verify the lContext and rContext parts of the rule."; |
279 @Override |
245 } |
280 public String getAppletInfo() { |
246 |
281 return "Title: CLSFractal 1.1f, 27 Mar 1995 \nAuthor: Jim Graham \nA " |
247 public String[][] getParameterInfo() { |
282 + "(not yet) Context Sensitive L-System production rule. \n" |
248 String[][] info = { |
283 + "This class encapsulates a production rule for a Context " |
249 {"level", "int", "Maximum number of recursions. Default is 1."}, |
284 + "Sensitive\n L-System \n(pred, succ, lContext, rContext)." |
250 {"incremental","boolean","Whether or not to repaint between recursions. Default is true."}, |
285 + " The matches() method, however, does not \n(yet) verify " |
251 {"delay","integer","Sets delay between repaints. Default is 50."}, |
286 + "the lContext and rContext parts of the rule."; |
252 {"startAngle","float","Sets the starting angle. Default is 0."}, |
287 } |
253 {"rotAngle","float","Sets the rotation angle. Default is 45."}, |
288 |
254 {"border","integer","Width of border. Default is 2."}, |
289 @Override |
255 {"normalizeScale","boolean","Whether or not to normalize the scaling. Default is true."}, |
290 public String[][] getParameterInfo() { |
256 {"pred","String","Initializes the rules for Context Sensitive L-Systems."}, |
291 String[][] info = { |
257 {"succ","String","Initializes the rules for Context Sensitive L-Systems."}, |
292 { "level", "int", "Maximum number of recursions. Default is 1." }, |
258 {"lContext","String","Initializes the rules for Context Sensitive L-Systems."}, |
293 { "incremental", "boolean", "Whether or not to repaint between " |
259 {"rContext","String","Initializes the rules for Context Sensitive L-Systems."} |
294 + "recursions. Default is true." }, |
260 }; |
295 { "delay", "integer", "Sets delay between repaints. Default is 50." }, |
261 return info; |
296 { "startAngle", "float", "Sets the starting angle. Default is 0." }, |
262 } |
297 { "rotAngle", "float", "Sets the rotation angle. Default is 45." }, |
|
298 { "border", "integer", "Width of border. Default is 2." }, |
|
299 { "normalizeScale", "boolean", "Whether or not to normalize " |
|
300 + "the scaling. Default is true." }, |
|
301 { "pred", "String", |
|
302 "Initializes the rules for Context Sensitive L-Systems." }, |
|
303 { "succ", "String", |
|
304 "Initializes the rules for Context Sensitive L-Systems." }, |
|
305 { "lContext", "String", |
|
306 "Initializes the rules for Context Sensitive L-Systems." }, |
|
307 { "rContext", "String", |
|
308 "Initializes the rules for Context Sensitive L-Systems." } |
|
309 }; |
|
310 return info; |
|
311 } |
263 } |
312 } |
|
313 |
264 |
314 |
265 /** |
315 /** |
266 * A Logo turtle class designed to support Context sensitive L-Systems. |
316 * A Logo turtle class designed to support Context sensitive L-Systems. |
267 * |
317 * |
268 * This turtle performs a few basic maneuvers needed to support the |
318 * This turtle performs a few basic maneuvers needed to support the |
269 * set of characters used in Context sensitive L-Systems "+-fF[]". |
319 * set of characters used in Context sensitive L-Systems "+-fF[]". |
270 * |
320 * |
271 * @author Jim Graham |
321 * @author Jim Graham |
272 */ |
322 */ |
273 class CLSTurtle { |
323 class CLSTurtle { |
|
324 |
274 float angle; |
325 float angle; |
275 float X; |
326 float X; |
276 float Y; |
327 float Y; |
277 float scaleX; |
328 float scaleX; |
278 float scaleY; |
329 float scaleY; |
279 int xoff; |
330 int xoff; |
280 int yoff; |
331 int yoff; |
281 |
332 |
282 public CLSTurtle(float ang, float x, float y, |
333 public CLSTurtle(float ang, float x, float y, |
283 int xorg, int yorg, float sx, float sy) { |
334 int xorg, int yorg, float sx, float sy) { |
284 angle = ang; |
335 angle = ang; |
285 scaleX = sx; |
336 scaleX = sx; |
286 scaleY = sy; |
337 scaleY = sy; |
287 X = x * sx; |
338 X = x * sx; |
288 Y = y * sy; |
339 Y = y * sy; |
328 * and rContext parts of the rules. |
380 * and rContext parts of the rules. |
329 * |
381 * |
330 * @author Jim Graham |
382 * @author Jim Graham |
331 */ |
383 */ |
332 class ContextLSystem { |
384 class ContextLSystem { |
|
385 |
333 String axiom; |
386 String axiom; |
334 Vector rules = new Vector(); |
387 List<CLSRule> rules = new ArrayList<CLSRule>(); |
335 int level; |
388 int level; |
336 |
389 |
337 public ContextLSystem(java.applet.Applet app) { |
390 public ContextLSystem(java.applet.Applet app) { |
338 axiom = app.getParameter("axiom"); |
391 axiom = app.getParameter("axiom"); |
339 int num = 1; |
392 int num = 1; |
340 while (true) { |
393 while (true) { |
341 String pred = app.getParameter("pred"+num); |
394 String pred = app.getParameter("pred" + num); |
342 String succ = app.getParameter("succ"+num); |
395 String succ = app.getParameter("succ" + num); |
343 if (pred == null || succ == null) { |
396 if (pred == null || succ == null) { |
344 break; |
397 break; |
345 } |
398 } |
346 rules.addElement(new CLSRule(pred, succ, |
399 rules.add(new CLSRule(pred, succ, |
347 app.getParameter("lContext"+num), |
400 app.getParameter("lContext" + num), |
348 app.getParameter("rContext"+num))); |
401 app.getParameter("rContext" + num))); |
349 num++; |
402 num++; |
350 } |
403 } |
351 currentPath = new StringBuffer(axiom); |
404 currentPath = new StringBuffer(axiom); |
352 level = 0; |
405 level = 0; |
353 } |
406 } |
354 |
407 |
355 public int getLevel() { |
408 public int getLevel() { |
356 return level; |
409 return level; |
357 } |
410 } |
358 |
|
359 StringBuffer currentPath; |
411 StringBuffer currentPath; |
360 |
412 |
361 public synchronized String getPath() { |
413 public synchronized String getPath() { |
362 return ((currentPath == null) ? null : currentPath.toString()); |
414 return ((currentPath == null) ? null : currentPath.toString()); |
363 } |
415 } |