Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
echau01 committed Jun 21, 2018
0 parents commit 52dc55c
Show file tree
Hide file tree
Showing 5 changed files with 378 additions and 0 deletions.
41 changes: 41 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Compiled class file

*.class


# Log file

*.log


# BlueJ files

*.ctxt


# Mobile Tools for Java (J2ME)

.mtj.tmp/


# Package Files #

*.jar
*.war
*.ear
*.zip
*.tar.gz
*.rar


# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml

hs_err_pid*


# Eclipse files

/bin/
/.settings/
.project
.classpath
169 changes: 169 additions & 0 deletions src/echau/gui/butterflycurve/ButterflyCurve.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
package echau.gui.butterflycurve;

/**
* This class represents the actual butterfly curve. This class tells the Screen class where to
* render the curve at a certain time. The main significant method in this class is {@link #update()}.
* <br>
* <br>
* According to Wikipedia, the butterfly curve is a parametric function defined as:
* <br>
* <br>
* {@code x(t) = [sin(t)][exp(cos(t)) - 2cos(4t) - (sin(t / 12))^5]}
* <br>
* {@code y(t) = [cos(t)][exp(cos(t)) - 2cos(4t) - (sin(t / 12))^5]}
*/
public class ButterflyCurve {
/* Current x- and y-coordinates of the curve */
private double xCoord;
private double yCoord;

/** t is the "time" variable in parametric equations. */
private double t;

/* Lower and upper bounds of t */
private final double tLowerBound;
private final double tUpperBound;

// Used to compare the floating-point value of t to tLowerBound and tUpperBound.
private static final double EPSILON = Gui.T_INCREMENT;

// The array storing all coordinates of the function within the domain T_LOWER_BOUND <= t <= T_UPPER_BOUND
private double[][] coordinateArray;

// Current index of the coordinate array being accessed
private int currentIndex;

// Indicates whether the value of t is increasing
private boolean tIncreasing;

// Indicates whether the curve is about to change direction; i.e. whether t is at a lower or upper bound
private boolean changingDirection;

/**
* Creates a ButterflyCurve with the specified lower and upper bound for t.
*/
public ButterflyCurve(double tLowerBound, double tUpperBound) {
this.tLowerBound = tLowerBound;
this.tUpperBound = tUpperBound;

if (tUpperBound - tLowerBound < Gui.T_INCREMENT) {
// Guarantees that the initial value of currentIndex is within the array
this.t = (tUpperBound + tLowerBound) / 2;
} else {
this.t = tLowerBound + 0.01;
}

currentIndex = (int) ((t - tLowerBound) / Gui.T_INCREMENT);

this.generateCoordinateArray();
tIncreasing = true;
}

/**
* Updates the state of the curve. First, the values of t and currentIndex are updated, then the
* next x- and y-coordinates are fetched and assigned to the variables xCoord and yCoord.
*/
public void update() {
updateTAndCurrentIndex();
checkDirection();
xCoord = coordinateArray[currentIndex][0];
yCoord = coordinateArray[currentIndex][1];
}

/**
* Updates the values of t and currentIndex
*/
private void updateTAndCurrentIndex() {
if (tIncreasing) {
currentIndex++;
t += Gui.T_INCREMENT;
} else {
currentIndex--;
t -= Gui.T_INCREMENT;
}
}

/**
* Checks whether the curve is about to change direction (i.e. whether {@code t} is at an upper or lower bound).
* This method changes the values of goingClockwise and changingDirection accordingly.
*/
private void checkDirection() {
if (t <= tLowerBound + EPSILON || t >= tUpperBound - EPSILON) {
tIncreasing = !tIncreasing;
changingDirection = true;
return;
}
changingDirection = false;
}

/**
* This method is to be used for pre-generating the coordinate arrays for efficiency.
*/
private void generateCoordinateArray() {
// We add 10 extra spaces to the end of coordinateArray to prevent ArrayIndexOutOfBounds exceptions.
// Floating-point arithmetic is dodgy
coordinateArray = new double[10 + (int) ((tUpperBound - tLowerBound) / Gui.T_INCREMENT)][2];
for (double i = tLowerBound; i <= tUpperBound; i += Gui.T_INCREMENT) {
// This is where the parametric equation goes
// Casting to an int always rounds down, so we add 0.001 to prevent floating-point arithmetic from screwing things up
coordinateArray[(int) ((i - tLowerBound + 0.001) / Gui.T_INCREMENT)][0] = Math.sin(i) * (Math.pow(Math.E, Math.cos(i)) - 2 * Math.cos(4 * i) - Math.pow(Math.sin(i / 12), 5));
coordinateArray[(int) ((i - tLowerBound + 0.001) / Gui.T_INCREMENT)][1] = Math.cos(i) * (Math.pow(Math.E, Math.cos(i)) - 2 * Math.cos(4 * i) - Math.pow(Math.sin(i / 12), 5));
}
}

/**
* @return The current value of the t variable of the curve
*/
public double getCurrentT() {
return t;
}

/**
* @return The current x-coordinate of the curve.
*/
public double getCurrentXCoord() {
return xCoord;
}

/**
* @return The current y-coordinate of the curve.
*/
public double getCurrentYCoord() {
return yCoord;
}

/**
* @return The current index of the coordinate array.
*/
public int getCurrentIndex() {
return currentIndex;
}

/**
* @return The lower bound of the t variable.
*/
public double getTLowerBound() {
return tLowerBound;
}

/**
* @return The upper bound of the t variable.
*/
public double getTUpperBound() {
return tUpperBound;
}

/**
* @return A boolean indicating whether the value of t is increasing
*/
public boolean isTIncreasing() {
return tIncreasing;
}

/**
* @return A boolean indicating whether the curve will reverse its direction on the next tick.
*/
public boolean isChangingDirection() {
return changingDirection;
}
}
60 changes: 60 additions & 0 deletions src/echau/gui/butterflycurve/Gui.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package echau.gui.butterflycurve;

import javax.swing.JFrame;
import javax.swing.Timer;

import java.awt.Color;
import java.awt.Container;

@SuppressWarnings("serial")
public class Gui extends JFrame {
/* Constants */
private static final boolean IS_RESIZABLE = false;
private static final Color BACKGROUND_COLOUR = Color.WHITE;

private ButterflyCurve curve;
private Screen screen;

/**
* The amount that {@link ButterflyCurve#getCurrentT()} will be incremented by every time the
* Timer ticks (once per millisecond).
*
* <br>
* <br>
*
* Setting the value of this constant to be greater than the difference between the upper and lower
* bounds of the parametric curve's t value will cause problems. In other words do not make
* the value of this constant greater than
* {@code this.getCurve().getTUpperBound() - this.getCurve().getTLowerBound()}
*/
public static final double T_INCREMENT = 0.003;

public Gui() {
// here, we subtract the preferred lower bound by T_LOWER_BOUND_EPSILON, and pass the
// result into the ButterflyCurve constructor
curve = new ButterflyCurve(0, 6.2835);
screen = new Screen(curve);
this.add(screen);
}

public void setUpGui() {
Container c = this.getContentPane();
c.setBackground(BACKGROUND_COLOUR);
this.setResizable(IS_RESIZABLE);
this.pack();
this.setTitle("Butterfly Curve");
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);

new Timer(1, screen.getPainter()).start();
}

public ButterflyCurve getCurve() {
return curve;
}

public Screen getScreen() {
return screen;
}
}
18 changes: 18 additions & 0 deletions src/echau/gui/butterflycurve/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package echau.gui.butterflycurve;

import javax.swing.SwingUtilities;

/**
* This project currently features a prototype parametric function - the butterfly function. Allowing
* users to input their own parametric functions is the next step.
*/
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new Gui().setUpGui();
}
});
}
}
90 changes: 90 additions & 0 deletions src/echau/gui/butterflycurve/Screen.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package echau.gui.butterflycurve;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JPanel;

@SuppressWarnings("serial")
/**
* The Screen renders the ParametricCurve.
*/
public class Screen extends JPanel {
/* Size of the window depends on these constants */
private static final int WIDTH = 1024;
private static final int HEIGHT = 780;

// The curve being drawn on the screen
private ButterflyCurve curve;

// The ActionListener that paints the screen
private final ActionListener painter;

/*
* An integer from 0 to 2. Each time the curve changes direction, the cycle number increases.
* Every number corresponds to a certain colour with which the curve is drawn.
*/
private int currentCycle;

/* Cycle numbers */
private static final int RED_CYCLE = 0;
private static final int GREEN_CYCLE = 1;
private static final int BLUE_CYCLE = 2;

// REMEMBER TO CHANGE THIS WHEN YOU ADD MORE CYCLES!
private static final int NUMBER_OF_CYCLES = 3;

/**
* Construct a Screen on which the specified ParametricCurve will be drawn.
*/
public Screen(ButterflyCurve curve) {
this.setPreferredSize(new Dimension(WIDTH, HEIGHT));
this.painter = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
repaint();
}
};

this.curve = curve;
this.currentCycle = 0;
}

@Override
public void paintComponent(Graphics g) {
curve.update();

this.setCurveColour(g);

if (curve.isChangingDirection()) {
// Change cycle
if (currentCycle == NUMBER_OF_CYCLES - 1) {
currentCycle = 0;
} else {
currentCycle++;
}
}

g.fillOval((int) (curve.getCurrentXCoord() * 100 + WIDTH * 0.5), (int) (curve.getCurrentYCoord() * -120 + HEIGHT * 0.6), 10, 10);
}

private void setCurveColour(Graphics g) {
if (currentCycle == RED_CYCLE) {
g.setColor(Color.RED);
} else if (currentCycle == GREEN_CYCLE) {
g.setColor(Color.GREEN);
} else if (currentCycle == BLUE_CYCLE) {
g.setColor(Color.BLUE);
}
}

/**
* Returns the ActionListener that paints the Screen.
*/
public ActionListener getPainter() {
return this.painter;
}
}

0 comments on commit 52dc55c

Please sign in to comment.