Question
Visualization is the art of depicting large sets of data as pictures, so that patterns can be recognized. In this assignment youll use an existing
Visualization is the art of depicting large sets of data as pictures, so that patterns can be recognized. In this assignment youll use an existing visualization application to draw pictures of mathematical functions of 2 variables.
Imagine the main app area as representing the (x,y) plane, with x ranging from -350 to +350, and y ranging from -200 to +200. Each dot on the screen (pixel) represents an (x,y) point in this 2-dimensional space. The app computes a user-specified function of each (x,y) point to generate a number. Then the app converts each of those numbers to a color, and paints the corresponding pixel.
To convert numbers (generated by functions) to colors, the app uses the following algorithm: 0 e Black 1eRed
2 255eRainbow blending: low values are red, blending to orange, to yellow, green, blue, purple, magenta, then back to red (See figure below). >255eCycle through the rainbow again and again and again.
The app manages all of this for you. So if youre confused by any of this, dont worry. Your job is to provide classes that compute various functions of (x,y). The visualization part is just to make it fun.
Create a new Eclipse Java project. Under src create a package called func. Import your starter code files into that package.
Your starter files are listed below. Some of them will have compiler errors until you complete your assigned code.
VizFrame.java This is the visualization app. After you write your code, you can run this to look at pictures of your functions. You wont change this class except for uncommenting a few lines when instructed below. Graphical Java is beyond the level of 46B, so dont expect to understand all of this file. But read it anyway ... its an example of how to lay out a slightly large source file, and it shows the sort of comment youre expected to write in your own code. Mostly you wont be graded on your comments. But if you hope to succeed as a programmer and especially if you hope to pass coding interviews you have to write good comments and lay out your code neatly and consistently. Run this class as an app (you might have to tell Eclipse to ignore compiler errors). By making selections in the Function drop-down menu, youll be able to visualize the axes or the addition function. More items will be added to the menu as you work through the assignment.
VizPanel.java Used by VizFrame.java. Dont change this code, but again get a feel for the comments and the layout.
DoubleFunctionOfTwoInts.java An interface that you will implement several times. The interface has 2 methods: double fOfXY(int x, int y), which computes a function on its inputs, and String getName() , which returns the name of the function. Dont change this code.
AdditionFunction.java A very simple implementation of the DoubleFunctionOfTwoInts interface. It might be a helpful guide when you write your own implementations. Dont change this code.
WeirdComplexFunction.java Dont change this code. Its another implementation of the interface, and its just for fun. You can see what it does
later once your own code works. The area of the inner black shape is finite but its boundary is infinitely long and its dimension is a fraction between 2 and 3!
FunctionGrader.java This is the grader bot. It will tell you how youre doing even if some of your work is incomplete or doesnt compile. But all homework assignments must have no compilation errors. No matter what grade the bot gives you, if you submit work that doesnt compile then you get zero points.
Complex.java See below.
Your assignment is to write the following Java classes. They should all go in the func package. Write them in the following order. After you complete each one, uncomment the corresponding line in VizFrame.java, in the block at lines 26-31. This will make the function available in the drop-down menu in the app, and youll be able to see a picture of the function.
SubtractionFunction.java An implementation of the interface. Its fOfXY method should return x minus y. Simple!
ModFunction.java Another implementation of the interface. Its fOfXY method should return x modulo y. Caution: anything % 0 is illegal, so if y is 0, change it to 1 before computing x%y. Before you visualize this function, try to guess what it looks like.
HypotFunction.java Yet another implementation of the interface. Its fOfXY method should return the hypotenuse of a right triangle whose legs have length x and y. Check that API page for the java.lang.Math class for an easy way to do this. Again, try to guess what the visualization will look like.
The next 2 interface implementations use complex numbers. Recall that a complex number has the form a+bi, where i is the square root of -1. Edit the starter file Complex.java, adding code where instructed by the comments. WARNING: its easy to download this code from the web. Remember that youre not here to submit someone elses code; youre here to learn how to be great at writing your own code. Also, submitting someone elses code as if it were your own is plagiarism. Thats a serious form of cheating, and the consequences are also serious.
After you complete Complex.java, write 2 more implementations of the DoubleFunctionOfTwoInts interface. After you write each class, uncomment the corresponding line at the beginning of VizFrame:
ComplexNormFunction The fOfXY method should treat its x and y inputs as the components of a complex number x+bi, and should return the norm of this complex number. Does this visualization look familiar?
ComplexSquaredNormFunction - The fOfXY method should treat its x and y inputs as the components of a complex number x+bi, and return the norm of (x+bi)*(x+bi).
Finally, uncomment line 31 in VizFrame.java. This will add WeirdComplexFunction to the drop-down menu. Dont worry if this takes a few minutes to compute. You won't lose points if this part doesnt work. But its worth waiting for!
Extra credit: Implement another function. Get creative. To visualize your function, edit VizFrame.java. After line 31 (new WeirdComplexFunction(),), add the following:
new MyCreativeFunction(),
(or whatever you call your class). Then run VizFrame.java. Your functions name will appear as the last item in the pull-down menu.
Suggestion: get playful with complex numbers. Even simple functions can be surprising and delightful. (ComplexSquaredNorm totally surprised me ... I had no idea it would look like that!)
java files provided:
1.
package func;
public class AdditionFunction implements DoubleFunctionOfTwoInts
{
@Override
public double fOfXY(int x, int y)
{
return x + y;
}
@Override
public String getName()
{
return "Addition";
}
}
2.
package func;
public class Complex
{
private double real;
private double imaginary;
// Constructs an instance, given its real and imaginary components.
// Complete this constructor, then remove this comment line.
public Complex(double real, double imaginary)
{
}
// Constructs an instance that duplicates source.
// Complete this constructor, then remove this comment line.
public Complex(Complex source)
{
}
// Getter method.
public double getReal()
{
}
// Getter method.
public double getImaginary()
{
}
//
// Constructs and returns a new instance of Complex that represents the sum of its inputs,
// according to the following formula:
//
// (a+bi) plus (c+di) = (a+c) + (b+d)i
//
// Complete this method, then remove this comment line.
//
public static Complex add(Complex c1, Complex c2)
{
}
//
// Constructs and returns a new instance of Complex that represents the product of its inputs,
// according to the following formula:
//
// (a+bi) times (c+di) = a*c + a*di + bi*c + bi*di = ac + (ad+bc)i + bd*ii
// Since ii is -1 by definition, the last term is -bd ==> the result is ac-bd + (ad+bc)i
//
// Complete this method, then remove this comment line.
//
public static Complex multiply(Complex c1, Complex c2)
{
}
//
// The "norm" of complex number a+bi is the square root of (a^2 + b^2).
// Complete this method, then remove this comment line.
//
public double norm()
{
}
}
3.
package func;
public interface DoubleFunctionOfTwoInts
{
public double fOfXY(int x, int y);
public String getName();
}
4.
package func;
import java.lang.reflect.*;
public class FunctionGrader
{
private final static int POINTS_PER_FUNCTION = 15;
private final static int POINTS_FOR_COMPLEX = 100 - POINTS_PER_FUNCTION*5;
private static int points = 100;
private static class GoldenComplex
{
double real;
double imaginary;
public GoldenComplex(double real, double imaginary)
{
this.real = real;
this.imaginary = imaginary;
}
public GoldenComplex(GoldenComplex source)
{
this.real = source.real;
this.imaginary = source.imaginary;
}
public static GoldenComplex add(GoldenComplex c1, GoldenComplex c2)
{
return new GoldenComplex(c1.real+c2.real, c1.imaginary+c2.imaginary);
}
public static GoldenComplex multiply(GoldenComplex c1, GoldenComplex c2)
{
double r = c1.real*c2.real - c1.imaginary*c2.imaginary;
double i = c1.real*c2.imaginary + c1.imaginary*c2.real;
return new GoldenComplex(r, i);
}
public double length()
{
return Math.hypot(real, imaginary);
}
public String toString()
{
if (real == 0)
return imaginary + "i";
else if (imaginary == 0)
return real + "";
return real + (imaginary > 0 ? "+" : "-") + imaginary;
}
}
private static void failComplex(String message)
{
sop("Failure in Complex class: " + message);
sop("Deducting " + POINTS_FOR_COMPLEX + " points");
points -= POINTS_FOR_COMPLEX;
return;
}
private static Class complexClass = null;
private static Constructor twoDoublesCtor = null;
private static Constructor copyCtor = null;
private static Method getRealMethod = null;
private static Method getImaginaryMethod = null;
private static Method addMethod = null;
private static Method multiplyMethod = null;
private static Method normMethod = null;
private static Object makeComplex(double r, double i)
{
try
{
return twoDoublesCtor.newInstance(r, i);
}
catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException x)
{
sop("????? " + x.getMessage() + " " + twoDoublesCtor);
return null;
}
}
private static Object makeComplex(Object src)
{
try
{
double dr = (double)getRealMethod.invoke(src);
double di = (double)getImaginaryMethod.invoke(src);
return makeComplex(dr, di);
}
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException x)
{
sop("????? " + x.getMessage() + " " + twoDoublesCtor);
return null;
}
}
private static boolean closeEnough(double d1, double d2)
{
return Math.abs(d1-d2) < 0.001;
}
private static void checkComplex()
{
//
// Structure.
//
try
{
complexClass = Class.forName("func.Complex");
}
catch (ClassNotFoundException x)
{
failComplex("No func.Complex class");
return;
}
for (Constructor c: complexClass.getConstructors())
{
if (c.getGenericParameterTypes().length == 2 &&
c.getGenericParameterTypes()[0].toString().equals("double") &&
c.getGenericParameterTypes()[0].toString().equals("double"))
twoDoublesCtor = c;
if (c.getGenericParameterTypes().length == 1 &&
c.getGenericParameterTypes()[0].toString().contains("Complex"))
copyCtor = c;
}
if (twoDoublesCtor == null)
{
failComplex("No (double, double) ctor in Complex class");
return;
}
if (copyCtor == null)
{
failComplex("No copy ctor in Complex class");
return;
}
try
{
getRealMethod = complexClass.getMethod("getReal", null);
}
catch (Exception x)
{
failComplex("No getReal(no-args) method");
}
try
{
getImaginaryMethod = complexClass.getMethod("getImaginary", null);
}
catch (Exception x)
{
failComplex("No getImaginary(no-args) method");
}
try
{
addMethod = complexClass.getMethod("add", complexClass, complexClass);
}
catch (Exception x)
{
failComplex("No add(complex, complex) method");
}
try
{
multiplyMethod = complexClass.getMethod("multiply", complexClass, complexClass);
}
catch (Exception x)
{
failComplex("No multiply(complex, complex) method");
}
try
{
normMethod = complexClass.getMethod("norm");
}
catch (Exception x)
{
failComplex("No norm() method");
}
assert getRealMethod != null && getImaginaryMethod != null;
//
// Check double,double ctor.
//
for (int r=-100; r<=100; r++)
{
for (int i=-100; i<=100; i++)
{
Object c = makeComplex(r, i);
if (c == null)
{
failComplex("Couldn't construct: new Complex(" + r + "," + i + ")");
return;
}
try
{
double dr = (double)getRealMethod.invoke(c);
if (!closeEnough(r, dr))
{
String err = "c = new Complex(" + r + ", " + i + "; c.getReal() + returned " + dr + ", expected " + r;
failComplex(err);
return;
}
double di = (double)getImaginaryMethod.invoke(c);
if (!closeEnough(di, i))
{
String err = "c = new Complex(" + r + ", " + i + "; c.getImaginary() + returned " + di + ", expected " + i;
failComplex(err);
return;
}
}
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException x)
{
sop("Grader trouble...not your problem");
sop(x.getMessage());
assert false;
}
}
}
// Check copy ctor. Assumes simple ctor works.
for (int r=-100; r<=100; r++)
{
for (int i=-100; i<=100; i++)
{
Object c1 = makeComplex(r, i);
Object c2 = makeComplex(c1);
try
{
double retrievedR = (double)getRealMethod.invoke(c2);
if (!closeEnough(retrievedR, r))
{
failComplex("c1 = new Complex(" + r + ", " + i + "); c2 = new Complex(c1); c2.getReal() returned " + retrievedR + ", should be " + r);
return;
}
double retrievedI = (double)getImaginaryMethod.invoke(c2);
if (!closeEnough(retrievedI, i))
{
failComplex("c1 = new Complex(" + r + ", " + i + "); c2 = new Complex(c1); c2.getImaginary() returned " + retrievedI + ", should be " + i);
assert false;
return;
}
}
catch (IllegalAccessException | InvocationTargetException x) { } // never
}
}
// Check static addition method.
for (int r1=-10; r1<=10; r1++)
{
for (int i1=-10; i1<=10; i1++)
{
for (int r2=-10; r2<=10; r2++)
{
for (int i2=-10; i2<=10; i2++)
{
Object c1 = makeComplex(r1, i1);
Object c2 = makeComplex(r2, i2);
try
{
Object sum = addMethod.invoke(null, c1, c2);
double sumR = (double)getRealMethod.invoke(sum);
double sumI = (double)getImaginaryMethod.invoke(sum);
if (!closeEnough(sumR, r1+r2))
{
String err = "c1 = new Complex(" + r1 + ", " + i1 + "); ";
err += "c2 = new Complex(" + r2 + ", " + i2 + "); ";
err += "Complex.add(c1, c2) returned " + sumR + " + " + sumI + "i ";
err += "Should be " + (r1+r2) + " + " + (i1+i2) + "i ";
failComplex(err);
return;
}
}
catch (InvocationTargetException | IllegalAccessException x) { }
}
}
}
}
// Check static multiply method.
for (int r1=-10; r1<=10; r1++)
{
for (int i1=-10; i1<=10; i1++)
{
for (int r2=-10; r2<=10; r2++)
{
for (int i2=-10; i2<=10; i2++)
{
try
{
Object c1 = makeComplex(r1, i1);
Object c2 = makeComplex(r2, i2);
Object prod = multiplyMethod.invoke(null, c1, c2);
double prodR = (double)getRealMethod.invoke(prod);
double prodI = (double)getImaginaryMethod.invoke(prod);
GoldenComplex golden = GoldenComplex.multiply(new GoldenComplex(r1, i1), new GoldenComplex(r2, i2));
if (Math.abs(prodR - golden.real) > 1.0e-6 || Math.abs(prodI - golden.imaginary) > 1.0e-6)
{
String err = "c1 = new Complex(" + r1 + ", " + i1 + "); ";
err += "c2 = new Complex(" + r2 + ", " + i2 + "); ";
err += "Complex.multiply(c1, c2) returned " + new GoldenComplex(prodR, prodI) + ", should be " + golden;
failComplex(err);
return;
}
}
catch (InvocationTargetException | IllegalAccessException x) { }
}
}
}
}
// Check norm method.
int[][] pairs = { {3, 4}, {4, 3}, {5, 12}, {12, 5} };
int[] lens = {5, 5, 13, 13};
for (int n=0; n<2; n++)
{
int real = pairs[n][0];
int im = pairs[n][1];
int goldenLen = lens[n];
for (int rCoeff=-1; rCoeff<=1; rCoeff+=2)
{
for (int iCoeff=-1; iCoeff<=1; iCoeff+=2)
{
int useReal = rCoeff * real;
int useIm = iCoeff * im;
try
{
Object c = makeComplex(useReal, useIm);
double len = (double)normMethod.invoke(c);
if (Math.abs(len-goldenLen) > 1.0e-6)
{
String err = "c = new Complex(" + useReal + ", " + useIm + "); ";
err += "c.length() returned " + len + ", should be " + goldenLen + " ";
failComplex(err);
return;
}
}
catch (InvocationTargetException | IllegalAccessException x) { } // never
}
}
}
}
private static Class> interfaceClass = null;
private static void checkFunctions()
{
try
{
interfaceClass = Class.forName("func.DoubleFunctionOfTwoInts");
}
catch (ClassNotFoundException x)
{
sop("No DoubleFunctionOfTwoInts interface, deducting " + 100);
points -= 100;
return;
}
checkSubtract();
checkMod();
checkHypot();
checkComplexNorm();
checkComplexSquared();
}
private static boolean implementsTheInterface(Class> clazz)
{
for (Class intf: clazz.getInterfaces())
if (intf == interfaceClass)
return true;
return false;
}
private static void checkSubtract()
{
Class> clazz = null;
Constructor ctor = null;
DoubleFunctionOfTwoInts f = null;
try
{
clazz = Class.forName("func.SubtractionFunction");
if (!implementsTheInterface(clazz))
{
sop("SubtractionFunction class doesn't declare that it implements the interface, deducting " + POINTS_PER_FUNCTION);
points -= POINTS_PER_FUNCTION;
return;
}
}
catch (ClassNotFoundException x)
{
sop("No SubtractionFunction class, deducting " + POINTS_PER_FUNCTION);
points -= POINTS_PER_FUNCTION;
return;
}
try
{
ctor = clazz.getConstructor(new Class[0]);
}
catch (NoSuchMethodException x)
{
sop("Can't construct an instance of SubtractionFunction ... make sure it has a no-args ctor.");
sop("Deducting " + POINTS_PER_FUNCTION);
points -= POINTS_PER_FUNCTION;
return;
}
try
{
f = (DoubleFunctionOfTwoInts)ctor.newInstance();
for (int x=-100; x<=100; x++)
{
for (int y=-100; y<=100; y++)
{
if (f.fOfXY(x, y) != x - y )
{
sop("SubtractionFunction FAILED for x=" + x + ", y=" + y);
sop("Your code returned " + f.fOfXY(x, y) + ", should be " + (x-y));
sop("Deducting " + POINTS_PER_FUNCTION + " points");
points -= POINTS_PER_FUNCTION;
return;
}
}
}
}
catch (Exception x) { } // 5 obscure exceptions that should never get thrown
sop("SubtractionFunction PASSED");
}
private static void checkMod()
{
Class> clazz = null;
Constructor ctor = null;
DoubleFunctionOfTwoInts f = null;
try
{
clazz = Class.forName("func.ModFunction");
if (!implementsTheInterface(clazz))
{
sop("ModFunction class doesn't declare that it implements the interface, deducting " + POINTS_PER_FUNCTION);
points -= POINTS_PER_FUNCTION;
return;
}
}
catch (ClassNotFoundException x)
{
sop("No ModFunction class, deducting " + POINTS_PER_FUNCTION);
points -= POINTS_PER_FUNCTION;
return;
}
try
{
ctor = clazz.getConstructor(new Class[0]);
}
catch (NoSuchMethodException x)
{
sop("Can't construct an instance of SubtractionFunction ... make sure it has a no-args ctor.");
sop("Deducting " + POINTS_PER_FUNCTION);
points -= POINTS_PER_FUNCTION;
return;
}
try
{
f = (DoubleFunctionOfTwoInts)ctor.newInstance();
for (int x=-100; x<=100; x++)
{
for (int y=-100; y<=100; y++)
{
if (y == 0)
continue;
if (f.fOfXY(x, y) != x % y )
{
sop("ModFunction FAILED for x=" + x + ", y=" + y);
sop("Your code returned " + f.fOfXY(x, y) + ", should be " + (x-y));
sop("Deducting " + POINTS_PER_FUNCTION + " points");
points -= POINTS_PER_FUNCTION;
return;
}
}
}
}
catch (Exception x) { } // never
sop("ModFunction PASSED");
}
private static void checkHypot()
{
Class> clazz = null;
Constructor ctor = null;
DoubleFunctionOfTwoInts f = null;
try
{
clazz = Class.forName("func.HypotFunction");
if (!implementsTheInterface(clazz))
{
sop("HypotFunction class doesn't declare that it implements the interface, deducting " + POINTS_PER_FUNCTION);
points -= POINTS_PER_FUNCTION;
return;
}
}
catch (ClassNotFoundException x)
{
sop("No HypotFunction class, deducting " + POINTS_PER_FUNCTION);
points -= POINTS_PER_FUNCTION;
return;
}
try
{
ctor = clazz.getConstructor(new Class[0]);
}
catch (NoSuchMethodException x)
{
sop("Can't construct an instance of HypotFunction ... make sure it has a no-args ctor.");
sop("Deducting " + POINTS_PER_FUNCTION);
points -= POINTS_PER_FUNCTION;
return;
}
try
{
f = (DoubleFunctionOfTwoInts)ctor.newInstance();
for (int x=-100; x<=100; x++)
{
for (int y=-100; y<=100; y++)
{
double golden = Math.hypot(x, y);
double vut = f.fOfXY(x, y);
if (Math.abs(golden-vut) > 1.0e-6)
{
sop("HypotFunction FAILED for x=" + x + ", y=" + y);
sop("Your code returned " + vut + ", should be " + golden);
sop("Deducting " + POINTS_PER_FUNCTION + " points");
points -= POINTS_PER_FUNCTION;
return;
}
}
}
}
catch (Exception x) { } // never
sop("HypotFunction PASSED");
}
private static void checkComplexNorm()
{
Class> clazz = null;
Constructor ctor = null;
DoubleFunctionOfTwoInts f = null;
try
{
clazz = Class.forName("func.ComplexNormFunction");
if (!implementsTheInterface(clazz))
{
sop("ComplexNormFunction class doesn't declare that it implements the interface, deducting " + POINTS_PER_FUNCTION);
points -= POINTS_PER_FUNCTION;
return;
}
}
catch (ClassNotFoundException x)
{
sop("No ComplexNormFunction class, deducting " + POINTS_PER_FUNCTION);
points -= POINTS_PER_FUNCTION;
return;
}
try
{
ctor = clazz.getConstructor(new Class[0]);
}
catch (NoSuchMethodException x)
{
sop("Can't construct an instance of ComplexNormFunction ... make sure it has a no-args ctor.");
sop("Deducting " + POINTS_PER_FUNCTION);
points -= POINTS_PER_FUNCTION;
return;
}
try
{
f = (DoubleFunctionOfTwoInts)ctor.newInstance();
for (int x=-100; x<=100; x++)
{
for (int y=-100; y<=100; y++)
{
double golden = Math.hypot(x, y);
double vut = f.fOfXY(x, y);
if (Math.abs(golden-vut) > 1.0e-6)
{
sop("ComplexNormFunction FAILED for x=" + x + ", y=" + y);
sop("Your code returned " + vut + ", should be " + golden);
sop("Deducting " + POINTS_PER_FUNCTION);
points -= POINTS_PER_FUNCTION;
return;
}
}
}
}
catch (Exception x) { } // never
sop("ComplexNormFunction PASSED");
}
private static void checkComplexSquared()
{
Class> clazz = null;
Constructor ctor = null;
DoubleFunctionOfTwoInts f = null;
try
{
clazz = Class.forName("func.ComplexSquaredNormFunction");
if (!implementsTheInterface(clazz))
{
sop("ComplexSquaredNormFunction class doesn't declare that it implements the interface, deducting " + POINTS_PER_FUNCTION);
points -= POINTS_PER_FUNCTION;
return;
}
}
catch (ClassNotFoundException x)
{
sop("No ComplexSquaredNormFunction class, deducting " + POINTS_PER_FUNCTION);
points -= POINTS_PER_FUNCTION;
return;
}
try
{
ctor = clazz.getConstructor(new Class[0]);
}
catch (NoSuchMethodException x)
{
sop("Can't construct an instance of ComplexSquaredNormFunction ... make sure it has a no-args ctor.");
sop("Deducting " + POINTS_PER_FUNCTION);
points -= POINTS_PER_FUNCTION;
return;
}
try
{
f = (DoubleFunctionOfTwoInts)ctor.newInstance();
for (int r=-100; r<=100; r++)
{
for (int i=-100; i<=100; i++)
{
double c2_real = (r * r) - (i * i);
double c2_im = 2 * r * i;
double golden = Math.hypot(c2_real, c2_im);
double vut = f.fOfXY(r, i);
if (Math.abs(golden-vut) > 1.0e-6)
{
sop("ComplexSquaredLengthFunction FAILED for x=" + r + ", y=" + i);
sop("Your code returned " + vut + ", should be " + golden);
sop("Deducting " + POINTS_PER_FUNCTION + " points");
points -= POINTS_PER_FUNCTION;
return;
}
}
}
}
catch (Exception x) { } // never
sop("ComplexSquaredLengthFunction PASSED");
}
private static void sop(Object x) { System.out.println(x); }
public static void main(String[] args)
{
sop("ASSIGNMENT 3 GRADER");
sop(" ---------------- CHECKING Complex class:");
checkComplex();
sop(" ---------------- CHECKING interface implementations:");
checkFunctions();
sop(" ----------------- TOTAL POINTS = " + points);
}
}
5.
package func;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.stream.*;
import javax.swing.*;
//
// Just before the class declaration, I put a comment describing the class. When you read the rest of
// this comment, don't expect to understand all of it. Just get a sense for how much detail is appropriate.
//
// This class is a JFrame subclass containing a combo box, a Quit button, and a VizPanel instance. Selection changes
// in the combo box trigger setFunction() calls to the VizPanel.
//
public class VizFrame extends JFrame implements ActionListener
{
private final static DoubleFunctionOfTwoInts[] FUNCTIONS =
{
null,
new AdditionFunction(),
//new SubtractionFunction(),
//new ModFunction(),
//new HypotFunction(),
//new ComplexNormFunction(),
//new ComplexSquaredNormFunction(),
//new WeirdComplexFunction(),
};
// Instance variables. I line up the declarations, and use tabs to line up the variable names.
// When you take code-writing interviews, they LOVE to see neat readable code.
private VizPanel vizPanel;
private JComboBox
private JButton quitBtn;
// I consistently skip 2 lines before/after constructors and methods. Consistency is good. For curlies,
// I line up the opening curly and the matching closing curly in the same column. This makes matching curlies
// easy to find visually: their /spatial/ relationship tells me something about their /functional/
// relationship.
VizFrame()
{
// Build and install the main panel. This "paragraph" does one thing. The other 2
// "paragraphs" in this ctor also do one thing.
vizPanel = new VizPanel(null);
add(vizPanel, BorderLayout.CENTER);
// Build and install the control panel.
JPanel controls = new JPanel();
controls.add(new JLabel("Function:"));
String[] names = new String[FUNCTIONS.length];
for (int i=0; i names[i] = (FUNCTIONS[i] == null) ? "No function, show Axes" : FUNCTIONS[i].getName(); combo = new JComboBox<>(names); combo.addActionListener(this); controls.add(combo); quitBtn = new JButton("Quit"); quitBtn.addActionListener(this); controls.add(quitBtn); add(controls, BorderLayout.NORTH); // Set component sizes. pack(); // Frame settings. setResizable(false); setTitle("CS 46B Vizualization Homework. Copyright (c) 2018 by Philip Heller."); } // @Override is an "annotation". It tells the compiler that the following method either // overrides a method inherited from a superclass, or implements a method of an interface // that this class sayis it implements. Here the class says it implements ActionListener, // which defines one method: actionPerformed(ActionEvent e). The annotation catches spelling // errors which would otherwise be hard to find. It's useful and interviewers love it when // you demonstrate that you know about it. Try changing the spelling of this method to see // what happens. Expect an exam question about @Override. @Override public void actionPerformed(ActionEvent e) { if (e.getSource() == quitBtn) System.exit(0); int index = combo.getSelectedIndex(); vizPanel.setFunction(FUNCTIONS[index]); } // Some people would add a comment here like "Main method of this class". I never do that. // Any reader who got past CS46A knows what a main method does. If your comments don't contain // useless information, your readers gain trust that reading your comments is worth their // effort. Comments shouldn't just be accurate, they should be /helpful/. Expect an exam question // about the previous sentence. public static void main(String[] args) { System.out.println("START"); new VizFrame().setVisible(true); } } 6. package func; import java.awt.*; import java.awt.event.*; import java.awt.geom.AffineTransform; import java.awt.image.*; import javax.swing.*; // // A JPanel that uses an instance of DoubleFunctionOfTwoInts. Size is hardcoded. When the DoubleFunctionOfTwoInts // is changed (via calls to setFunction()), the new function is applied to (width,height) space, with function values // translated to colors. Pixel colors are stored in a buffered image. // public class VizPanel extends JPanel { // Static constants are the only variables that should start with a capital letter. In fact, // they should be in all capitals. I line up the declarations, names, and equals-signs. private final static int WIDTH_PIXELS = 700; private final static int HEIGHT_PIXELS = 500; private final static int MAX_XFERABLE = 255; private final static int[] RGBS; // This is a static initializer. It executes once, when the JVM loads the class, before any // instances are constructed. Static initializers aren't part of CS46A or B. static { RGBS = new int[MAX_XFERABLE+1]; float hue = 0f; // variable hue across the spectrum float deltaHue = 1f / (1+MAX_XFERABLE); for (int i=0; i<=MAX_XFERABLE; i++, hue+=deltaHue) RGBS[i] = Color.HSBtoRGB(hue, 1, 1); // maximum saturation and brightness } // For instance variables, I line up the declarations and also the variable names. private DoubleFunctionOfTwoInts function; private BufferedImage image; public VizPanel(DoubleFunctionOfTwoInts function) { this.function = function; setPreferredSize(new Dimension(WIDTH_PIXELS, HEIGHT_PIXELS)); } // A transfer function is any conversion from a number to a color. private static int transfer(double d) { int n = (int)Math.round(d); if (n == 0) return 0; // 0 -> black n = n % RGBS.length; // modulo brings n into range if (n == 0) n = 1; while (n < 0) n += RGBS.length; return RGBS[n]; } // Apply user-selected implementation of function. private void recomputeImage() { // Build blank image. int w = getWidth(); int h = getHeight(); image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); // Function is null => show axes. if (function == null) { Graphics2D g = (Graphics2D)image.getGraphics(); g.setColor(Color.WHITE); g.fillRect(0, 0, w, h); g.setColor(Color.BLACK); int[] axisHalfLens = { (int)(0.95f * Math.max(w, h)/2), (int)(0.95f * Math.min(w, h)/2) }; AffineTransform xform = g.getTransform(); g.translate(w/2, h/2); for (int i=0; i<4; i++) { // In each of 4 cardinal directions, draw a ray with an arrowhead. g.drawLine(0, 0, axisHalfLens[i%2], 0); g.drawLine(axisHalfLens[i%2], 0, axisHalfLens[i%2]-10, 7); g.drawLine(axisHalfLens[i%2], 0, axisHalfLens[i%2]-10, -7); g.rotate(Math.PI/2); } g.setTransform(xform); g.translate(w/2, h/2); for (int x=-320; x<=320; x+=10) { if (x == 0) continue; // Ticks and values on X axis. int tickLen = (x%50 == 0) ? 20 : 8; g.drawLine(x, -tickLen/2, x, tickLen/2); if (x%50 == 0) { String s = "" + x; int sw = g.getFontMetrics().stringWidth(s); g.drawString(s, x-sw/2, 22); } // Ticks and values on Y axis. if (x >= -220 && x <= 220) { g.drawLine(-tickLen/2, x, tickLen/2, x); if (x%50 == 0) { String s = "" + -x; g.drawString(s, tickLen/2 + 12, x+4); } } } g.setTransform(xform); } // Function is non-null. For each (x,y) point, compute f(x,y), convert to color, // and paint pixel at (x,y). else { for (int row=h-1; row>=0; row--) { int y = h/2 - row; //int y = row - h/2; for (int col=0; col { int x = col - w/2; double fn = function.fOfXY(x, y); int rgb = transfer(fn); image.setRGB(col, row, rgb); } } } } // To make a new image, set this.image to null and then repaint. public void paintComponent(Graphics g) { g.setColor(Color.WHITE); g.fillRect(0, 0, getWidth(), getHeight()); if (image == null) recomputeImage(); g.drawImage(image, 0, 0, getWidth(), getHeight(), this); } void setFunction(DoubleFunctionOfTwoInts function) { this.function = function; image = null; repaint(); } // Not part of the app. This class is a color legend panel. A screenshot appears // in the assignment instructions. private static class ColorLegend extends JPanel { public Dimension getPreferredSize() { return new Dimension(800, 400); } public void paintComponent(Graphics g) { // Clear. Graphics2D g2 = (Graphics2D)g; g2.setColor(Color.WHITE); g2.fillRect(0, 0, getWidth(), getHeight()); // Cache default affine transform. AffineTransform dfltXform = g2.getTransform(); // Axis. g2.setStroke(new BasicStroke(2)); g2.translate(20, getHeight()-50); g2.setColor(Color.BLACK); g2.drawLine(0, 0, 3*256, 0); // Ticks and labels. AffineTransform xform = g2.getTransform(); int x = 0; for (int i=0; i<256; i+=5) { x = i * 3; g2.setColor(Color.BLACK); g2.drawLine(x, -10, x, 10); g2.translate(x, 18); g2.rotate(Math.PI/2); g2.drawString(""+i, 0, 4); g2.setTransform(xform); } // Colors. g2.setStroke(new BasicStroke(1)); x = 0; for (int i=0; i<256; i++) { x = i * 3; g2.setColor(new Color(transfer(i))); for (int j=0; j<3; j++) g2.drawLine(x+j, -20, x+j, -800); } g2.setTransform(dfltXform); } } public static void main(String[] args) { JFrame frame = new JFrame(); frame.add(new ColorLegend()); frame.pack(); frame.setVisible(true); } } 7. package func; public class WeirdComplexFunction implements DoubleFunctionOfTwoInts { @Override public double fOfXY(int x, int y) { Complex cOriginal = new Complex(x/125f, y/125f); Complex c = new Complex(cOriginal); for (int n=1; n<=255; n++) { if (c.norm() >= 2) { if (n%2 == 0) //n = 0; n *= 30; return n; } c = Complex.multiply(c, c); c = Complex.add(c, cOriginal); } return 0; } @Override public String getName() { return "Weird complex function"; } }
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started