Trajectory Calculator - Key Code Requirements
// The line below isn't necessary in Jupyter Notebook
//package com.hacks.trajectoryCalculator;
import org.jfree.data.function.Function2D;
/*
* Actual math for calculating trajectory
*
* Calculates equation as a string
*
* Returns equation
*
*/
public class TrajectoryMath implements Function2D {
// Initialize variables
private double velocity;
private double degrees;
private double height;
private String equation;
private double coefficientA;
private double coefficientB;
private double coefficientC;
// Constructor
public TrajectoryMath(double velocity, double degrees, double height) {
this.velocity = velocity;
this.degrees = degrees;
this.height = height;
this.calculateEquation();
}
// Getters and setters
public double getVelocity() {
return this.velocity;
}
public double getDegrees() {
return this.degrees;
}
public double getHeight() {
return this.height;
}
public String getEquation() {
return this.equation;
}
public double getCoefficientA() {
return this.coefficientA;
}
public double getCoefficientB() {
return this.coefficientB;
}
public double getCoefficientC() {
return this.coefficientC;
}
// Gets the root of the equation
// There should be only one positive root, so the method will return that and discard the other
// Returns 0.0 if none is found (which shouldn't happen usually)
public double getRoot() {
double rootOne = (-this.coefficientB + Math.sqrt(Math.pow(coefficientB, 2) - 4 * (-this.coefficientC) * this.coefficientA)) / (2 * (-this.coefficientC));
double rootTwo = (-this.coefficientB - Math.sqrt(Math.pow(coefficientB, 2) - 4 * (-this.coefficientC) * this.coefficientA)) / (2 * (-this.coefficientC));
if (rootOne > 0) {
return rootOne;
} else if (rootTwo > 0) {
return rootTwo;
} else {
return 0.0;
}
}
public void setVelocity(double velocity) {
this.velocity = velocity;
}
public void setDegrees(double degrees) {
this.degrees = degrees;
}
public void setHeight(double height) {
this.height = height;
}
// Array should be in order of velocity, degrees, and height
public void setParameters(double[] values) {
this.velocity = values[0];
this.degrees = values[1];
this.height = values[2];
}
// Math for equation
private void calculateEquation() {
// Calculates coefficients for each part
this.coefficientA = height;
this.coefficientB = Math.tan(degrees * Math.PI/180);
this.coefficientC = 9.8 / (2 * Math.pow(velocity, 2) * Math.pow(Math.cos(degrees * Math.PI/180), 2));
// Makes string of equation just in case
String precheckedEquation = "y = " + String.valueOf(coefficientA) + " + " + String.valueOf(coefficientB) + "x - " +
String.valueOf(coefficientC) + "x^2";
this.equation = precheckedEquation;
}
// Returns equation
public double getValue(double v) {
return coefficientA + coefficientB * v - coefficientC * Math.pow(v, 2);
}
/*
* public static void main(String[] args) {
TrajectoryMath example = new TrajectoryMath(15, 60, 4);
System.out.println(example.getRoot());
}
*/
}
// Below line is unnecessary
//package com.hacks.trajectoryCalculator;
import javax.swing.JOptionPane; // library to display options
import javax.swing.JTextField; // library to create a text field to render on GUI
public class InputInitial {
// instance variables to be used
public static Double initialVelocity;
public static Double initialDegrees;
public static Double initialHeight;
// create the GUI element that users input into
public void spawnInputs() {
// while the values have not changed yet, keep going (for error handling)
while (initialVelocity == null || initialDegrees == null || initialHeight == null) {
// text field initialization
JTextField inputVelocity = new JTextField();
JTextField inputDegrees = new JTextField();
JTextField inputHeight = new JTextField();
// organizing the input text to display + the text field in object
Object[] inputs = {
"Initial Velocity (m/s):", inputVelocity,
"Initial Degrees:", inputDegrees,
"Initial Height (m):", inputHeight
};
JOptionPane.showConfirmDialog(null, inputs, "Input the initial values for your object (numbers only):", JOptionPane.OK_CANCEL_OPTION); // creates the option menu with the 3 inputs
// take the input, assign it to the public variables
initialVelocity = parseInput(inputVelocity);
initialDegrees = parseInput(inputDegrees);
initialHeight = parseInput(inputHeight);
}
}
// change JTextField into Double, also error handling
public Double parseInput(JTextField inputValue) {
String placeholder = inputValue.getText(); // get the string out of the input
// error handling + edge cases
try {
double initialValue = Double.parseDouble(placeholder);
// if negative, cannot be valid so throw error --> reinput values bc still null
if (initialValue < 0.0) {
JOptionPane.showMessageDialog(null, "Inputs must be greater than 0", "Invalid Input", JOptionPane.WARNING_MESSAGE);
return null;
} else { // if everything ok, return the value
return initialValue;
}
} catch (Exception e) { // if cannot be cased as a double, throw error --> reinput values
JOptionPane.showMessageDialog(null, "There was an invalid input for " + placeholder + ", please try again. " + e, "Unwanted Input", JOptionPane.WARNING_MESSAGE);
return null;
}
}
}
// Below line is unnecessary
// package com.hacks.trajectoryCalculator; // maven build
// import the graphs
import org.jfree.data.function.Function2D;
import org.jfree.data.general.*;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYDataset;
// import the other files
import com.hacks.trajectoryCalculator.*;
// import swing and awt
import javax.swing.JFrame;
import java.awt.Dimension;
public class TrajectoryGraph extends JFrame {
// Constructor of the graph that will be displayed
public TrajectoryGraph() {
InputInitial newInputs = new InputInitial(); // start input object from separate file
newInputs.spawnInputs(); // start the process of collecting user input
drawGraph(InputInitial.initialVelocity, InputInitial.initialDegrees, InputInitial.initialHeight); // call method to draw the graph with the user input taken
}
// graph drawer
public void drawGraph(double velocity, double degrees, double height) {
Function2D test = new TrajectoryMath(velocity, degrees, height); // TrajectoryMath implements function2d, so use those values create new function2d object
TrajectoryMath testGetter = new TrajectoryMath(velocity, degrees, height); // creates TrajectoryMath object from the other file to call custom methods
XYDataset dataset = DatasetUtils.sampleFunction2D(test, 0.0, testGetter.getRoot(), 50, "Function"); // generates the dataset of xy values with the function
final JFreeChart chart = ChartFactory.createXYLineChart("Trajectory Equation", "X Position (meters)", "Y Position (meters)", dataset, PlotOrientation.VERTICAL, true, true, false); // creates the actual graph with attributes
// initializing the display
ChartPanel cp = new ChartPanel(chart) {
@Override
public Dimension getPreferredSize() {
return new Dimension(500, 500); // set initial dimension
}
};
// allow mouse wheel scrolling
cp.setMouseWheelEnabled(true);
add(cp);
// Finalize the building of the graph
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
}
public static void main(String[] args) {
// runs the creation of the graph with a queue in a different thread and posts the gui after events are processed
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
// initialize new TrajectoryGraph object, setvisible to display the graph
new TrajectoryGraph().setVisible(true);
}
});
}
}