1 36 37 40 41 import java.awt.Graphics ; 42 import java.util.Stack ; 43 import java.util.Vector ; 44 import java.awt.event.*; 45 46 60 public class CLSFractal 61 extends java.applet.Applet 62 implements Runnable , MouseListener { 63 Thread kicker; 64 ContextLSystem cls; 65 int fractLevel = 1; 66 int repaintDelay = 50; 67 boolean incrementalUpdates; 68 float startAngle = 0; 69 float rotAngle = 45; 70 float Xmin; 71 float Xmax; 72 float Ymin; 73 float Ymax; 74 int border; 75 boolean normalizescaling; 76 77 public void init() { 78 String s; 79 cls = new ContextLSystem(this); 80 s = getParameter("level"); 81 if (s != null) fractLevel = Integer.parseInt(s); 82 s = getParameter("incremental"); 83 if (s != null) incrementalUpdates = s.equalsIgnoreCase("true"); 84 s = getParameter("delay"); 85 if (s != null) repaintDelay = Integer.parseInt(s); 86 s = getParameter("startAngle"); 87 if (s != null) startAngle = Float.valueOf(s).floatValue(); 88 s = getParameter("rotAngle"); 89 if (s != null) rotAngle = Float.valueOf(s).floatValue(); 90 rotAngle = rotAngle / 360 * 2 * 3.14159265358f; 91 s = getParameter("border"); 92 if (s != null) border = Integer.parseInt(s); 93 s = getParameter("normalizescale"); 94 if (s != null) normalizescaling = s.equalsIgnoreCase("true"); 95 addMouseListener(this); 96 } 97 98 public void destroy() { 99 removeMouseListener(this); 100 } 101 102 public void run() { 103 Thread me = Thread.currentThread(); 104 boolean needsRepaint = false; 105 while (kicker == me && cls.getLevel() < fractLevel) { 106 cls.generate(); 107 if (kicker == me && incrementalUpdates) { 108 repaint(); 109 try {Thread.sleep(repaintDelay);} catch (InterruptedException e){} 110 } else { 111 needsRepaint = true; 112 } 113 } 114 if (kicker == me) { 115 kicker = null; 116 if (needsRepaint) { 117 repaint(); 118 } 119 } 120 } 121 122 public void start() { 123 kicker = new Thread (this); 124 kicker.start(); 125 } 126 127 public void stop() { 128 kicker = null; 129 } 130 131 132 public void mouseClicked(MouseEvent e) { 133 } 134 135 public void mousePressed(MouseEvent e) { 136 } 137 138 public void mouseReleased(MouseEvent e) { 139 cls = new ContextLSystem(this); 140 savedPath = null; 141 start(); 142 e.consume(); 143 } 144 145 public void mouseEntered(MouseEvent e) { 146 } 147 148 public void mouseExited(MouseEvent e) { 149 } 150 151 String savedPath; 152 153 public void paint(Graphics g) { 154 String fractalPath = cls.getPath(); 155 if (fractalPath == null) { 156 super.paint(g); 157 return; 158 } 159 if (savedPath == null || !savedPath.equals(fractalPath)) { 160 savedPath = fractalPath; 161 render(null, fractalPath); 162 } 163 164 for (int i = 0; i < border; i++) { 165 g.draw3DRect(i, i, getSize().width - i * 2, getSize().height - i * 2,false); 166 } 167 render(g, fractalPath); 168 } 169 170 void render(Graphics g, String path) { 171 Stack turtleStack = new Stack (); 172 CLSTurtle turtle; 173 174 if (g == null) { 175 Xmin = 1E20f; 176 Ymin = 1E20f; 177 Xmax = -1E20f; 178 Ymax = -1E20f; 179 turtle = new CLSTurtle(startAngle, 0, 0, 0, 0, 1, 1); 180 } else { 181 float frwidth = Xmax - Xmin; 182 if (frwidth == 0) 183 frwidth = 1; 184 float frheight = Ymax - Ymin; 185 if (frheight == 0) 186 frheight = 1; 187 float xscale = (getSize().width - border * 2 - 1) / frwidth; 188 float yscale = (getSize().height - border * 2 - 1) / frheight; 189 int xoff = border; 190 int yoff = border; 191 if (normalizescaling) { 192 if (xscale < yscale) { 193 yoff += ((getSize().height - border * 2) 194 - ((Ymax - Ymin) * xscale)) / 2; 195 yscale = xscale; 196 } else if (yscale < xscale) { 197 xoff += ((getSize().width - border * 2) 198 - ((Xmax - Xmin) * yscale)) / 2; 199 xscale = yscale; 200 } 201 } 202 turtle = new CLSTurtle(startAngle, 0 - Xmin, 0 - Ymin, 203 xoff, yoff, xscale, yscale); 204 } 205 206 for (int pos = 0; pos < path.length(); pos++) { 207 switch (path.charAt(pos)) { 208 case '+': 209 turtle.rotate(rotAngle); 210 break; 211 case '-': 212 turtle.rotate(-rotAngle); 213 break; 214 case '[': 215 turtleStack.push(turtle); 216 turtle = new CLSTurtle(turtle); 217 break; 218 case ']': 219 turtle = (CLSTurtle) turtleStack.pop(); 220 break; 221 case 'f': 222 turtle.jump(); 223 break; 224 case 'F': 225 if (g == null) { 226 includePt(turtle.X, turtle.Y); 227 turtle.jump(); 228 includePt(turtle.X, turtle.Y); 229 } else { 230 turtle.draw(g); 231 } 232 break; 233 default: 234 break; 235 } 236 } 237 } 238 239 void includePt(float x, float y) { 240 if (x < Xmin) 241 Xmin = x; 242 if (x > Xmax) 243 Xmax = x; 244 if (y < Ymin) 245 Ymin = y; 246 if (y > Ymax) 247 Ymax = y; 248 } 249 250 public String getAppletInfo() { 251 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."; 252 } 253 254 public String [][] getParameterInfo() { 255 String [][] info = { 256 {"level", "int", "Maximum number of recursions. Default is 1."}, 257 {"incremental","boolean","Whether or not to repaint between recursions. Default is true."}, 258 {"delay","integer","Sets delay between repaints. Default is 50."}, 259 {"startAngle","float","Sets the starting angle. Default is 0."}, 260 {"rotAngle","float","Sets the rotation angle. Default is 45."}, 261 {"border","integer","Width of border. Default is 2."}, 262 {"normalizeScale","boolean","Whether or not to normalize the scaling. Default is true."}, 263 {"pred","String","Initializes the rules for Context Sensitive L-Systems."}, 264 {"succ","String","Initializes the rules for Context Sensitive L-Systems."}, 265 {"lContext","String","Initializes the rules for Context Sensitive L-Systems."}, 266 {"rContext","String","Initializes the rules for Context Sensitive L-Systems."} 267 }; 268 return info; 269 } 270 } 271 272 281 class CLSTurtle { 282 float angle; 283 float X; 284 float Y; 285 float scaleX; 286 float scaleY; 287 int xoff; 288 int yoff; 289 290 public CLSTurtle(float ang, float x, float y, 291 int xorg, int yorg, float sx, float sy) { 292 angle = ang; 293 scaleX = sx; 294 scaleY = sy; 295 X = x * sx; 296 Y = y * sy; 297 xoff = xorg; 298 yoff = yorg; 299 } 300 301 public CLSTurtle(CLSTurtle turtle) { 302 angle = turtle.angle; 303 X = turtle.X; 304 Y = turtle.Y; 305 scaleX = turtle.scaleX; 306 scaleY = turtle.scaleY; 307 xoff = turtle.xoff; 308 yoff = turtle.yoff; 309 } 310 311 public void rotate(float theta) { 312 angle += theta; 313 } 314 315 public void jump() { 316 X += (float) Math.cos(angle) * scaleX; 317 Y += (float) Math.sin(angle) * scaleY; 318 } 319 320 public void draw(Graphics g) { 321 float x = X + (float) Math.cos(angle) * scaleX; 322 float y = Y + (float) Math.sin(angle) * scaleY; 323 g.drawLine((int) X + xoff, (int) Y + yoff, 324 (int) x + xoff, (int) y + yoff); 325 X = x; 326 Y = y; 327 } 328 } 329 330 341 class ContextLSystem { 342 String axiom; 343 Vector rules = new Vector (); 344 int level; 345 346 public ContextLSystem(java.applet.Applet app) { 347 axiom = app.getParameter("axiom"); 348 int num = 1; 349 while (true) { 350 String pred = app.getParameter("pred"+num); 351 String succ = app.getParameter("succ"+num); 352 if (pred == null || succ == null) { 353 break; 354 } 355 rules.addElement(new CLSRule(pred, succ, 356 app.getParameter("lContext"+num), 357 app.getParameter("rContext"+num))); 358 num++; 359 } 360 currentPath = new StringBuffer (axiom); 361 level = 0; 362 } 363 364 public int getLevel() { 365 return level; 366 } 367 368 StringBuffer currentPath; 369 370 public synchronized String getPath() { 371 return ((currentPath == null) ? null : currentPath.toString()); 372 } 373 374 private synchronized void setPath(StringBuffer path) { 375 currentPath = path; 376 level++; 377 } 378 379 public void generate() { 380 StringBuffer newPath = new StringBuffer (); 381 int pos = 0; 382 while (pos < currentPath.length()) { 383 CLSRule rule = findRule(pos); 384 if (rule == null) { 385 newPath.append(currentPath.charAt(pos)); 386 pos++; 387 } else { 388 newPath.append(rule.succ); 389 pos += rule.pred.length(); 390 } 391 } 392 setPath(newPath); 393 } 394 395 public CLSRule findRule(int pos) { 396 for (int i = 0; i < rules.size(); i++) { 397 CLSRule rule = (CLSRule) rules.elementAt(i); 398 if (rule.matches(currentPath, pos)) { 399 return rule; 400 } 401 } 402 return null; 403 } 404 } 405 406 417 class CLSRule { 418 String pred; 419 String succ; 420 String lContext; 421 String rContext; 422 423 public CLSRule(String p, String d, String l, String r) { 424 pred = p; 425 succ = d; 426 lContext = l; 427 rContext = r; 428 } 429 430 public boolean matches(StringBuffer sb, int pos) { 431 if (pos + pred.length() > sb.length()) { 432 return false; 433 } 434 char cb[] = new char[pred.length()]; 435 sb.getChars(pos, pos + pred.length(), cb, 0); 436 return pred.equals(new String (cb)); 437 } 438 } 439 | Popular Tags |