home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / JBuilder8.iso / Solaris / resource / jre / demo / plugin / applets / Fractal / CLSFractal.java < prev    next >
Encoding:
Java Source  |  2002-09-06  |  11.8 KB  |  438 lines

  1. /*
  2.  * Copyright (c) 2002 Sun Microsystems, Inc. All  Rights Reserved.
  3.  * 
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions
  6.  * are met:
  7.  * 
  8.  * -Redistributions of source code must retain the above copyright
  9.  *  notice, this list of conditions and the following disclaimer.
  10.  * 
  11.  * -Redistribution in binary form must reproduct the above copyright
  12.  *  notice, this list of conditions and the following disclaimer in
  13.  *  the documentation and/or other materials provided with the distribution.
  14.  * 
  15.  * Neither the name of Sun Microsystems, Inc. or the names of contributors
  16.  * may be used to endorse or promote products derived from this software
  17.  * without specific prior written permission.
  18.  * 
  19.  * This software is provided "AS IS," without a warranty of any kind. ALL
  20.  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
  21.  * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
  22.  * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT
  23.  * BE LIABLE FOR ANY DAMAGES OR LIABILITIES SUFFERED BY LICENSEE AS A RESULT
  24.  * OF OR RELATING TO USE, MODIFICATION OR DISTRIBUTION OF THE SOFTWARE OR ITS
  25.  * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
  26.  * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
  27.  * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
  28.  * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN
  29.  * IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
  30.  * 
  31.  * You acknowledge that Software is not designed, licensed or intended for
  32.  * use in the design, construction, operation or maintenance of any nuclear
  33.  * facility.
  34.  */
  35.  
  36. /*
  37.  * @(#)CLSFractal.java    1.9 02/06/13
  38.  */
  39.  
  40. import java.awt.Graphics;
  41. import java.util.Stack;
  42. import java.util.Vector;
  43. import java.awt.event.*;
  44.  
  45. /**
  46.  * A (not-yet) Context sensitive L-System Fractal applet class.
  47.  *
  48.  * The rules for the Context L-system are read from the java.applet.Applet's
  49.  * attributes and then the system is iteratively applied for the
  50.  * given number of levels, possibly drawing each generation as it
  51.  * is generated.  Note that the ContextLSystem class does not yet
  52.  * handle the lContext and rContext attributes, although this
  53.  * class is already designed to parse the '[' and ']' characters
  54.  * typically used in Context sensitive L-Systems.
  55.  *
  56.  * @author     Jim Graham
  57.  * @version     1.1f, 27 Mar 1995
  58.  */
  59. public class CLSFractal
  60.     extends java.applet.Applet
  61.     implements Runnable, MouseListener {
  62.     Thread kicker;
  63.     ContextLSystem cls;
  64.     int fractLevel = 1;
  65.     int repaintDelay = 50;
  66.     boolean incrementalUpdates;
  67.     float startAngle = 0;
  68.     float rotAngle = 45;
  69.     float Xmin;
  70.     float Xmax;
  71.     float Ymin;
  72.     float Ymax;
  73.     int border;
  74.     boolean normalizescaling;
  75.  
  76.     public void init() {
  77.     String s;
  78.     cls = new ContextLSystem(this);
  79.     s = getParameter("level");
  80.     if (s != null) fractLevel = Integer.parseInt(s);
  81.     s = getParameter("incremental");
  82.     if (s != null) incrementalUpdates = s.equalsIgnoreCase("true");
  83.     s = getParameter("delay");
  84.     if (s != null) repaintDelay = Integer.parseInt(s);
  85.     s = getParameter("startAngle");
  86.     if (s != null) startAngle = Float.valueOf(s).floatValue();
  87.     s = getParameter("rotAngle");
  88.     if (s != null) rotAngle = Float.valueOf(s).floatValue();
  89.     rotAngle = rotAngle / 360 * 2 * 3.14159265358f;
  90.     s = getParameter("border");
  91.     if (s != null) border = Integer.parseInt(s);
  92.     s = getParameter("normalizescale");
  93.     if (s != null) normalizescaling = s.equalsIgnoreCase("true");
  94.     addMouseListener(this);
  95.     }
  96.  
  97.     public void destroy() {
  98.         removeMouseListener(this);
  99.     }
  100.  
  101.     public void run() {
  102.     Thread me = Thread.currentThread();
  103.     boolean needsRepaint = false;
  104.     while (kicker == me && cls.getLevel() < fractLevel) {
  105.         cls.generate();
  106.         if (kicker == me && incrementalUpdates) {
  107.         repaint();
  108.         try {Thread.sleep(repaintDelay);} catch (InterruptedException e){}
  109.         } else {
  110.         needsRepaint = true;
  111.         }
  112.     }
  113.     if (kicker == me) {
  114.         kicker = null;
  115.         if (needsRepaint) {
  116.         repaint();
  117.         }
  118.     }
  119.     }
  120.  
  121.     public void start() {
  122.     kicker = new Thread(this);
  123.     kicker.start();
  124.     }
  125.  
  126.     public void stop() {
  127.     kicker = null;
  128.     }
  129.  
  130.       /*1.1 event handling */
  131.     public void mouseClicked(MouseEvent e) {
  132.     }
  133.  
  134.     public void mousePressed(MouseEvent e) {
  135.     }
  136.  
  137.     public void mouseReleased(MouseEvent e) {
  138.         cls = new ContextLSystem(this);
  139.         savedPath = null;
  140.         start();
  141.         e.consume();
  142.     }
  143.  
  144.     public void mouseEntered(MouseEvent e) {
  145.     }
  146.  
  147.     public void mouseExited(MouseEvent e) {
  148.     }
  149.  
  150.     String savedPath;
  151.  
  152.     public void paint(Graphics g) {
  153.     String fractalPath = cls.getPath();
  154.     if (fractalPath == null) {
  155.         super.paint(g);
  156.         return;
  157.     }
  158.     if (savedPath == null || !savedPath.equals(fractalPath)) {
  159.         savedPath = fractalPath;
  160.         render(null, fractalPath);
  161.     }
  162.  
  163.     for (int i = 0; i < border; i++) {
  164.         g.draw3DRect(i, i, getSize().width - i * 2, getSize().height - i * 2,false);
  165.     }
  166.     render(g, fractalPath);
  167.     }
  168.  
  169.     void render(Graphics g, String path) {
  170.     Stack turtleStack = new Stack();
  171.     CLSTurtle turtle;
  172.  
  173.     if (g == null) {
  174.         Xmin = 1E20f;
  175.         Ymin = 1E20f;
  176.         Xmax = -1E20f;
  177.         Ymax = -1E20f;
  178.         turtle = new CLSTurtle(startAngle, 0, 0, 0, 0, 1, 1);
  179.     } else {
  180.         float frwidth = Xmax - Xmin;
  181.         if (frwidth == 0)
  182.         frwidth = 1;
  183.         float frheight = Ymax - Ymin;
  184.         if (frheight == 0)
  185.         frheight = 1;
  186.         float xscale = (getSize().width - border * 2 - 1) / frwidth;
  187.         float yscale = (getSize().height - border * 2 - 1) / frheight;
  188.         int xoff = border;
  189.         int yoff = border;
  190.         if (normalizescaling) {
  191.         if (xscale < yscale) {
  192.             yoff += ((getSize().height - border * 2)
  193.                  - ((Ymax - Ymin) * xscale)) / 2;
  194.             yscale = xscale;
  195.         } else if (yscale < xscale) {
  196.             xoff += ((getSize().width - border * 2)
  197.                  - ((Xmax - Xmin) * yscale)) / 2;
  198.             xscale = yscale;
  199.         }
  200.         }
  201.         turtle = new CLSTurtle(startAngle, 0 - Xmin, 0 - Ymin,
  202.                    xoff, yoff, xscale, yscale);
  203.     }
  204.  
  205.     for (int pos = 0; pos < path.length(); pos++) {
  206.         switch (path.charAt(pos)) {
  207.         case '+':
  208.         turtle.rotate(rotAngle);
  209.         break;
  210.         case '-':
  211.         turtle.rotate(-rotAngle);
  212.         break;
  213.         case '[':
  214.         turtleStack.push(turtle);
  215.         turtle = new CLSTurtle(turtle);
  216.         break;
  217.         case ']':
  218.         turtle = (CLSTurtle) turtleStack.pop();
  219.         break;
  220.         case 'f':
  221.         turtle.jump();
  222.         break;
  223.         case 'F':
  224.         if (g == null) {
  225.             includePt(turtle.X, turtle.Y);
  226.             turtle.jump();
  227.             includePt(turtle.X, turtle.Y);
  228.         } else {
  229.             turtle.draw(g);
  230.         }
  231.         break;
  232.         default:
  233.         break;
  234.         }
  235.     }
  236.     }
  237.  
  238.     void includePt(float x, float y) {
  239.     if (x < Xmin)
  240.         Xmin = x;
  241.     if (x > Xmax)
  242.         Xmax = x;
  243.     if (y < Ymin)
  244.         Ymin = y;
  245.     if (y > Ymax)
  246.         Ymax = y;
  247.     }
  248.  
  249.   public String getAppletInfo() {
  250.     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.";
  251.   }
  252.  
  253.   public String[][] getParameterInfo() {
  254.     String[][] info = {
  255.       {"level", "int", "Maximum number of recursions.  Default is 1."},
  256.       {"incremental","boolean","Whether or not to repaint between recursions.  Default is true."},
  257.       {"delay","integer","Sets delay between repaints.  Default is 50."},
  258.       {"startAngle","float","Sets the starting angle.  Default is 0."},
  259.       {"rotAngle","float","Sets the rotation angle.  Default is 45."},
  260.       {"border","integer","Width of border.  Default is 2."},
  261.       {"normalizeScale","boolean","Whether or not to normalize the scaling.  Default is true."},
  262.       {"pred","String","Initializes the rules for Context Sensitive L-Systems."},
  263.       {"succ","String","Initializes the rules for Context Sensitive L-Systems."},
  264.       {"lContext","String","Initializes the rules for Context Sensitive L-Systems."},
  265.       {"rContext","String","Initializes the rules for Context Sensitive L-Systems."}
  266.     };
  267.     return info;
  268.   }
  269. }
  270.  
  271. /**
  272.  * A Logo turtle class designed to support Context sensitive L-Systems.
  273.  *
  274.  * This turtle performs a few basic maneuvers needed to support the
  275.  * set of characters used in Context sensitive L-Systems "+-fF[]".
  276.  *
  277.  * @author     Jim Graham
  278.  * @version     1.1f, 27 Mar 1995
  279.  */
  280. class CLSTurtle {
  281.     float angle;
  282.     float X;
  283.     float Y;
  284.     float scaleX;
  285.     float scaleY;
  286.     int xoff;
  287.     int yoff;
  288.  
  289.     public CLSTurtle(float ang, float x, float y,
  290.              int xorg, int yorg, float sx, float sy) {
  291.     angle = ang;
  292.     scaleX = sx;
  293.     scaleY = sy;
  294.     X = x * sx;
  295.     Y = y * sy;
  296.     xoff = xorg;
  297.     yoff = yorg;
  298.     }
  299.  
  300.     public CLSTurtle(CLSTurtle turtle) {
  301.     angle = turtle.angle;
  302.     X = turtle.X;
  303.     Y = turtle.Y;
  304.     scaleX = turtle.scaleX;
  305.     scaleY = turtle.scaleY;
  306.     xoff = turtle.xoff;
  307.     yoff = turtle.yoff;
  308.     }
  309.  
  310.     public void rotate(float theta) {
  311.     angle += theta;
  312.     }
  313.  
  314.     public void jump() {
  315.     X += (float) Math.cos(angle) * scaleX;
  316.     Y += (float) Math.sin(angle) * scaleY;
  317.     }
  318.  
  319.     public void draw(Graphics g) {
  320.     float x = X + (float) Math.cos(angle) * scaleX;
  321.     float y = Y + (float) Math.sin(angle) * scaleY;
  322.     g.drawLine((int) X + xoff, (int) Y + yoff,
  323.            (int) x + xoff, (int) y + yoff);
  324.     X = x;
  325.     Y = y;
  326.     }
  327. }
  328.  
  329. /**
  330.  * A (non-)Context sensitive L-System class.
  331.  *
  332.  * This class initializes the rules for Context sensitive L-Systems
  333.  * (pred, succ, lContext, rContext) from the given java.applet.Applet's attributes.
  334.  * The generate() method, however, does not (yet) apply the lContext
  335.  * and rContext parts of the rules.
  336.  *
  337.  * @author     Jim Graham
  338.  * @version     1.1f, 27 Mar 1995
  339.  */
  340. class ContextLSystem {
  341.     String axiom;
  342.     Vector rules = new Vector();
  343.     int level;
  344.  
  345.     public ContextLSystem(java.applet.Applet app) {
  346.     axiom = app.getParameter("axiom");
  347.     int num = 1;
  348.     while (true) {
  349.         String pred = app.getParameter("pred"+num);
  350.         String succ = app.getParameter("succ"+num);
  351.         if (pred == null || succ == null) {
  352.         break;
  353.         }
  354.         rules.addElement(new CLSRule(pred, succ,
  355.                      app.getParameter("lContext"+num),
  356.                      app.getParameter("rContext"+num)));
  357.         num++;
  358.     }
  359.     currentPath = new StringBuffer(axiom);
  360.     level = 0;
  361.     }
  362.  
  363.     public int getLevel() {
  364.     return level;
  365.     }
  366.  
  367.     StringBuffer currentPath;
  368.  
  369.     public synchronized String getPath() {
  370.     return ((currentPath == null) ? null : currentPath.toString());
  371.     }
  372.  
  373.     private synchronized void setPath(StringBuffer path) {
  374.     currentPath = path;
  375.     level++;
  376.     }
  377.  
  378.     public void generate() {
  379.     StringBuffer newPath = new StringBuffer();
  380.     int pos = 0;
  381.     while (pos < currentPath.length()) {
  382.         CLSRule rule = findRule(pos);
  383.         if (rule == null) {
  384.         newPath.append(currentPath.charAt(pos));
  385.         pos++;
  386.         } else {
  387.         newPath.append(rule.succ);
  388.         pos += rule.pred.length();
  389.         }
  390.     }
  391.     setPath(newPath);
  392.     }
  393.  
  394.     public CLSRule findRule(int pos) {
  395.     for (int i = 0; i < rules.size(); i++) {
  396.         CLSRule rule = (CLSRule) rules.elementAt(i);
  397.         if (rule.matches(currentPath, pos)) {
  398.         return rule;
  399.         }
  400.     }
  401.     return null;
  402.     }
  403. }
  404.  
  405. /**
  406.  * A Context sensitive L-System production rule.
  407.  *
  408.  * This class encapsulates a production rule for a Context sensitive
  409.  * L-System (pred, succ, lContext, rContext).
  410.  * The matches() method, however, does not (yet) verify the lContext
  411.  * and rContext parts of the rule.
  412.  *
  413.  * @author     Jim Graham
  414.  * @version     1.1f, 27 Mar 1995
  415.  */
  416. class CLSRule {
  417.     String pred;
  418.     String succ;
  419.     String lContext;
  420.     String rContext;
  421.  
  422.     public CLSRule(String p, String d, String l, String r) {
  423.     pred = p;
  424.     succ = d;
  425.     lContext = l;
  426.     rContext = r;
  427.     }
  428.  
  429.     public boolean matches(StringBuffer sb, int pos) {
  430.     if (pos + pred.length() > sb.length()) {
  431.         return false;
  432.     }
  433.     char cb[] = new char[pred.length()];
  434.     sb.getChars(pos, pos + pred.length(), cb, 0);
  435.     return pred.equals(new String(cb));
  436.     }
  437. }
  438.