/*
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);
}
}