-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathProject2.java
More file actions
370 lines (310 loc) · 13.7 KB
/
Copy pathProject2.java
File metadata and controls
370 lines (310 loc) · 13.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
/*
* PROJECT II: Project2.java
*
* This file contains a template for the class Project2. Not all methods
* are implemented. Make sure you have carefully read the project formulation
* before starting to work on this file.
*
* There are a lot of functions in this class, as it deals with creating an
* image using purely Java. I have already completed a lot of the technical
* aspects for you, so there should not be a huge amount for you to do in this
* class!
*
* At the bottom of this class there is a section of functions which I have
* already written and deal with the more complicated tasks. You should make
* sure that you read through the function descriptions, but DO NOT ALTER
* THEM! Also, remember to call the setupFractal() function from your
* constructor!
*
* Remember not to change the names, parameters or return types of any
* variables in this file! You should also test this class using the main()
* function.
*
* The function of the methods and instance variables are outlined in the
* comments directly above them.
*
* Tasks:
*
* 1) Complete this class with the indicated methods and instance variables.
*
* 2) Fill in the following fields:
*
* NAME: Archie Bevan
* UNIVERSITY ID: 5538165
* DEPARTMENT: Maths and Stats
*/
// These next lines import the relevant classes needed to output an image and
// *SHOULD NOT* be changed. You do not need to worry about their definitions.
import java.io.*;
import java.awt.image.*;
import java.awt.*;
import javax.imageio.ImageIO;
import java.util.ArrayList;
public class Project2 {
/**
* A reference to the Secant iterator object.
*/
private Secant iterator;
/**
* The top-left corner of the square in the complex plane to examine.
*/
private Complex origin;
/**
* The width of the square in the complex plane to examine.
*/
private double width;
/**
* A list of roots of the polynomial.
*/
private ArrayList<Complex> roots;
/**
* A two dimensional array holding the colours of the plot.
*/
private Color[][] colours;
/**
* A flag indicating the type of plot to generate. If true, colourPixel will
* choose darker colours if a particular root takes longer to converge.
*/
private boolean colourIterations;
/**
* A standard Java object which allows us to store a simple image in
* memory. This will be set up by setupFractal -- you do not need to worry
* about it!
*/
private BufferedImage fractal;
/**
* This object is another standard Java object which allows us to perform
* basic graphical operations (drawing lines, rectangles, pixels, etc) on
* the BufferedImage. This will be set up by setupFractal -- you do not
* need to worry about it!
*/
private Graphics2D g2;
/**
* Defines the width (in pixels) of the BufferedImage and hence the
* resulting image.
*/
public static final int NUMPIXELS = 400;
// ========================================================
// Constructor function.
// ========================================================
/**
* Constructor function which initialises the instance variables
* above. IMPORTANT: Remember to call setupFractal at the end of this
* function!!
*
* @param p The polynomial to generate the fractal of.
* @param origin The top-left corner of the square to image.
* @param width The width of the square to image.
*/
public Project2(Polynomial p, Complex origin, double width) {
// You need to fill in this function with the correct code.
// initialise the origin and width. Call roots an arraylist with complex numbers in.
// call the secant(p) method iterator
// setupFractal- as told in the pdf to do so
this.origin=origin;
this.width=width;
roots=new ArrayList<Complex>();
iterator=new Secant(p);
setupFractal();
}
// ========================================================
// Basic operations.
// ========================================================
/**
* Print out all of the roots found so far, which are contained in the
* roots ArrayList.
*/
public void printRoots() {
// You need to fill in this function.
System.out.println("Roots:" +roots);
}
/**
*
* @return an ArrayList of roots for the polynomial
*/
public ArrayList<Complex> getRoots() {
// This method is complete.
return roots;
}
/**
* Check to see if root is in the roots ArrayList (up to tolerance).
*
* @param root Root to find in this.roots.
* @return The index of root within roots (-1 if the root is not found) IN THE ARRAY OF ROOTS
*/
public int index(Complex root) {
// You need to fill in this function.
// iterate i the number of times equal to the size of the root array. If the root is found the array within TOL
// then return the index of the root in the array.
// if the root is not found in the root array then return -1
for(int i=0;i<roots.size();i++){
if ((roots.get(i).add(root.negate())).abs() < Secant.TOL){
return i;
}
}
//System.out.println("returning -1");
return -1;
}
/**
* Convert from pixel indices (i,j) to the complex number (origin.real +
* i*dz, origin.imag - j*dz).
*
* @param i x-axis co-ordinate of the pixel located at (i,j)
* @param j y-axis co-ordinate of the pixel located at (i,j)
*
*/
public Complex pixelToComplex(int i, int j) {
// You need to fill in this function.
// Iterate over each pixel at position (𝑗,𝑘). Then translate this position to a complex number using
// pixelToComplex, which uses the simple mapping (𝑗,𝑘) ↦ 𝑜𝑟𝑖𝑔𝑖𝑛 + Δ𝑧(𝑗 − 𝑖𝑘). NOTE: Δ𝑧 is the
//distance between two pixels being plotted in the complex plane.
// distance between two pixels would be the width of the image divided by the number of pixels.
// then create a new complex number using the formula given in the pdf coursework2.
// this assigns a complex number to any pixel coordinate 400x400
double zchange = width/NUMPIXELS;
double g = origin.getReal() + i*zchange;
double h = origin.getImag() - j*zchange;
return new Complex(g,h);
}
// ========================================================
// Fractal generating function.
// ========================================================
/**
* Generate the fractal image. Use colourPixel() to add coloured pixels
* to the image for this fractal.
*/
public void createFractal(boolean colourIterations) {
// You need to fill in this function.
// go over each pixel using a for loop within a for loop for each 'x and y' co ordinate for a pixel.
// within the double for loop convert the pixel co ordinates to a complex number.
// iterate using the iterator function with the starting point and the pixel/complex co ordinate
// if statement ignores and removes any pixels that do not converge to a root or converge to zero (error)
// if the rootindex is equal to -1 then this means the root is not in the arraylist for the roots of the polynomial so we add this root the the arraylist
// we then change the root index so it is the size of the root arraylist -1 which means we can start from zero index
// to check the function was working at various points i printed out values to check if they were correct and certain parts of the code were running as expected (these are commented)
// i then printed out the roots array list to check if the roots are correct
// then the pixels have an index which represented the root they converge to and this index is associated with a colour therefore the pixel that converges to a certain root is assigned to a certain colour.
// use the colour pixel to put in the i and j values which will go thrpugh each pixel co ordinate due to the double for loop
// the number of iterations is called by getnumiterations and this determines the darkness of the fractal. longer = darker
this.colourIterations = colourIterations; // consider colouriterations
Complex z0 = new Complex(0, 0); // start point for iteration
for (int i = 0; i < NUMPIXELS; i++) {
for (int j = 0; j < NUMPIXELS; j++) {
Complex cx = pixelToComplex(i, j);
iterator.iterate(z0, cx);
if (iterator.getError() == Secant.Error.DNF || iterator.getError() == Secant.Error.ZERO) {
continue;
}
Complex root = iterator.getRoot();
int rootIndex = index(root);
if (rootIndex == -1) {
roots.add(root);
rootIndex = roots.size() -1;
// System.out.println("Added root: " + root);
}
int numIterations = iterator.getNumIterations();
Secant.Error error = iterator.getError();
// System.out.println("Root: " + root);
// System.out.println("Error: " + error);
// System.out.println("Index: " + rootIndex);
// printRoots();
colourPixel(i,j,rootIndex,numIterations);
}
}
}
// ========================================================
// Tester function.
// ========================================================
public static void main(String[] args) {
// Here is some example code which generates the two images seen in
// figure 1 of the formulation.
Complex[] coeff = new Complex[] { new Complex(-1.0,0.0), new Complex(), new Complex(), new Complex(1.0,0.0) };
Polynomial p = new Polynomial(coeff);
Project2 project = new Project2(p, new Complex(-1.0,1.0), 2.0);
// The following lines of code will raise Exceptions initially
// because the createFractal and the constructor are incomplete
project.createFractal(false);
project.saveFractal("fractal-light.png");
project.createFractal(true);
project.saveFractal("fractal-dark.png");
//New Fractal (Test)
Complex[] coeff2 = new Complex[] { new Complex(-1.0,0.0), new Complex(), new Complex(), new Complex(), new Complex(), new Complex(1.0,0.0) };
Polynomial p2 = new Polynomial(coeff2);
Project2 project2 = new Project2(p2, new Complex(-1.5,1.5), 3.0);
project2.createFractal(false);
project2.saveFractal("fractal2-light.png");
project2.createFractal(true);
project2.saveFractal("fractal2-dark.png");
}
// ====================================================================
// OTHER FUNCTIONS
//
// The rest of the functions in this class are COMPLETE (with the
// exception of the main function) since they involve quite complex Java
// code to deal with the graphics. This means they *do not* and *should
// not* need to be altered! But you should read their descriptions so you
// know how to use them.
// ====================================================================
/**
* Sets up all the fractal image. Make sure that your constructor calls
* this function!
*/
private void setupFractal()
{
// This function is complete!
int i, j;
if (iterator.getF().degree() < 3 || iterator.getF().degree() > 5)
throw new RuntimeException("Degree of polynomial must be between 3 and 5 inclusive!");
this.colours = new Color[5][Secant.MAXITER];
this.colours[0][0] = Color.RED;
this.colours[1][0] = Color.GREEN;
this.colours[2][0] = Color.BLUE;
this.colours[3][0] = Color.CYAN;
this.colours[4][0] = Color.MAGENTA;
for (i = 0; i < 5; i++) {
float[] components = colours[i][0].getRGBComponents(null);
float[] delta = new float[3];
for (j = 0; j < 3; j++)
delta[j] = 0.8f*components[j]/Secant.MAXITER;
for (j = 1; j < Secant.MAXITER; j++) {
float[] tmp = colours[i][j-1].getRGBComponents(null);
colours[i][j] = new Color(tmp[0]-delta[0], tmp[1]-delta[1],
tmp[2]-delta[2]);
}
}
fractal = new BufferedImage(NUMPIXELS, NUMPIXELS, BufferedImage.TYPE_INT_RGB);
g2 = fractal.createGraphics();
}
/**
* Colours a pixel in the image.
*
* @param i x-axis co-ordinate of the pixel located at (i,j)
* @param j y-axis co-ordinate of the pixel located at (i,j)
* @param rootColour An integer between 0 and 4 inclusive indicating the
* root number.
* @param numIter Number of iterations at this root.
*/
private void colourPixel(int i, int j, int rootColour, int numIter)
{
// This function is complete!
if (colourIterations)
g2.setColor(colours[rootColour][numIter-1]);
else
g2.setColor(colours[rootColour][0]);
g2.fillRect(i,j,1,1);
}
/**
* Saves the fractal image to a file.
*
* @param fileName The filename to save the image as. Should end in .png.
*/
public void saveFractal(String fileName) {
// This function is complete!
try {
File outputfile = new File(fileName);
ImageIO.write(fractal, "png", outputfile);
} catch (IOException e) {
System.out.println("I got an error trying to save! Maybe you're out of space?");
}
}
}