I'm making a derivative calculator that asks the user for the degree of their polynomial and then the coefficients for each term, partly because I'm an inexperienced programmer and can't parse input like 3x^4/4 + sin(x).
Here's my class.
package beta;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JOptionPane;
public class DerivativeCalculator
{
public DerivativeCalculator(String d, String v)
{
int degree = Integer.parseInt(d);
double value = Double.parseDouble(v);
coeffList = new ArrayList<Double>();
for (int i = 0; i <= degree; i++)
{
String console = JOptionPane.showInputDialog("Enter the coefficient of the "
+ "x^" + i + " term.");
Double coeff = Double.parseDouble(console);
coeffList.add(coeff);
}
}
public double calc()
{
double dx = 0.0001;
double x1 = value;
double y1 = 0;
for (int d = degree; d >= 0; d--)
{
y1 += coeffList.get(d) * Math.pow(x1, d);
}
double x2 = x1 + dx;
double y2 = 0;
for (int d = degree; d >= 0; d--)
{
y2 += coeffList.get(d) * Math.pow(x2, d);
}
double slope = (y2 - y1)/ (x2 - x1);
DecimalFormat round = new DecimalFormat("##.##");
round.setRoundingMode(RoundingMode.DOWN);
return Double.valueOf(round.format(slope));
}
public String getEquation()
{
String equation = "";
for (int d = degree; d >= 0; d--)
{
equation = equation + String.valueOf(coeffList.get(d)) + "x^" + String.valueOf(d) + " + ";
}
return equation;
}
public String getValue()
{
return String.valueOf(value);
}
private int degree;
private double value;
private List<Double> coeffList;
}
Now here's my test class.
package beta;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JApplet;
import javax.swing.JOptionPane;
public class DerivativeCalculatorTest extends JApplet
{
public void paint(Graphics g)
{
Graphics2D g2 = (Graphics2D)g;
String d = JOptionPane.showInputDialog("Enter the degree of your polynomial: ");
String v = JOptionPane.showInputDialog("Enter the x value "
+ "at which you want to take the derivative");
DerivativeCalculator myDerivCalc = new DerivativeCalculator(d, v);
g2.drawString(String.valueOf(myDerivCalc.calc()), 10, 100);
g2.drawString(myDerivCalc.getEquation(), 10, 40);
g2.drawString(myDerivCalc.getValue(), 10, 70);
}
}
Running this creates an applet window that displays
5.0x^0+
0.0
0.0
which is not the correct derivative.
I debugged my program and everything runs as expected until the view switches to my test class and it executes g2.drawString(String.valueOf(myDerivCalc.calc()), 10, 100);
After it executes this line, degree (the degree of the polynomial) resets to 0 even though the user entered 5. This then messes up all the for loops in my class.
Why does this happen? Any suggestions on fixing this? Thanks
You redefine degree and value as local variables inside your constructor. They shadow your class variables with the same name.
Do not re-declare them.
Instead of
int degree = <something>;
double value = <something>;
you need
degree = <something>;
value = <something>;
Isn't 5.0x^0 = 5.0 * 1 = 5.0, and the derivative of that is 0..
I believe your code is working.
Related
If you run this program you will notice that the table that displays the celsius conversion looks funky. What I have been trying to do is have it stop at the tenth place. I really would I appreciate any feedback. Thanks in advance.
Output:
import java.awt.*;
import java.awt.event.*;
import java.util.Arrays;
public class Foo extends Frame
{
public Foo()
{
setTitle(" Fahrenheit To Celsius Chart");
setSize(400, 600);
setVisible(true);
addWindowListener(
new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
}
);
}
public static void main(String[] args)
{
Foo chart = new Foo();
}
public void paint (Graphics g)
{
for(int i = 0; i < 25; i++)
{
g.setColor(Color.BLACK);
g.setFont(new Font("SansSerif", Font.BOLD, 14 ));
g.drawString("Fahrenheit", 70, 110);
g.drawString("Celsius", 200, 110);
int[] tempF = new int[25];
int y = 100, x = 130;
int y1 = 215, x1 = 130;
tempF[0] = 0;
int counter = 0;
while(counter < 26)
{
int index = 0;
String Fahrenheit = String.valueOf(tempF[index]);
double tempC = (tempF[index] - 32) * (5/9.0);
String Celsius = String.valueOf(tempC);
String formatedCelcius = String.format("%.1f", tempC);
g.drawString(Fahrenheit, y, x);
g.drawString(Celsius, y1, x1);
x += 15;
x1 += 15;
tempF[index] += 10;
index++;
counter++;
}
}
}
}
The code for rendering the temperatures should look like:
String Fahrenheit = String.valueOf(tempF[index]);
double tempC = (tempF[index] - 32) * (5/9.0);
String formattedCelcius = String.format("%.1f", tempC);
g.drawString(Fahrenheit, y, x);
g.drawString(formattedCelcius, y1, x1);
In your code, you did:
String.format("%.1f", Celsius);
Rather than:
String.format("%.1f", tempC);
(I hope the difference is clear)
The %f format specifier expects a Double argument (like tempC) but you were passing in a String (Celsius)
This caused a java.util.IllegalFormatConversionException: f != java.lang.String (which you may not have seen as the exception was thrown into the Swing event thread) which aborted the rest of paint method.
Thank you everyone for your feedback. I found the solution. The Math class has a function round() that did the trick. I put this in and it fixed the issue:
double tempC = (tempF[index] - 32) * (5/9.0);
double c = Math.round(tempC);
After changing this I'm getting the proper output:
Final Output
Again, thank you all for your feedback.
Best regards,
DDKGM
I'm working on a program that calculates pi based on randomly generated float numbers that represent x,y co-ordinates on a graph. Each x, y co-ordinate is raised by the power of 2 and stored in two separate arrays. The co-ordinates are distributed uniformly on a graph of interval of 0,1.
The program adds the x, y co-ordinates and if they are less than 1 then the points are located within a circle of diameter 1, illustrated in the diagram below.
I then used the formula,
π ≈ 4 w / n
to work out pi. Where, w is the count of the points within the circle and n is the number of x or y co-ordinates within the arrays.
When I set n up to 10,000,000 (the size of the array) it generates the most accurate calculation of pi of 15-16 decimal places. However after dedicating 4GB of RAM to the run config and setting n to 100,000,000 pi ends up being 0.6710...
I was wondering why this may be happening? Sorry if this is a stupid question.. code is below.
import java.text.DecimalFormat;
import java.util.Random;
public class random_pi {
public random_pi() {
float x2_store[] = new float[10000000];
float y2_store[] = new float[10000000];
float w = 0;
Random rand = new Random();
DecimalFormat df2 = new DecimalFormat("#,###,###");
for (int i = 0; i < x2_store.length; i++) {
float x2 = (float) Math.pow(rand.nextFloat(), 2);
x2_store[i] = x2;
float y2 = (float) Math.pow(rand.nextFloat(), 2);
y2_store[i] = y2;
}
for (int i = 0; i < x2_store.length; i++) {
if (x2_store[i] + y2_store[i] < 1) {
w++;
}
}
System.out.println("w: "+w);
float numerator = (4*w);
System.out.printf("4*w: " + (numerator));
System.out.println("\nn: " + df2.format(x2_store.length));
float pi = numerator / x2_store.length;
String fmt = String.format("%.20f", pi);
System.out.println(fmt);
String pi_string = Double.toString(Math.abs(pi));
int intP = pi_string.indexOf('.');
int decP = pi_string.length() - intP - 1;
System.out.println("decimal places: " + decP);
}
public static void main(String[] args) {
new random_pi();
}
}
The problem is here:
float w = 0;
float numerator = (4*w);
float precision is not enough, change it to int or double:
Like this working sample code:
import java.text.DecimalFormat;
import java.util.Random;
public class random_pi {
public random_pi() {
float x2_store[] = new float[100000000];
float y2_store[] = new float[100000000];
int w = 0;
Random rand = new Random();
DecimalFormat df2 = new DecimalFormat("#,###,###");
for (int i = 0; i < x2_store.length; i++) {
float x2 = (float) Math.pow(rand.nextFloat(), 2);
x2_store[i] = x2;
float y2 = (float) Math.pow(rand.nextFloat(), 2);
y2_store[i] = y2;
}
for (int i = 0; i < x2_store.length; i++) {
if (x2_store[i] + y2_store[i] < 1) {
w++;
}
}
System.out.println("w: "+w);
int numerator = (4*w);
System.out.printf("4*w: " + (numerator));
System.out.println("\nn: " + df2.format(x2_store.length));
float pi = ((float)numerator) / x2_store.length;
String fmt = String.format("%.20f", pi);
System.out.println(fmt);
String pi_string = Double.toString(Math.abs(pi));
int intP = pi_string.indexOf('.');
int decP = pi_string.length() - intP - 1;
System.out.println("decimal places: " + decP);
}
public static void main(String[] args) {
new random_pi();
}
}
output:
w: 78544041
4*w: 314176164
n: 100,000,000
3.14176154136657700000
decimal places: 15
And you don't need to store the results, like this working sample code:
import java.text.DecimalFormat;
import java.util.Random;
public class pi {
public pi() {
double n=100000000;
double w = 0;
Random rand = new Random();
DecimalFormat df2 = new DecimalFormat("#,###,###");
for (int i = 0; i < n; i++) {
double x = rand.nextFloat();
double y = rand.nextFloat();
if ((x*x + y*y) < 1.0) w++;
}
System.out.println("w: "+w);//w: 7852372.0
double numerator = (4*w);
System.out.printf("4*w: " + (numerator));//4*w: 3.1409488E7
System.out.println("\nn: " + df2.format(n));//n: 10,000,000
double pi = numerator / n;
final String fmt = String.format("%.20f", pi);
System.out.println(fmt);//3.14094877243042000000
String pi_string = Double.toString(Math.abs(pi));
int intP = pi_string.indexOf('.');
int decP = pi_string.length() - intP - 1;
System.out.println("decimal places: " + decP);//decimal places: 14
}
public static void main(String[] args) {
new random_pi();
}
}
output:
w: 78539606
4*w: 314158424
n: 100,000,000
3.14158439636230470000
decimal places: 16
I make my first steps in implementation of batch and stochastic gradient descent.
Here is my implementation:
package ch.learning;
import java.util.*;
import org.jzy3d.analysis.AbstractAnalysis;
import org.jzy3d.analysis.AnalysisLauncher;
import org.jzy3d.chart.factories.AWTChartComponentFactory;
import org.jzy3d.colors.Color;
import org.jzy3d.colors.ColorMapper;
import org.jzy3d.colors.colormaps.ColorMapRainbow;
import org.jzy3d.maths.Coord3d;
import org.jzy3d.maths.Range;
import org.jzy3d.plot3d.builder.*;
import org.jzy3d.plot3d.builder.concrete.*;
import org.jzy3d.plot3d.primitives.Scatter;
import org.jzy3d.plot3d.primitives.Shape;
import org.jzy3d.plot3d.rendering.canvas.Quality;
import org.apache.commons.math3.analysis.function.Sigmoid;
public class LogisticReg_GradientDescent {
private List<double[]> trainingExamples = new LinkedList<double[]>();
private static final int sizeTrainingset = 1000;
private volatile double[] theta = {10, 10, 10, 10 };
// Configurable compoenent of step size during theata update
private final double alpha = 0.01;
// Amount of iteration in Batch Gradient Descent
private static final int iterations = 10000;
private static final int printsAtStartAndEnd = 5;
private void buildTrainingExample(int amount) {
// Area of the house
double areaMin = 80;
double areaMax = 1000;
double areaRange = areaMax - areaMin;
// Distance to center
double distanceMin = 10;
double distanceMax = 10000;
double distanceRange = distanceMax - distanceMin;
// Generate training examples with prices
for (int i = 0; i < amount; i++) {
double[] example = new double[5];
example[0] = 1.0;
example[1] = areaMin + Math.random() * areaRange;
example[2] = distanceMin + Math.random() * distanceRange;
// Price is a feature as well in this logistic regression example
double price = 0;
price += _priceComponent(example[1], areaRange);
price += _priceComponent(example[2], distanceRange);
// price += _priceComponent(example[3], yocRange);
example[3] = price;
example[4] = (price>200000)?0:1;
trainingExamples.add(example);
}
}
// Random price according with some range constraints
private double _priceComponent(double value, double range) {
if (value <= range / 3)
return 50000 + 50000 * Math.random() * 0.1;
if (value <= (range / 3 * 2))
return 100000 + 100000 * Math.random() * 0.1;
return 150000 + 150000 * Math.random() * 0.1;
}
private double classificationByHypothesis(double[] features) {
// Scaling
double scalingF0 = features[0];
double scalingF1 = (features[1] - 80) / (920);
double scalingF2 = (features[2] - 10) / (9990);
double scalingF3 = (features[3] - 50000) / (400000);
double z = this.theta[0] * scalingF0 + this.theta[1] * scalingF1 + this.theta[2] * scalingF2
+ this.theta[3] * scalingF3;
double ret = 1 / (1 + Math.pow(Math.E, -z));
return ret;
}
// Costfunction: Mean squared error function
private double gradientBatch_costs() {
double costs = this.trainingExamples.stream().mapToDouble(l -> {
double costsint;
if (l[4] == 0) {
costsint = -Math.log(1 - classificationByHypothesis(l));
} else {
costsint = -Math.log(classificationByHypothesis(l));
}
return costsint;
}).sum();
return costs / this.trainingExamples.size();
}
// Theta Update with Batch Gradient Descent
private void gradientBatch_thetaUpdate(int amount) {
for (int i = 0; i < amount; i++) {
double partialDerivative0 = this.trainingExamples.stream()
.mapToDouble(l -> (classificationByHypothesis(l) - l[4]) * l[0]).sum();
double tmpTheta0 = this.theta[0] - (this.alpha * partialDerivative0 / this.trainingExamples.size());
double partialDerivative1 = this.trainingExamples.stream()
.mapToDouble(l -> (classificationByHypothesis(l) - l[4]) * l[1]).sum();
double tmpTheta1 = this.theta[1] - (this.alpha * partialDerivative1 / this.trainingExamples.size());
double partialDerivative2 = this.trainingExamples.stream()
.mapToDouble(l -> (classificationByHypothesis(l) - l[4]) * l[2]).sum();
double tmpTheta2 = this.theta[2] - (this.alpha * partialDerivative2 / this.trainingExamples.size());
double partialDerivative3 = this.trainingExamples.stream()
.mapToDouble(l -> (classificationByHypothesis(l) - l[4]) * l[3]).sum();
double tmpTheta3 = this.theta[3] - (this.alpha * partialDerivative3 / this.trainingExamples.size());
this.theta = new double[] { tmpTheta0, tmpTheta1, tmpTheta2, tmpTheta3 };
}
}
// Theta update with Stochastic Gradient Descent
private void gradientStochastic_thetaUpdate(double[] feature) {
double tmpTheta0 = this.theta[0] - this.alpha * (classificationByHypothesis(feature) - feature[4]) * feature[0];
double tmpTheta1 = this.theta[1] - this.alpha * (classificationByHypothesis(feature) - feature[4]) * feature[1];
double tmpTheta2 = this.theta[2] - this.alpha * (classificationByHypothesis(feature) - feature[4]) * feature[2];
double tmpTheta3 = this.theta[3] - this.alpha * (classificationByHypothesis(feature) - feature[4]) * feature[3];
this.theta = new double[] { tmpTheta0, tmpTheta1, tmpTheta2, tmpTheta3 };
}
private void resetTheta() {
this.theta = new double[] {0.00001, 0.00001, 0.00001, 0.00001};
}
private void printSummary(int iteration) {
System.out.println(String.format("%s \t\t Theta: %f \t %f \t %f \t %f \t Costs: %f", iteration, this.theta[0],
this.theta[1], this.theta[2], this.theta[3], this.gradientBatch_costs()));
}
public static void main(String[] args) {
LogisticReg_GradientDescent d = new LogisticReg_GradientDescent();
// Batch and Stochastic Gradient Descent use the same training example
d.buildTrainingExample(sizeTrainingset);
System.out.println("Batch Gradient Descent");
d.printSummary(0);
System.out.println(String.format("First %s iterations", printsAtStartAndEnd));
for (int i = 1; i <= iterations; i++) {
d.gradientBatch_thetaUpdate(1);
d.printSummary(i);
}
System.out.println("Some examples are:");
System.out.println(String.format("The 1:%s, Area:%s, Distance:%s, Price:%s, Classification:%s", d.trainingExamples.get(0)[0],d.trainingExamples.get(0)[1],d.trainingExamples.get(0)[2],d.trainingExamples.get(0)[3],d.trainingExamples.get(0)[4]));
System.out.println(String.format("The 1:%s, Area:%s, Distance:%s, Price:%s, Classification:%s", d.trainingExamples.get(500)[0],d.trainingExamples.get(500)[1],d.trainingExamples.get(500)[2],d.trainingExamples.get(500)[3],d.trainingExamples.get(500)[4]));
try {
AnalysisLauncher.open(d.new SurfaceDemo());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
class SurfaceDemo extends AbstractAnalysis{
#Override
public void init(){
double x;
double y;
double z;
float a;
Coord3d[] points = new Coord3d[trainingExamples.size()];
Color[] colors = new Color[trainingExamples.size()];
for(int i=0; i<trainingExamples.size(); i++){
x = trainingExamples.get(i)[1]; // Area
y = trainingExamples.get(i)[2]; // Distance to center
z = trainingExamples.get(i)[3]; // price
points[i] = new Coord3d(x, y, z);
a = 1f;
if(trainingExamples.get(i)[4]==1){
colors[i] =new Color(0,0,0,a);
}else{
colors[i]= new Color(250,0,0,a);
}
}
Scatter scatter = new Scatter(points, colors);
scatter.setWidth(4);
Mapper mapper = new Mapper() {
#Override
public double f(double x, double y) {
return (-theta[0]-theta[1]*x-theta[2]*y)/theta[3];
}
};
// Create the object to represent the function over the given range.
Range rangeX = new Range(0, 1000);
Range rangeY = new Range(0, 10000);
int steps = 10;
final Shape surface = Builder.buildOrthonormal(new OrthonormalGrid(rangeX, steps, rangeY, steps), mapper);
surface.setColorMapper(new ColorMapper(new ColorMapRainbow(), surface.getBounds().getZmin(), surface.getBounds().getZmax(), new Color(1, 1, 1, .5f)));
surface.setFaceDisplayed(true);
surface.setWireframeDisplayed(false);
chart = AWTChartComponentFactory.chart(Quality.Advanced, getCanvasType());
chart.getScene().add(scatter);
chart.getScene().add(surface);
}
}
}
A graphical representation looks like
So i plot the generated training instances with org.jzy3d.plot3d.
We see x(the area of the house), y(distance to town center) and z(price).
The classification makes red (negative class -> not sold) and black (positive class -> sold).
In the generated trainings instances the classification depends just at the price, you see it here:
example[4] = (price>200000)?0:1;
The problem, the thing I don't understand is
I would like to plot the decision boundary of my classificator.
The decision bounday depends on the optimized components from Theta. (Using batch gradient descent).
So i try to plot the decision boundary plane with this code:
Mapper mapper = new Mapper() {
#Override
public double f(double x, double y) {
return (-theta[0]-theta[1]*x-theta[2]*y)/theta[3];
}
};
Because
theta[0]*1 + theta[1 ]*x + theta[2]*y + theta[3]*z = 0
so
z = -(theta[0]*1 + theta[1 ]*x + theta[2]*y)/theta[3]
I would expect my decision boundary plane between the red- and blackarea.
Instead it hangs around by z=0.
I didn't know, either I'm not able to plot this decision boundary plane in a proper way, or my optimized parameters are shit.
Further I don't know how to choose a good initial theta vector.
Right now i use
private volatile double[] theta = {1, 1, 1, 1 };
I set alpha to 0.0001
private final double alpha = 0.0001;
It was the biggest possible Alpha, where my cost function doesn't jump around and the sigmoid implementation doesn't return infinity.
I already make feature scaling at
private double classificationByHypothesis(double[] features) {
// Scaling
double scalingF0 = features[0];
double scalingF1 = (features[1] - 80) / (920);
double scalingF2 = (features[2] - 10) / (9990);
double scalingF3 = (features[3] - 50000) / (400000);
double z = this.theta[0] * scalingF0 + this.theta[1] * scalingF1 + this.theta[2] * scalingF2
+ this.theta[3] * scalingF3;
double ret = 1 / (1 + Math.pow(Math.E, -z));
return ret;
}
The last five iteration with given initial theta and alpha equals 0.0001 are
9996,Theta: 1.057554,-6.340981,-6.242139,8.145087,Costs: 0.359108
9997,Theta: 1.057560,-6.341234,-6.242345,8.145576,Costs: 0.359109
9998,Theta: 1.057565,-6.341487,-6.242552,8.146065,Costs: 0.359110
9999,Theta: 1.057571,-6.341740,-6.242758,8.146553,Costs: 0.359112
10000,Theta: 1.057576,-6.341993,-6.242965,8.147042,Costs: 0.359113
Some example of the generated training instances are
Area: 431.50139030510206, Distance: 8591.341686012887,
Price: 255049.1280388437, Classification:0.0
Area: 727.4042972310916, Distance: 4364.710136408952,
Price: 258385.59452489938, Classification:0.0
Thanks for any hint!
//I'm trying to draw a new dot every 250 milliseconds but it only draws the dot a single time. I have tried fixing it many times, but it still will only paint a single dot, rather than one after 250 milliseconds. Is this a problem with the timer or the paint method? Here is the code:
import javax.swing.JPanel;
import javax.swing.Timer;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Window extends JPanel{
private int size;
private static double maxValue;
private double elevation;
private double vertV;
public double horizV;
public double gravity;
public double range;
public double time;
public double t = 0;
public Window(int s, double v, double e, double v2, double g,double h,double r,double t){
size = s;
maxValue = v;
elevation = e;
vertV = v2;
gravity = g;
horizV = h;
range = r;
time = t;
setPreferredSize(new Dimension(size, size));
}
public void paintComponent(Graphics g){
g.drawLine(size/25, 0,size/25, size);
g.drawLine(0, size - (size/25), size, size - (size/25));
double[] lines = getLine();
int x = size/5 + (size/25), y = size - (size/25);
int x2 = x;
for(int i = 0; i < 4; i++){
g.drawLine(x, y+5, x, y-5);
g.drawString(lines[i]+"",x-size/50,y+size/30);
x+=x2;
}
int yx = size/25, yy = size - (size/5 + (size/25));
int y2 = size/5 + (size/25);
for(int i=0;i<4;i++){
g.drawLine(yx-5, yy, yx+5, yy);
g.drawString(lines[i]+"",yx-size/25,yy+size/30);
yy -= y2;
}
drawDots(g);
}
//this is the place where i make the dots but it only makes one.
//used to be a for loop but i altered it to an if statement so i could paint one dot at a time
public void drawDots(Graphics g)
{
double ratio = (size-((size/25)*2))/maxValue;
double fx;
double xvalue;
// This for loop is where dots are drawn, each iteration draws one dot. It starts at zero, and counts up to the time variable t.
if(t<=time)
{
t+=0.025;
t = Math.round(t*1000.0)/1000.0;
fx = function(t);
xvalue = xfunction(t);
if(fx >= 0){
System.out.print("Time: " + t + " " + "Range: " + xvalue + " " + "Height: ");
System.out.println(fx);
g.drawLine((int)(size/25+(ratio*xvalue)), (int)((size-(size/25))-(ratio*fx)),
(int)(size/25+(ratio*xvalue)), (int)((size-(size/25))-(ratio*fx)));
}
}
}
//where i make the timer
//250 mill
public void dostuff()
{
int delay = 250;
ActionListener taskPerformer = new ActionListener()
{
public void actionPerformed(ActionEvent arg0)
{
repaint();
}
};
new Timer(delay, taskPerformer).start();
}
public double xfunction(double t){
double x = 0.0;
x = Math.round(horizV * t * 1000.0)/1000.0;
return x;
}
public double function(double t){
double fx = 0.0;
fx = Math.round((vertV*t + .5*(-(gravity))*(t*t) + elevation)*1000.0)/1000.0;
return fx;
}
private static double[] getLine(){
double increment = maxValue / 4;
double currentLine = 0;
double[] lines = new double[4];
for(int i = 0; i < 4; i++){
currentLine+=increment;
lines[i] = Math.round(currentLine * 10.0)/10.0;
}
return lines;
}
}
This is the original version of the code that displays the projectile's motion, but it does not wait 250 milliseconds between drawing each point:
import javax.swing.JPanel;
import java.awt.*;
public class Window extends JPanel{
private int size;
private static double maxValue;
private double elevation;
private double vertV;
public double horizV;
public double gravity;
public double range;
public double time;
public Window(int s, double v, double e, double v2, double g,double h,double r,double t){
size = s;
maxValue = v;
elevation = e;
vertV = v2;
gravity = g;
horizV = h;
range = r;
time = t;
setPreferredSize(new Dimension(size, size));
}
public void paintComponent(Graphics g){
g.drawLine(size/25, 0,size/25, size);
g.drawLine(0, size - (size/25), size, size - (size/25));
double[] lines = getLine();
int x = size/5 + (size/25), y = size - (size/25);
int x2 = x;
for(int i = 0; i < 4; i++){
g.drawLine(x, y+5, x, y-5);
g.drawString(lines[i]+"",x-size/50,y+size/30);
x+=x2;
}
int yx = size/25, yy = size - (size/5 + (size/25));
int y2 = size/5 + (size/25);
for(int i=0;i<4;i++){
g.drawLine(yx-5, yy, yx+5, yy);
g.drawString(lines[i]+"",yx-size/25,yy+size/30);
yy -= y2;
}
drawDots(g);
}
public void drawDots(Graphics g){
double ratio = (size-((size/25)*2))/maxValue;
double fx;
double xvalue;
// This for loop is where dots are drawn, each iteration draws one dot. It starts at zero, and counts up to the time variable t.
for(double t=0;t<=time; t+=0.025){
t = Math.round(t*1000.0)/1000.0;
fx = function(t);
xvalue = xfunction(t);
if(fx >= 0){
System.out.print("Time: " + t + " " + "Range: " + xvalue + " " + "Height: ");
System.out.println(fx);
g.drawLine((int)(size/25+(ratio*xvalue)), (int)((size-(size/25))-(ratio*fx)),
(int)(size/25+(ratio*xvalue)), (int)((size-(size/25))-(ratio*fx)));
}
}
}
public double xfunction(double t){
double x = 0.0;
x = Math.round(horizV * t * 1000.0)/1000.0;
return x;
}
public double function(double t){
double fx = 0.0;
fx = Math.round((vertV*t + .5*(-(gravity))*(t*t) + elevation)*1000.0)/1000.0;
return fx;
}
private static double[] getLine(){
double increment = maxValue / 4;
double currentLine = 0;
double[] lines = new double[4];
for(int i = 0; i < 4; i++){
currentLine+=increment;
lines[i] = Math.round(currentLine * 10.0)/10.0;
}
return lines;
}
}
My problem is that I cant get the diagonal to resize properly. If I run the code the diagonal is on the wrong side and when I expand it vertically it doesn't maintain a perfect diagonal from one corner to another.
Below I have my code for the program and the driver.
import javax.swing.JFrame;
public class Points
{
public static void main(String[] args)
{
JFrame frame = new JFrame("Points");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
PointsPanel panel = new PointsPanel();
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
}
Here is the main program
import javax.swing.JPanel;
import java.awt.Dimension;
import java.awt.Graphics;
import java.util.Random;
import java.awt.Color;
import java.lang.Math.*;
public class PointsPanel extends JPanel
{
private final int MAX_POINTS = 20000;
private final int LENGTH = 1;
private int x,x1,y,y1;
private Random random;
double slope,b,c,g;
public PointsPanel(){
random = new Random();
setBackground(Color.black);
setPreferredSize(new Dimension(300,300));
}
public void paintComponent(Graphics page)
{
super.paintComponent(page);
for(int count = 0; count < MAX_POINTS; count++)
{
x = random.nextInt(getWidth()-1) + 1;
y = random.nextInt(getHeight()-1) + 1;
x1= x + LENGTH;
y1= y + LENGTH;
slope = x1/y1;
c = slope*x;
b = ((-1)*(y))-c;
g = (-1)*y1;
if (b <= g)
page.setColor(Color.red);
else
page.setColor(Color.green);
page.drawLine(x,y,x1,y1);
}
}
}
I solved your issue by making a little change to your PointsPanel class. Take a look at PointsPanel2 class. First of all the diagonal is a linear equation of the form y = aX + b and since it passes by the points of coordinate (0,0) we can reduce it to y = aX therefore a = Y/X for any (X,Y) point that is part of the diagonal.
Now event though the drawing methods use integer coordinate we still have to compute the a coefficient as a floating number (like a double), otherwise it won't work because of rounding issues.
Then once the other part of your code runs and we obtain (x,y) then x1 and y1, all I have to do is to compute the corresponding diagonal y for x1 and compare it to y1 and depending on the obtained value, change the color to red or green
Use this PointsPanel2 class instead of PointsPanel to test with your other Points class
import javax.swing.JPanel;
import java.awt.Dimension;
import java.awt.Graphics;
import java.util.Random;
import java.awt.Color;
import java.lang.Math.*;
public class PointsPanel2 extends JPanel
{
private final int MAX_POINTS = 20000;
private final int LENGTH = 1;
private int x,x1,y,y1;
private Random random;
double slope,b,c,g;
public PointsPanel2(){
random = new Random();
setBackground(Color.black);
setPreferredSize(new Dimension(300,300));
}
public void paintComponent(Graphics page)
{
super.paintComponent(page);
// Diagonal equation
// X0, Y0 = (0,0)
// Xl, Yl = width, height
// Equation y = aX + b
// 0 = 0 + b ==> b = 0
// Yl = aXl ==> a = Yl/Xl
// Computes the diagonal a coefficient
double aCoeff = (getHeight()*1.0)/(getWidth()*1.0);
System.out.println("Xl,Yl, a = " + getWidth() + " " + getHeight() + " " + aCoeff);
for(int count = 0; count < MAX_POINTS; count++)
{
x = random.nextInt(getWidth()-1) + 1;
y = random.nextInt(getHeight()-1) + 1;
x1= x + LENGTH;
y1= y + LENGTH;
// Computes the diagonal image of x in order to compare it with y1
double diagImage = aCoeff * x1;
slope = x1/y1;
c = slope*x;
b = ((-1)*(y))-c;
g = (-1)*y1;
//if (b <= g)
if (diagImage <= y1)
page.setColor(Color.red);
else
page.setColor(Color.green);
page.drawLine(x,y,x1,y1);
}
}
}