import java.applet.*; import java.awt.*; // This applet implements an old IBM PC Basic program called Squiral whose // purpose is to draw "pretty" designs by drawing multiple shrinking // rectangles in many colors. However, I did not have the Basic code - // I just coded it as I remembered it working. If I did it wrong, I would // be glad to change the name. However, most of all I would like to credit // whoever wrote the original. If you know the original source, I would // love to have it. // The user gets to enter the three parameters - angle through which the // next rectangle will be rotated, how much (in decimal percentage) the next // rectangle will be shrunk, and how many times to repeat the process. // To keep the rectangles in the drawing region, the number of repetitions // is kept to no more than two/the shrinking percentage. This allows the // rectangle to shrink down to 0 then grow until it is the "original" // size. If it continued it would expand past the size of the starting // rectangle and become to large to fit. If the user puts in too many // repetitions or a negative or 0 shrinking parameter, the program will // "fix" the problem - without warning you. public class Squiral extends Applet { private Button ClearButton; // Clears the drawing area. private Button SquiralButton; // Draws the Squiral pattern when // pressed. private TextField AngleTextField; // Contains the Angle that the // next drawn box will be rotated // through before being drawn. // The angle is in degrees. private TextField DecrementTextField; // How much smaller the next // drawn box will be as a // decimal percentage. private TextField NumberOfIterationsTextField; // How many boxes to // draw. // Called to initialize the applet public void init() { this.setBackground(Color.white); // Set up the Angle box with default value of 10 degrees. AngleTextField=new TextField("10.0",10); this.add(AngleTextField); // Set up the Decrement box with a default value of 1% (.01). DecrementTextField=new TextField("0.01",10); this.add(DecrementTextField); // Set up Number of Iterations box with a default value of 200. NumberOfIterationsTextField=new TextField("200",10); this.add(NumberOfIterationsTextField); // Set up the button that draws the Squiral pattern. SquiralButton = new Button("Squiral"); SquiralButton.setForeground(Color.blue); SquiralButton.setBackground(Color.red); this.add(SquiralButton); // Set up the Clear button. ClearButton = new Button("Clear"); ClearButton.setForeground(Color.black); ClearButton.setBackground(Color.lightGray); this.add(ClearButton); } // Called when the user clicks a button. public boolean action(Event event, Object arg) { // If the Clear button was clicked on, clear the drawing area // by drawing a rectangle in the background color. if(event.target==ClearButton) { Graphics CurrentGraphicsRegion = this.getGraphics(); Rectangle BoundsOfGraphicsRegion=this.bounds(); CurrentGraphicsRegion.setColor(this.getBackground()); CurrentGraphicsRegion.fillRect(BoundsOfGraphicsRegion.x,BoundsOfGraphicsRegion.y,BoundsOfGraphicsRegion.width,BoundsOfGraphicsRegion.height); return true; } else if(event.target==SquiralButton) { Rectangle BoundsOfGraphicsRegion=this.bounds(); Graphics CurrentGraphicsRegion=this.getGraphics(); // xstart and ystart are the left and top of the largest // rectangles. double xstart=((double) BoundsOfGraphicsRegion.x) + 0.25*((double) BoundsOfGraphicsRegion.width); double ystart=((double) BoundsOfGraphicsRegion.x) + 0.33*((double) BoundsOfGraphicsRegion.height); double xend=xstart+0.50*((double) BoundsOfGraphicsRegion.height); double yend=ystart+0.50*((double) BoundsOfGraphicsRegion.height); if (BoundsOfGraphicsRegion.height > BoundsOfGraphicsRegion.width) { xend=xstart+0.5*((double) BoundsOfGraphicsRegion.width); yend=ystart+0.5*((double) BoundsOfGraphicsRegion.width); } double xcenter=(xstart+xend)/2; double ycenter=(ystart+yend)/2; double theta1=Math.atan2(ystart-ycenter,xstart-xcenter); double theta4=Math.atan2(-(ystart-ycenter),xstart-xcenter); double theta2=theta4+Math.PI; double theta3=theta1+Math.PI; // Compute DelTheta - the increment in radians to rotate each // time. Double Number=new Double(0.0); Number=Number.valueOf(AngleTextField.getText()); double DelTheta=Math.PI*Number.doubleValue()/180.0; // HalfDiagonal contains the distance from the center to any // of the corners of the rectangle to be drawn. double HalfDiagonal=Math.sqrt((yend-ycenter)*(yend-ycenter)+ (xend-xcenter)*(xend-xcenter)); // Decrement contains how much the rectangle shrinks each // time through. Number=Number.valueOf(DecrementTextField.getText()); double Decrement=Number.doubleValue()*HalfDiagonal; // We cannot allow negative decrements. if (Decrement<0) { Decrement=-Decrement; Number=new Double(-Number.doubleValue()); DecrementTextField.setText(Number.toString()); } // NumberOfReps is how many times the rectangle is drawn. // It cannot be too big or the rectangles will grow out of // the region by shrinking the distance from the center to // the corners to zero and, then, through increasing // negative values until it does not fit. Number=Number.valueOf(NumberOfIterationsTextField.getText()); int NumberOfReps = (int) Number.doubleValue(); // Make sure that Decrement>0 before dividing by it. if (Decrement>0.0) { if(NumberOfReps > ((int) (2.0*HalfDiagonal/Decrement))) { NumberOfReps = (int) (2.0*HalfDiagonal/Decrement); Number=new Double((double) NumberOfReps); NumberOfIterationsTextField.setText(Number.toString()); } } // Used for corner points of drawn rectangle int x1,y1,x2,y2,x3,y3,x4,y4; // Start with corners (xstart,ystart),(xend,ystart),(xend,yend), // (xstart,yend) which is at a rotaion of 0.0 double theta=0.0; // current is the color used to draw a rectangle. It changes // randomly as the rectangles rotate. Color current; for(int k=0;k