public class FractalPlants extends JFrame
2: import java.util.Scanner;
3: import java.awt.*;
4: import java.awt.image.BufferedImage;
5: import javax.swing.*;
7: /**
8: * My attempt to create the fractal plant described in
9: * http://en.wikipedia.org/wiki/Lindenmayer_system
10: *
11: * @author Mark Young
12: * @version 1.0
13: */
14: public class FractalPlants extends JFrame {
16: // default width for fern windows
17: public static final int DEFAULT_WIDTH = 800;
18: public static final int DEFAULT_HEIGHT = 600;
19: public static final int ANGLE_ADJUSTMENT = 25;
20: public static final double MIN_SIZE = 20.0;
22: // here is the program -- the class is below
23: public static void main(String[] args) {
24: Scanner kbd = new Scanner(System.in);
26: // introduce yourself
27: System.out.println("\n\n"
28: + "Plant Drawing Program\n"
29: + "---------------------\n\n");
31: // suggest values
32: System.out.println("Might I suggest:\n"
33: + "\tMake the window 500 by 600.\n"
34: + "\tPlace the root at 50 600.\n"
35: + "\tSet the angle to 160.\n"
36: + "\tMake the plant 550 pixels tall.\n");
38: // get window parameters (all windows the same size)
39: System.out.print("How big should the windows be (width height)? ");
40: int width = kbd.nextInt();
41: int height = kbd.nextInt();
42: kbd.nextLine();
43: if (width <= 0) {
44: width = DEFAULT_WIDTH;
45: }
46: if (height <= 0) {
47: height = DEFAULT_HEIGHT;
48: }
50: // repeat
51: String resp;
52: do {
53: // get root location
54: System.out.println();
55: System.out.print("Where should the root of the fern be? ");
56: int x = kbd.nextInt();
57: int y = kbd.nextInt();
58: kbd.nextLine();
60: // get angle of growth
61: System.out.print("What angle should the plant grow at "
62: + "(180 = straight up)? ");
63: int angle = kbd.nextInt();
64: kbd.nextLine();
66: // get fern size
67: System.out.print("And what height should the plant be? ");
68: int size = kbd.nextInt();
69: kbd.nextLine();
71: // draw that fern in a new window
72: FractalPlants win = new FractalPlants(width, height, x, y, angle, size);
73: win.setVisible(true);
75: // ask if there's more
76: System.out.print("another (y/n)> ");
77: resp = kbd.nextLine().toUpperCase();
78: } while (resp.startsWith("Y"));
79: System.exit(0);
80: }
82: // here is the class
83: private final BufferedImage img;
84: private final Graphics canvas;
85: private final int w, h;
86: private final double rootX, rootY;
87: private final double rootAngle;
88: private final double fullSize;
90: // constructor sets instance variables
91: /**
92: * Create a window and draw the plant in it.
93: *
94: * @param w width of the window
95: * @param h height of the window
96: * @param x x-coordinate of the plant's root
97: * @param y y-coordinate of the plant's root
98: * @param a angle the plant grows at
99: * @param s size of the plant (base to tip; approximate)
100: */
101: public FractalPlants(int w, int h, double x, double y, double a, double s) {
102: super("A Plant by MYoung");
103: setSize(w, h);
104: setBackground(Color.BLACK);
105: this.w = w;
106: this.h = h;
107: rootX = x;
108: rootY = y;
109: rootAngle = a;
110: fullSize = s;
111: img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
112: canvas = img.createGraphics();
113: canvas.setColor(Color.BLACK);
114: canvas.fillRect(0, 0, w, h);
115: canvas.setColor(new Color(0, 127, 0));
116: drawPlant(rootX, rootY, rootAngle, fullSize);
117: }
119: /**
120: * Respond to the computer's request to paint the window. This method is
121: * called when the computer shows the window.
122: *
123: * @param g the canvas provided by the computer
124: */
125: @Override
126: public void paint(Graphics g) {
127: g.drawImage(img,
128: 0, 0, w, h,
129: 0, 0, w, h,
130: null);
131: }
133: /**
134: * Draw the plant.
135: *
136: * @param x x-coordinate of the plant's root
137: * @param y y-coordinate of the plant's root
138: * @param angle angle the plant grows from its root
139: * @param size size of the plant
140: */
141: public void drawPlant(double x, double y, double angle, double size) {
142: // draw the stem of the plant
143: double length = size * 0.2;
144: double[] end = drawStem(x, y, angle, length);
146: // if more should be drawn...
147: if (size > MIN_SIZE) {
148: // ...draw more of the plant
149: double smaller = size * 0.5;
150: // a piece growing out of the stem at an angle
151: drawPlant(end[0], end[1], angle + ANGLE_ADJUSTMENT, smaller);
152: // a piece continuing in the same direction as the stem
153: drawPlant(end[0], end[1], angle, smaller);
154: // move up the stem
155: end = drawStem(end[0], end[1], angle, length);
156: // grow out of the stem at the opposite angle
157: end = drawStem(end[0], end[1], angle - ANGLE_ADJUSTMENT, length);
158: // two more pieces growing out the end of this stem
159: drawPlant(end[0], end[1], angle - ANGLE_ADJUSTMENT, smaller);
160: drawPlant(end[0], end[1], angle, smaller);
161: }
162: }
164: /**
165: * Draw the stem of the plant.
166: * (You don't need to know how this method works.)
167: *
168: * @param x x-coordinate of the stem's root
169: * @param y y-coordinate of the stem's root
170: * @param angle angle the plant grows from its root
171: * @param length the length of the stem
172: * @return the end point of the stem
173: */
174: public double[] drawStem(double x, double y, double angle, double length) {
175: // convert to radians for sin and cos functions
176: double radians = Math.toRadians(angle);
178: // figure out (and remember) the stem's end point
179: double[] end = new double[2];
180: end[0] = x + Math.sin(radians) * length;
181: end[1] = y + Math.cos(radians) * length;
183: // draw the stem
184: drawLine(x, y, end[0], end[1]);
186: // return its end point
187: return end;
188: }
190: /**
191: * Draw a line between two points on the canvas.
192: * (You do not need to understand how this method works.)
193: *
194: * @param x1 x-coordinate of the line's starting point
195: * @param y1 y-coordinate of the line's starting point
196: * @param x2 x-coordinate of the line's ending point
197: * @param y2 y-coordinate of the line's ending point
198: */
199: public void drawLine(double x1, double y1, double x2, double y2) {
200: // round off the coordinates...
201: int startX = (int) Math.round(x1);
202: int startY = (int) Math.round(y1);
203: int endX = (int) Math.round(x2);
204: int endY = (int) Math.round(y2);
206: // ...because the canvas is expecting integers
207: canvas.drawLine(startX, startY, endX, endY);
208: }
209: }