/* Author: James Pate Williams, Jr. Stochastic L-System to draw a plant. See "Simulating Plant Growth" by Marco Grubert, Crossroads, the ACM Student Magazine Issue 8.2, Winter 2001, pages 20-27. */ import java.awt.*; import java.awt.event.*; import java.lang.*; import java.util.*; import javax.swing.*; class Cursor { private double factor, rTheta; private int height, theta, width, x, x0, y, y0; public Cursor() { } public Cursor(int w, int h) { width = w; height = h; factor = Math.PI / 180.0; theta = 270; rTheta = factor * theta; x0 = width / 2; y0 = height; x = 0; y = 0; } public Cursor(int iw, int ih, int iTheta, int ix, int iy) { width = iw; height = ih; theta = iTheta; factor = Math.PI / 180.0; rTheta = factor * theta; x0 = width / 2; y0 = height; x = ix; y = iy; } public void F(Graphics g, int n) { double nX = n * Math.cos(rTheta) + x, nY = n * Math.sin(rTheta) + y; int X = x, Y = y; x = (int) nX; y = (int) nY; g.drawLine(X + x0, Y + y0, x + x0, y + y0); } public void f(Graphics g, int n) { double nX = n * Math.cos(rTheta) + x, nY = n * Math.sin(rTheta) + y; x = (int) nX; y = (int) nY; g.translate(x + x0, y + y0); } public void plus(int alpha) { theta = (theta - alpha) % 360; if (theta < 0) theta += 360; rTheta = factor * theta; } public void minus(int alpha) { theta = (theta + alpha) % 360; if (theta < 0) theta += 360; rTheta = factor * theta; } public void exclamation() { theta = (theta + 180) % 360; if (theta < 0) theta += 360; rTheta = factor * theta; } public int getWidth() { return width; } public int getHeight() { return height; } public int getTheta() { return theta; } public int getX() { return x; } public int getY() { return y; } public int getX0() { return x0; } public int getY0() { return y0; } } class PlantPanel extends JPanel { int depth; Cursor cursor = null; Random random = null; public PlantPanel(int iDepth, int iWidth, int iHeight, int seed) { depth = iDepth; cursor = new Cursor(iWidth, iHeight); random = new Random(seed); } public void lSystem1(Graphics g, int d, int depth, int n, int width, int height, int theta, int x, int y) { int alpha = 20; Cursor cursor = new Cursor(width, height, theta, x, y); Cursor stackCursor = null; if (d == depth) return; cursor.F(g, n); theta = cursor.getTheta(); x = cursor.getX(); y = cursor.getY(); lSystem0(g, d + 1, depth, n / 2, width, height, theta, x, y); stackCursor = new Cursor(cursor.getWidth(), cursor.getHeight(), cursor.getTheta(), cursor.getX(), cursor.getY()); stackCursor.plus(alpha); stackCursor.F(g, n); theta = stackCursor.getTheta(); x = stackCursor.getX(); y = stackCursor.getY(); lSystem0(g, d + 1, depth, n / 2, width, height, theta, x, y); cursor.F(g, n); theta = cursor.getTheta(); x = cursor.getX(); y = cursor.getY(); lSystem0(g, d + 1, depth, n / 2, width, height, theta, x, y); stackCursor = new Cursor(cursor.getWidth(), cursor.getHeight(), cursor.getTheta(), cursor.getX(), cursor.getY()); stackCursor.minus(alpha); stackCursor.F(g, n); theta = stackCursor.getTheta(); x = stackCursor.getX(); y = stackCursor.getY(); lSystem0(g, d + 1, depth, n / 2, width, height, theta, x, y); cursor.F(g, n); theta = cursor.getTheta(); x = cursor.getX(); y = cursor.getY(); lSystem0(g, d + 1, depth, n / 2, width, height, theta, x, y); } public void lSystem2(Graphics g, int d, int depth, int n, int width, int height, int theta, int x, int y) { int alpha = 20; Cursor cursor = new Cursor(width, height, theta, x, y); Cursor stackCursor = null; if (d == depth) return; cursor.F(g, n); theta = cursor.getTheta(); x = cursor.getX(); y = cursor.getY(); lSystem0(g, d + 1, depth, n / 2, width, height, theta, x, y); stackCursor = new Cursor(cursor.getWidth(), cursor.getHeight(), cursor.getTheta(), cursor.getX(), cursor.getY()); stackCursor.plus(alpha); stackCursor.F(g, n); theta = stackCursor.getTheta(); x = stackCursor.getX(); y = stackCursor.getY(); lSystem0(g, d + 1, depth, n / 2, width, height, theta, x, y); cursor.F(g, n); theta = cursor.getTheta(); x = cursor.getX(); y = cursor.getY(); lSystem0(g, d + 1, depth, n / 2, width, height, theta, x, y); } public void lSystem3(Graphics g, int d, int depth, int n, int width, int height, int theta, int x, int y) { int alpha = 20; Cursor cursor = new Cursor(width, height, theta, x, y); Cursor stackCursor = null; if (d == depth) return; cursor.F(g, n); theta = cursor.getTheta(); x = cursor.getX(); y = cursor.getY(); lSystem0(g, d + 1, depth, n / 2, width, height, theta, x, y); stackCursor = new Cursor(cursor.getWidth(), cursor.getHeight(), cursor.getTheta(), cursor.getX(), cursor.getY()); stackCursor.minus(alpha); stackCursor.F(g, n); theta = stackCursor.getTheta(); x = stackCursor.getX(); y = stackCursor.getY(); lSystem0(g, d + 1, depth, n / 2, width, height, theta, x, y); } public void lSystem0(Graphics g, int d, int depth, int n, int width, int height, int theta, int x, int y) { double r = random.nextDouble(); if (d == depth) return; if (r <= 0.33) lSystem1(g, d, depth, n, width, height, theta, x, y); else if (r <= 0.66) lSystem2(g, d, depth, n, width, height, theta, x, y); else lSystem3(g, d, depth, n, width, height, theta, x, y); theta = cursor.getTheta(); x = cursor.getX(); y = cursor.getY(); lSystem0(g, d + 1, depth, n / 2, width, height, theta, x, y); } public void lSystem(Graphics g, int d, int depth, int n, int width, int height, int theta, int x, int y) { lSystem0(g, d, depth, n, width, height, theta, x, y); } public void paintComponent(Graphics g) { int n = 120; int width = cursor.getWidth(), height = cursor.getHeight(); int theta = cursor.getTheta(), x0 = cursor.getX0(), y0 = cursor.getY0(); lSystem(g, 0, depth, n, width, height, theta, 0, 0); } } class PlantFrame extends JFrame { int iHeight, iWidth; PlantPanel plantPanel; // step 3 - percentage size the window void setDesktopSize(JFrame frame, int wPerc, int hPerc) { Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); iWidth = screen.width * wPerc / 100; iHeight = screen.height * hPerc / 100; frame.setSize(iWidth, iHeight); } // step 4 - center the window void centerOnScreen(JFrame frame) { Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); Dimension window = frame.getSize(); int iCenterX = screen.width / 2; int iCenterY = screen.height / 2; frame.setLocation(iCenterX - window.width / 2, iCenterY - window.height / 2); } public PlantFrame(int depth, int seed) { String title = "Plant by James Pate Williams, Jr. (c) 2001"; setTitle(title); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent event) { System.exit(0); } }); setDesktopSize(this, 100, 100); centerOnScreen(this); Container contentPane = getContentPane(); plantPanel = new PlantPanel(depth, iWidth, iHeight, seed); contentPane.add(plantPanel, BorderLayout.CENTER); this.show(); } } class Plant { public static void main(String[] args) { if (args.length != 2) { System.out.println("usage: java Plant depth seed"); System.out.println("where 5 <= depth <= 8 and seed >= 1"); System.exit(0); } int depth = (new Integer(args[0])). intValue(); if (depth < 5 || depth > 8) { System.out.println("depth not in range 5 <= depth <= 8!"); System.exit(0); } int seed = (new Integer(args[1])).intValue(); if (seed < 1) { System.out.println("seed must be >= 1"); System.exit(0); } PlantFrame plantFrame = new PlantFrame(depth, seed); } }