HirstSquares.java
1    /* 
2     * A program to paint, centered on the canvas, a circle of randomly colored, black-framed squares. 
3     */
4    
5    package npw;
6    
7    import painter.SPainter;
8    import shapes.SCircle;
9    import shapes.SSquare;
10   
11   import javax.swing.*;
12   import java.awt.*;
13   import java.util.Random;
14   import java.util.Scanner;
15   
16   public class HirstSquares {
17   
18       private void paintTheImage(){
19           // Get the input information
20           int radius = getNumber("circle radius");
21           int side = getNumber("square side length");
22   
23           // Establish the painter
24           SPainter painter = new SPainter("Circle of Squares", radius*2+50, radius*2+50);
25           painter.setBrushWidth(3);
26           SCircle circle = new SCircle(radius);
27           SSquare square = new SSquare(side);
28   
29           // Paint the squares
30           paintCircleOfSquares(painter, circle, square);
31       }
32   
33       private void paintCircleOfSquares(SPainter painter, SCircle circle, SSquare square){
34           // Paint the circle of squares
35           double howFarToMove = 0;
36   
37           while (howFarToMove < circle.radius()) {
38               double chord = chordLength(howFarToMove, circle);
39               int squares = squaresOnLineCount(chord, square.side());
40               if (howFarToMove == 0) {
41                   paintRow(painter, square, squares);
42               }
43               else {
44                   // Stay invariant with respect to painter position
45                   painter.mfd(howFarToMove);
46                   paintRow(painter, square, squares);
47                   painter.mbk(howFarToMove * 2);
48                   paintRow(painter, square, squares);
49                   painter.mfd(howFarToMove);
50               }
51               howFarToMove = howFarToMove + square.side();
52           }
53       }
54   
55       // Assumes the painter is at the center of the row to paint, facing right.
56       private void paintRow(SPainter painter, SSquare square, int squaresToPaint){
57           // Turn right to start painting the row.
58           painter.tr();
59           // Move backward 1/2 of the length we're painting to get ready to paint the row.
60           double centerOffset = ( (squaresToPaint * square.side()) / 2) - square.side()/2;
61           painter.mbk(centerOffset);
62   
63           // Paint the row of squares.
64           int painted = 0;
65           while (painted < squaresToPaint){
66               paintOneSquare(painter, square);
67               painter.mfd(square.side());
68               painted = painted + 1;
69           }
70   
71           // Make the method invariant with respect to painter position.
72           painter.mbk(centerOffset + square.side());
73           // Turn left to stay invariant with respect to direction.
74           painter.tl();
75       }
76   
77       private void paintOneSquare(SPainter painter, SSquare square){
78           square.s2();
79           painter.setColor(randomColor());
80           painter.paint(square);
81           painter.setColor(Color.BLACK);
82           painter.draw(square);
83           square.x2();
84   
85   
86       }
87   
88       private static int squaresOnLineCount(double lineLength, double sideLength){
89           int squares = ( (int)Math.ceil( ( lineLength - sideLength ) / sideLength ) + 1);
90           return squares;
91       }
92   
93       private double chordLength(double yOffset, SCircle circle){
94           double xLength = Math.sqrt(Math.pow(circle.radius(), 2) - Math.pow(yOffset, 2));
95           double chordLength = xLength * 2;
96           return chordLength;
97       }
98   
99       private static int getNumber(String prompt) {
100          String nss = JOptionPane.showInputDialog(null,prompt+"?");
101          Scanner scanner = new Scanner(nss);
102          return scanner.nextInt();
103      }
104  
105      private static Color randomColor() {
106          Random rgen = new Random();
107          int r = rgen.nextInt(256);
108          int g = rgen.nextInt(256);
109          int b = rgen.nextInt(256);
110          return new Color(r,g,b);
111      }
112  
113      public HirstSquares() {paintTheImage();}
114  
115      public static void main(String[] args) {
116          SwingUtilities.invokeLater(new Runnable() {
117              public void run() {
118                  new HirstSquares();
119              }
120          });
121      }
122  }