home *** CD-ROM | disk | FTP | other *** search
/ Ultra Pack / UltraComputing Technology Demos and Tools.iso / java / demo / Fractal / CLSFractal.java < prev    next >
Encoding:
Java Source  |  1996-04-26  |  9.7 KB  |  386 lines

  1. /*
  2.  * Copyright (c) 1994-1996 Sun Microsystems, Inc. All Rights Reserved.
  3.  *
  4.  * Permission to use, copy, modify, and distribute this software
  5.  * and its documentation for NON-COMMERCIAL or COMMERCIAL purposes and
  6.  * without fee is hereby granted.
  7.  * Please refer to the file http://java.sun.com/copy_trademarks.html
  8.  * for further important copyright and trademark information and to
  9.  * http://java.sun.com/licensing.html for further important licensing
  10.  * information for the Java (tm) Technology.
  11.  *
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  13.  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  14.  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  15.  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  16.  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  17.  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  18.  *
  19.  * THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE
  20.  * CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE
  21.  * PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT
  22.  * NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE
  23.  * SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
  24.  * SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE
  25.  * PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES").  SUN
  26.  * SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR
  27.  * HIGH RISK ACTIVITIES.
  28.  */
  29. import java.awt.Graphics;
  30. import java.util.Stack;
  31. import java.util.Vector;
  32.  
  33. /**
  34.  * A (not-yet) Context sensitive L-System Fractal applet class.
  35.  *
  36.  * The rules for the Context L-system are read from the java.applet.Applet's
  37.  * attributes and then the system is iteratively applied for the
  38.  * given number of levels, possibly drawing each generation as it
  39.  * is generated.  Note that the ContextLSystem class does not yet
  40.  * handle the lContext and rContext attributes, although this
  41.  * class is already designed to parse the '[' and ']' characters
  42.  * typically used in Context sensitive L-Systems.
  43.  *
  44.  * @author     Jim Graham
  45.  * @version     1.1f, 27 Mar 1995
  46.  */
  47. public class CLSFractal extends java.applet.Applet implements Runnable {
  48.     ContextLSystem cls;
  49.     int fractLevel = 1;
  50.     int repaintDelay = 50;
  51.     boolean incrementalUpdates;
  52.     float startAngle;
  53.     float rotAngle;
  54.     float Xmin;
  55.     float Xmax;
  56.     float Ymin;
  57.     float Ymax;
  58.     int border;
  59.     boolean normalizescaling;
  60.  
  61.     public void init() {
  62.     String s;
  63.     cls = new ContextLSystem(this);
  64.     s = getParameter("level");
  65.     if (s != null) fractLevel = Integer.parseInt(s);
  66.     s = getParameter("incremental");
  67.     if (s != null) incrementalUpdates = s.equals("true");
  68.     s = getParameter("delay");
  69.     if (s != null) repaintDelay = Integer.parseInt(s);
  70.     s = getParameter("startAngle");
  71.     if (s != null) startAngle = Float.valueOf(s).floatValue();
  72.     s = getParameter("rotAngle");
  73.     if (s != null) rotAngle = Float.valueOf(s).floatValue();
  74.     rotAngle = rotAngle / 360 * 2 * 3.14159265358f;
  75.     s = getParameter("border");
  76.     if (s != null) border = Integer.parseInt(s);
  77.     s = getParameter("normalizescale");
  78.     if (s != null) normalizescaling = s.equals("true");
  79.     }
  80.  
  81.     Thread kicker;
  82.  
  83.     public void run() {
  84.     Thread me = Thread.currentThread();
  85.     boolean needsRepaint = false;
  86.     while (kicker == me && cls.getLevel() < fractLevel) {
  87.         cls.generate();
  88.         if (kicker == me && incrementalUpdates) {
  89.         repaint();
  90.         try {Thread.sleep(repaintDelay);} catch (InterruptedException e){}
  91.         } else {
  92.         needsRepaint = true;
  93.         }
  94.     }
  95.     if (kicker == me) {
  96.         kicker = null;
  97.         if (needsRepaint) {
  98.         repaint();
  99.         }
  100.     }
  101.     }
  102.  
  103.     public void start() {
  104.     kicker = new Thread(this);
  105.     kicker.start();
  106.     }
  107.  
  108.     public void stop() {
  109.     kicker = null;
  110.     }
  111.  
  112.     public boolean mouseUp(java.awt.Event evt, int x, int y) {
  113.     cls = new ContextLSystem(this);
  114.     savedPath = null;
  115.     start();
  116.     return true;
  117.     }
  118.  
  119.     String savedPath;
  120.  
  121.     public void paint(Graphics g) {
  122.     String fractalPath = cls.getPath();
  123.     if (fractalPath == null) {
  124.         super.paint(g);
  125.         return;
  126.     }
  127.     if (savedPath == null || !savedPath.equals(fractalPath)) {
  128.         savedPath = fractalPath;
  129.         render(null, fractalPath);
  130.     }
  131.  
  132.     for (int i = 0; i < border; i++) {
  133.         g.draw3DRect(i, i, size().width - i * 2, size().height - i * 2,false);
  134.     }
  135.     render(g, fractalPath);
  136.     }
  137.  
  138.     void render(Graphics g, String path) {
  139.     Stack turtleStack = new Stack();
  140.     CLSTurtle turtle;
  141.  
  142.     if (g == null) {
  143.         Xmin = 1E20f;
  144.         Ymin = 1E20f;
  145.         Xmax = -1E20f;
  146.         Ymax = -1E20f;
  147.         turtle = new CLSTurtle(startAngle, 0, 0, 0, 0, 1, 1);
  148.     } else {
  149.         float frwidth = Xmax - Xmin;
  150.         if (frwidth == 0)
  151.         frwidth = 1;
  152.         float frheight = Ymax - Ymin;
  153.         if (frheight == 0)
  154.         frheight = 1;
  155.         float xscale = (size().width - border * 2 - 1) / frwidth;
  156.         float yscale = (size().height - border * 2 - 1) / frheight;
  157.         int xoff = border;
  158.         int yoff = border;
  159.         if (normalizescaling) {
  160.         if (xscale < yscale) {
  161.             yoff += ((size().height - border * 2)
  162.                  - ((Ymax - Ymin) * xscale)) / 2;
  163.             yscale = xscale;
  164.         } else if (yscale < xscale) {
  165.             xoff += ((size().width - border * 2)
  166.                  - ((Xmax - Xmin) * yscale)) / 2;
  167.             xscale = yscale;
  168.         }
  169.         }
  170.         turtle = new CLSTurtle(startAngle, 0 - Xmin, 0 - Ymin,
  171.                    xoff, yoff, xscale, yscale);
  172.     }
  173.  
  174.     for (int pos = 0; pos < path.length(); pos++) {
  175.         switch (path.charAt(pos)) {
  176.         case '+':
  177.         turtle.rotate(rotAngle);
  178.         break;
  179.         case '-':
  180.         turtle.rotate(-rotAngle);
  181.         break;
  182.         case '[':
  183.         turtleStack.push(turtle);
  184.         turtle = new CLSTurtle(turtle);
  185.         break;
  186.         case ']':
  187.         turtle = (CLSTurtle) turtleStack.pop();
  188.         break;
  189.         case 'f':
  190.         turtle.jump();
  191.         break;
  192.         case 'F':
  193.         if (g == null) {
  194.             includePt(turtle.X, turtle.Y);
  195.             turtle.jump();
  196.             includePt(turtle.X, turtle.Y);
  197.         } else {
  198.             turtle.draw(g);
  199.         }
  200.         break;
  201.         default:
  202.         break;
  203.         }
  204.     }
  205.     }
  206.  
  207.     void includePt(float x, float y) {
  208.     if (x < Xmin)
  209.         Xmin = x;
  210.     if (x > Xmax)
  211.         Xmax = x;
  212.     if (y < Ymin)
  213.         Ymin = y;
  214.     if (y > Ymax)
  215.         Ymax = y;
  216.     }
  217. }
  218.  
  219. /**
  220.  * A Logo turtle class designed to support Context sensitive L-Systems.
  221.  *
  222.  * This turtle performs a few basic maneuvers needed to support the
  223.  * set of characters used in Context sensitive L-Systems "+-fF[]".
  224.  *
  225.  * @author     Jim Graham
  226.  * @version     1.1f, 27 Mar 1995
  227.  */
  228. class CLSTurtle {
  229.     float angle;
  230.     float X;
  231.     float Y;
  232.     float scaleX;
  233.     float scaleY;
  234.     int xoff;
  235.     int yoff;
  236.  
  237.     public CLSTurtle(float ang, float x, float y,
  238.              int xorg, int yorg, float sx, float sy) {
  239.     angle = ang;
  240.     scaleX = sx;
  241.     scaleY = sy;
  242.     X = x * sx;
  243.     Y = y * sy;
  244.     xoff = xorg;
  245.     yoff = yorg;
  246.     }
  247.  
  248.     public CLSTurtle(CLSTurtle turtle) {
  249.     angle = turtle.angle;
  250.     X = turtle.X;
  251.     Y = turtle.Y;
  252.     scaleX = turtle.scaleX;
  253.     scaleY = turtle.scaleY;
  254.     xoff = turtle.xoff;
  255.     yoff = turtle.yoff;
  256.     }
  257.  
  258.     public void rotate(float theta) {
  259.     angle += theta;
  260.     }
  261.  
  262.     public void jump() {
  263.     X += (float) Math.cos(angle) * scaleX;
  264.     Y += (float) Math.sin(angle) * scaleY;
  265.     }
  266.  
  267.     public void draw(Graphics g) {
  268.     float x = X + (float) Math.cos(angle) * scaleX;
  269.     float y = Y + (float) Math.sin(angle) * scaleY;
  270.     g.drawLine((int) X + xoff, (int) Y + yoff,
  271.            (int) x + xoff, (int) y + yoff);
  272.     X = x;
  273.     Y = y;
  274.     }
  275. }
  276.  
  277. /**
  278.  * A (non-)Context sensitive L-System class.
  279.  *
  280.  * This class initializes the rules for Context sensitive L-Systems
  281.  * (pred, succ, lContext, rContext) from the given java.applet.Applet's attributes.
  282.  * The generate() method, however, does not (yet) apply the lContext
  283.  * and rContext parts of the rules.
  284.  *
  285.  * @author     Jim Graham
  286.  * @version     1.1f, 27 Mar 1995
  287.  */
  288. class ContextLSystem {
  289.     String axiom;
  290.     Vector rules = new Vector();
  291.     int level;
  292.  
  293.     public ContextLSystem(java.applet.Applet app) {
  294.     axiom = app.getParameter("axiom");
  295.     int num = 1;
  296.     while (true) {
  297.         String pred = app.getParameter("pred"+num);
  298.         String succ = app.getParameter("succ"+num);
  299.         if (pred == null || succ == null) {
  300.         break;
  301.         }
  302.         rules.addElement(new CLSRule(pred, succ,
  303.                      app.getParameter("lContext"+num),
  304.                      app.getParameter("rContext"+num)));
  305.         num++;
  306.     }
  307.     currentPath = new StringBuffer(axiom);
  308.     level = 0;
  309.     }
  310.  
  311.     public int getLevel() {
  312.     return level;
  313.     }
  314.  
  315.     StringBuffer currentPath;
  316.  
  317.     public synchronized String getPath() {
  318.     return ((currentPath == null) ? null : currentPath.toString());
  319.     }
  320.  
  321.     private synchronized void setPath(StringBuffer path) {
  322.     currentPath = path;
  323.     level++;
  324.     }
  325.  
  326.     public void generate() {
  327.     StringBuffer newPath = new StringBuffer();
  328.     int pos = 0;
  329.     while (pos < currentPath.length()) {
  330.         CLSRule rule = findRule(pos);
  331.         if (rule == null) {
  332.         newPath.append(currentPath.charAt(pos));
  333.         pos++;
  334.         } else {
  335.         newPath.append(rule.succ);
  336.         pos += rule.pred.length();
  337.         }
  338.     }
  339.     setPath(newPath);
  340.     }
  341.  
  342.     public CLSRule findRule(int pos) {
  343.     for (int i = 0; i < rules.size(); i++) {
  344.         CLSRule rule = (CLSRule) rules.elementAt(i);
  345.         if (rule.matches(currentPath, pos)) {
  346.         return rule;
  347.         }
  348.     }
  349.     return null;
  350.     }
  351. }
  352.  
  353. /**
  354.  * A Context sensitive L-System production rule.
  355.  *
  356.  * This class encapsulates a production rule for a Context sensitive
  357.  * L-System (pred, succ, lContext, rContext).
  358.  * The matches() method, however, does not (yet) verify the lContext
  359.  * and rContext parts of the rule.
  360.  *
  361.  * @author     Jim Graham
  362.  * @version     1.1f, 27 Mar 1995
  363.  */
  364. class CLSRule {
  365.     String pred;
  366.     String succ;
  367.     String lContext;
  368.     String rContext;
  369.  
  370.     public CLSRule(String p, String d, String l, String r) {
  371.     pred = p;
  372.     succ = d;
  373.     lContext = l;
  374.     rContext = r;
  375.     }
  376.  
  377.     public boolean matches(StringBuffer sb, int pos) {
  378.     if (pos + pred.length() > sb.length()) {
  379.         return false;
  380.     }
  381.     char cb[] = new char[pred.length()];
  382.     sb.getChars(pos, pos + pred.length(), cb, 0);
  383.     return pred.equals(new String(cb));
  384.     }
  385. }
  386.