jdk/src/share/demo/applets/Fractal/CLSFractal.java
changeset 8980 2adf3601083f
parent 5506 202f599c92aa
child 10292 ed7db6a12c2a
equal deleted inserted replaced
8979:30050c8aea19 8980:2adf3601083f
     1 /*
     1 /*
     2  * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
     3  *
     3  *
     4  * Redistribution and use in source and binary forms, with or without
     4  * Redistribution and use in source and binary forms, with or without
     5  * modification, are permitted provided that the following conditions
     5  * modification, are permitted provided that the following conditions
     6  * are met:
     6  * are met:
     7  *
     7  *
    27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
    27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
    28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    30  */
    30  */
    31 
    31 
    32 /*
       
    33  */
       
    34 
    32 
    35 import java.awt.Graphics;
    33 import java.awt.Graphics;
    36 import java.util.Stack;
    34 import java.util.Stack;
    37 import java.util.Vector;
       
    38 import java.awt.event.*;
    35 import java.awt.event.*;
       
    36 import java.util.ArrayList;
       
    37 import java.util.List;
       
    38 
    39 
    39 
    40 /**
    40 /**
    41  * A (not-yet) Context sensitive L-System Fractal applet class.
    41  * A (not-yet) Context sensitive L-System Fractal applet class.
    42  *
    42  *
    43  * The rules for the Context L-system are read from the java.applet.Applet's
    43  * The rules for the Context L-system are read from the java.applet.Applet's
    48  * class is already designed to parse the '[' and ']' characters
    48  * class is already designed to parse the '[' and ']' characters
    49  * typically used in Context sensitive L-Systems.
    49  * typically used in Context sensitive L-Systems.
    50  *
    50  *
    51  * @author      Jim Graham
    51  * @author      Jim Graham
    52  */
    52  */
       
    53 @SuppressWarnings("serial")
    53 public class CLSFractal
    54 public class CLSFractal
    54     extends java.applet.Applet
    55         extends java.applet.Applet
    55     implements Runnable, MouseListener {
    56         implements Runnable, MouseListener {
       
    57 
    56     Thread kicker;
    58     Thread kicker;
    57     ContextLSystem cls;
    59     ContextLSystem cls;
    58     int fractLevel = 1;
    60     int fractLevel = 1;
    59     int repaintDelay = 50;
    61     int repaintDelay = 50;
    60     boolean incrementalUpdates;
    62     boolean incrementalUpdates;
    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) {
   110                 repaint();
   132                 repaint();
   111             }
   133             }
   112         }
   134         }
   113     }
   135     }
   114 
   136 
       
   137     @Override
   115     public void start() {
   138     public void start() {
   116         kicker = new Thread(this);
   139         kicker = new Thread(this);
   117         kicker.start();
   140         kicker.start();
   118     }
   141     }
   119 
   142 
       
   143     @Override
   120     public void stop() {
   144     public void stop() {
   121         kicker = null;
   145         kicker = null;
   122     }
   146     }
   123 
   147 
   124       /*1.1 event handling */
   148     /*1.1 event handling */
       
   149     @Override
   125     public void mouseClicked(MouseEvent e) {
   150     public void mouseClicked(MouseEvent e) {
   126     }
   151     }
   127 
   152 
       
   153     @Override
   128     public void mousePressed(MouseEvent e) {
   154     public void mousePressed(MouseEvent e) {
   129     }
   155     }
   130 
   156 
       
   157     @Override
   131     public void mouseReleased(MouseEvent e) {
   158     public void mouseReleased(MouseEvent e) {
   132         cls = new ContextLSystem(this);
   159         cls = new ContextLSystem(this);
   133         savedPath = null;
   160         savedPath = null;
   134         start();
   161         start();
   135         e.consume();
   162         e.consume();
   136     }
   163     }
   137 
   164 
       
   165     @Override
   138     public void mouseEntered(MouseEvent e) {
   166     public void mouseEntered(MouseEvent e) {
   139     }
   167     }
   140 
   168 
       
   169     @Override
   141     public void mouseExited(MouseEvent e) {
   170     public void mouseExited(MouseEvent e) {
   142     }
   171     }
   143 
       
   144     String savedPath;
   172     String savedPath;
   145 
   173 
       
   174     @Override
   146     public void paint(Graphics g) {
   175     public void paint(Graphics g) {
   147         String fractalPath = cls.getPath();
   176         String fractalPath = cls.getPath();
   148         if (fractalPath == null) {
   177         if (fractalPath == null) {
   149             super.paint(g);
   178             super.paint(g);
   150             return;
   179             return;
   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;
   311 
   362 
   312     public void draw(Graphics g) {
   363     public void draw(Graphics g) {
   313         float x = X + (float) Math.cos(angle) * scaleX;
   364         float x = X + (float) Math.cos(angle) * scaleX;
   314         float y = Y + (float) Math.sin(angle) * scaleY;
   365         float y = Y + (float) Math.sin(angle) * scaleY;
   315         g.drawLine((int) X + xoff, (int) Y + yoff,
   366         g.drawLine((int) X + xoff, (int) Y + yoff,
   316                    (int) x + xoff, (int) y + yoff);
   367                 (int) x + xoff, (int) y + yoff);
   317         X = x;
   368         X = x;
   318         Y = y;
   369         Y = y;
   319     }
   370     }
   320 }
   371 }
       
   372 
   321 
   373 
   322 /**
   374 /**
   323  * A (non-)Context sensitive L-System class.
   375  * A (non-)Context sensitive L-System class.
   324  *
   376  *
   325  * This class initializes the rules for Context sensitive L-Systems
   377  * This class initializes the rules for Context sensitive L-Systems
   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     }
   383         setPath(newPath);
   435         setPath(newPath);
   384     }
   436     }
   385 
   437 
   386     public CLSRule findRule(int pos) {
   438     public CLSRule findRule(int pos) {
   387         for (int i = 0; i < rules.size(); i++) {
   439         for (int i = 0; i < rules.size(); i++) {
   388             CLSRule rule = (CLSRule) rules.elementAt(i);
   440             CLSRule rule = rules.get(i);
   389             if (rule.matches(currentPath, pos)) {
   441             if (rule.matches(currentPath, pos)) {
   390                 return rule;
   442                 return rule;
   391             }
   443             }
   392         }
   444         }
   393         return null;
   445         return null;
   394     }
   446     }
   395 }
   447 }
       
   448 
   396 
   449 
   397 /**
   450 /**
   398  * A Context sensitive L-System production rule.
   451  * A Context sensitive L-System production rule.
   399  *
   452  *
   400  * This class encapsulates a production rule for a Context sensitive
   453  * This class encapsulates a production rule for a Context sensitive
   403  * and rContext parts of the rule.
   456  * and rContext parts of the rule.
   404  *
   457  *
   405  * @author      Jim Graham
   458  * @author      Jim Graham
   406  */
   459  */
   407 class CLSRule {
   460 class CLSRule {
       
   461 
   408     String pred;
   462     String pred;
   409     String succ;
   463     String succ;
   410     String lContext;
   464     String lContext;
   411     String rContext;
   465     String rContext;
   412 
   466